diff --git a/.appveyor/after_build.ps1 b/.appveyor/after_build.ps1 new file mode 100644 index 000000000..a6837974d --- /dev/null +++ b/.appveyor/after_build.ps1 @@ -0,0 +1,36 @@ +param ( + $VcpkgPath = 'c:\tools\vcpkg\', + $VcpkgPlatform = 'x64-windows' +) + +$ErrorActionPreference = 'Stop' + +function Pack-Files($ext, $includeExe, $targetPath, $archiveName) { + New-Item $targetPath\imageformats -Type Directory -Force | Out-Null + New-Item $targetPath\platforms -Type Directory -Force | Out-Null + + foreach ($name in @('Qt5Core', 'Qt5Gui', 'Qt5Network', 'Qt5Widgets')) { + Copy-Item $env:QT_DIR\bin\$name.$ext $targetPath\ + } + + Copy-Item $env:QT_DIR\plugins\imageformats\qwebp.$ext $targetPath\imageformats\ + Copy-Item $env:QT_DIR\plugins\imageformats\qjpeg.$ext $targetPath\imageformats\ + Copy-Item $env:QT_DIR\plugins\platforms\qwindows.$ext $targetPath\platforms\ + Copy-Item $VcpkgPath\installed\$VcpkgPlatform\bin\ssleay32.$ext $targetPath\ + Copy-Item $VcpkgPath\installed\$VcpkgPlatform\bin\libeay32.$ext $targetPath\ + + $itemsToPack = @("$targetPath\*.$ext", "$targetPath\platforms\*.$ext", "$targetPath\imageformats\*.$ext") + if ($includeExe) { + $itemsToPack += @("$targetPath\kepka.exe") + } + + 7z a -mmt $archiveName @itemsToPack +} + +Push-Location "$PSScriptRoot\..\build" +try { + Pack-Files dll $true Telegram kepka.zip + Pack-Files pdb $false Telegram pdb.zip +} finally { + Pop-Location +} diff --git a/.appveyor/before_build.cmd b/.appveyor/before_build.cmd new file mode 100644 index 000000000..b940dc6da --- /dev/null +++ b/.appveyor/before_build.cmd @@ -0,0 +1,2 @@ +set PATH=C:\Python35;%QT_DIR%\bin;%PATH% +call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" diff --git a/.appveyor/build.ps1 b/.appveyor/build.ps1 new file mode 100644 index 000000000..bb32eae8c --- /dev/null +++ b/.appveyor/build.ps1 @@ -0,0 +1,23 @@ +$ErrorActionPreference = 'Stop' + +Push-Location "$env:APPVEYOR_BUILD_FOLDER\build" + +function execute-cmake { + # We have to merge the stderr and stdout here because otherwise the build will fail on any random warning + cmd /c 'cmake 2>&1' @args + if ($LASTEXITCODE -ne 0) { + throw "CMake execution error: $LASTEXITCODE" + } +} + +try { + execute-cmake '-GNinja' ` + '-DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake' ` + '-DCMAKE_BUILD_TYPE=RelWithDebInfo' ` + .. + execute-cmake --build . --config RelWithDebInfo + ctest . + if (!$?) { throw 'ctest execution error' } +} finally { + Pop-Location +} diff --git a/.appveyor/install.bat b/.appveyor/install.bat deleted file mode 100644 index 194eed0d8..000000000 --- a/.appveyor/install.bat +++ /dev/null @@ -1,92 +0,0 @@ -@echo off - -IF "%BUILD_DIR%"=="" SET BUILD_DIR=C:\TBuild -SET LIB_DIR=%BUILD_DIR%\Libraries -SET SRC_DIR=%BUILD_DIR%\tdesktop -SET QT_VERSION=5_6_2 - -call:configureBuild -call:getDependencies -call:setupGYP -cd %SRC_DIR% - -echo Finished! - -GOTO:EOF - -:: FUNCTIONS -:logInfo - echo [INFO] %~1 -GOTO:EOF - -:logError - echo [ERROR] %~1 -GOTO:EOF - -:getDependencies - call:logInfo "Clone dependencies repository" - git clone -q --depth 1 --branch=master https://github.com/telegramdesktop/dependencies_windows.git %LIB_DIR% - cd %LIB_DIR% - - if exist prepare.bat ( - call prepare.bat - ) else ( - call:logError "Error cloning dependencies, trying again" - rmdir %LIB_DIR% /S /Q - call:getDependencies - ) -GOTO:EOF - -:setupGYP - call:logInfo "Setup GYP/Ninja and generate VS solution" - cd %LIB_DIR% - git clone https://chromium.googlesource.com/external/gyp - cd gyp - git checkout a478c1ab51 - SET PATH=%PATH%;%BUILD_DIR%\Libraries\gyp;%BUILD_DIR%\Libraries\ninja; - cd %SRC_DIR% - git submodule init - git submodule update - cd %SRC_DIR%\Telegram - call gyp\refresh.bat -GOTO:EOF - -:configureBuild - call:logInfo "Configuring build" - call:logInfo "Build version: %BUILD_VERSION%" - set TDESKTOP_BUILD_DEFINES= - - echo %BUILD_VERSION% | findstr /C:"disable_autoupdate">nul && ( - set TDESKTOP_BUILD_DEFINES=%TDESKTOP_BUILD_DEFINES%,TDESKTOP_DISABLE_AUTOUPDATE - ) - - echo %BUILD_VERSION% | findstr /C:"disable_register_custom_scheme">nul && ( - set TDESKTOP_BUILD_DEFINES=%TDESKTOP_BUILD_DEFINES%,TDESKTOP_DISABLE_REGISTER_CUSTOM_SCHEME - ) - - echo %BUILD_VERSION% | findstr /C:"disable_crash_reports">nul && ( - set TDESKTOP_BUILD_DEFINES=%TDESKTOP_BUILD_DEFINES%,TDESKTOP_DISABLE_CRASH_REPORTS - ) - - echo %BUILD_VERSION% | findstr /C:"disable_network_proxy">nul && ( - set TDESKTOP_BUILD_DEFINES=%TDESKTOP_BUILD_DEFINES%,TDESKTOP_DISABLE_NETWORK_PROXY - ) - - echo %BUILD_VERSION% | findstr /C:"disable_desktop_file_generation">nul && ( - set TDESKTOP_BUILD_DEFINES=%TDESKTOP_BUILD_DEFINES%,TDESKTOP_DISABLE_DESKTOP_FILE_GENERATION - ) - - echo %BUILD_VERSION% | findstr /C:"disable_unity_integration">nul && ( - set TDESKTOP_BUILD_DEFINES=%TDESKTOP_BUILD_DEFINES%,TDESKTOP_DISABLE_UNITY_INTEGRATION - ) - - echo %BUILD_VERSION% | findstr /C:"disable_gtk_integration">nul && ( - set TDESKTOP_BUILD_DEFINES=%TDESKTOP_BUILD_DEFINES%,TDESKTOP_DISABLE_GTK_INTEGRATION - ) - - if not "%TDESKTOP_BUILD_DEFINES%" == "" ( - set "TDESKTOP_BUILD_DEFINES=%TDESKTOP_BUILD_DEFINES:~1%" - ) - - call:logInfo "Build Defines: %TDESKTOP_BUILD_DEFINES%" -GOTO:EOF diff --git a/.appveyor/install.cmd b/.appveyor/install.cmd new file mode 100644 index 000000000..824d24ca2 --- /dev/null +++ b/.appveyor/install.cmd @@ -0,0 +1,4 @@ +vcpkg install --triplet x64-windows openal-soft openssl opus zlib ffmpeg +appveyor DownloadFile https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-win.zip +mkdir %APPVEYOR_BUILD_FOLDER%\build +7z x ninja-win.zip -o%APPVEYOR_BUILD_FOLDER%\build > nul diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..3c72c483b --- /dev/null +++ b/.clang-format @@ -0,0 +1,43 @@ +--- +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: false +AlignEscapedNewlines: false +AlignOperands: true +AlignTrailingComments: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: true +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +BinPackArguments: true +BinPackParameters: true +BreakBeforeBraces: Attach +BreakBeforeTernaryOperators: false +BreakConstructorInitializers: BeforeComma +BreakStringLiterals: true +ColumnLimit: 120 +ConstructorInitializerAllOnOneLineOrOnePerLine: false +Cpp11BracedListStyle: true +DerivePointerAlignment: true +IndentCaseLabels: false +IndentWidth: 4 +KeepEmptyLinesAtTheStartOfBlocks: false +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: None +PointerAlignment: Right +SortIncludes: false +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +Standard: Cpp11 +TabWidth: 4 +UseTab: ForIndentation +ForEachMacros: [ for_const, foreach, Q_FOREACH, BOOST_FOREACH ] +... diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index cef07b094..36887c90e 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contributing -This document describes how you can contribute to Telegram Desktop. Please read it carefully. +This document describes how you can contribute to Kepka. Please read it carefully. **Table of Contents** @@ -17,14 +17,14 @@ This document describes how you can contribute to Telegram Desktop. Please read ## What contributions are accepted -We highly appreciate your contributions in the matter of fixing bugs and optimizing the Telegram Desktop source code and its documentation. In case of fixing the existing user experience please push to your fork and [submit a pull request][pr]. +We highly appreciate your contributions in the matter of fixing bugs and optimizing the Kepka source code and its documentation. In case of fixing the existing user experience please push to your fork and [submit a pull request][pr]. Wait for us. We try to review your pull requests as fast as possible. If we find issues with your pull request, we may suggest some changes and improvements. -Unfortunately we **do not merge** any pull requests that have new feature implementations, translations to new languages and those which introduce any new user interface elements. +Unfortunately we **do not merge** any pull requests that have not comply with [Telegram API Terms of Use][api-tos]. -Telegram Desktop is not a standalone application but a part of [Telegram project][telegram], so all the decisions about the features, languages, user experience, user interface and the design are made inside Telegram team, often according to some roadmap which is not public. +Kepka is a fork of a Telegram Desktop which a part of [Telegram project][telegram], so all the decisions about the features, languages, user experience, user interface and the design *in upstream* are made inside Telegram team, often according to some roadmap which is not public. ## Build instructions @@ -33,11 +33,11 @@ environments. ## Pull upstream changes into your fork regularly -Telegram Desktop is advancing quickly. It is therefore critical that you pull upstream changes into your fork on a regular basis. Nothing is worse than putting in a days of hard work into a pull request only to have it rejected because it has diverged too far from upstram. +Kepka is advancing quickly. It is therefore critical that you pull upstream changes into your fork on a regular basis. Nothing is worse than putting in a days of hard work into a pull request only to have it rejected because it has diverged too far from upstram. To pull in upstream changes: - git remote add upstream https://github.com/telegramdesktop/tdesktop.git + git remote add upstream https://github.com/procxx/kepka.git git fetch upstream master Check the log to be sure that you actually want the changes, before merging: @@ -56,7 +56,7 @@ For more info, see [GitHub Help][help_fork_repo]. ## How to get your pull request accepted -We want to improve Telegram Desktop with your contributions. But we also want to provide a stable experience for our users and the community. Follow these rules and you should succeed without a problem! +We want to improve Kepka with your contributions. But we also want to provide a stable experience for our users and the community. Follow these rules and you should succeed without a problem! ### Keep your pull requests limited to a single issue @@ -95,7 +95,7 @@ Furthermore, the pixel shortage is over. We want to see: ### Test your changes! -Before you submit a pull request, please test your changes. Verify that Telegram Desktop still works and your changes don't cause other issue or crashes. +Before you submit a pull request, please test your changes. Verify that Kepka still works and your changes don't cause other issue or crashes. ### Write a good commit message @@ -105,11 +105,52 @@ Before you submit a pull request, please test your changes. Verify that Telegram For example: `Fix #545` +* For documentation commits add `[ci skip]` (or `[skip ci]`) at the end of the commit message. + +#### Commit Message Example + +``` +Summarize changes in around 50 characters or less + +More detailed explanatory text, if necessary. Wrap it to about 72 +characters or so. In some contexts, the first line is treated as the +subject of the commit and the rest of the text as the body. The +blank line separating the summary from the body is critical (unless +you omit the body entirely); various tools like `log`, `shortlog` +and `rebase` can get confused if you run the two together. + +Explain the problem that this commit is solving. Focus on why you +are making this change as opposed to how (the code explains that). +Are there side effects or other unintuitive consequences of this +change? Here's the place to explain them. + +Further paragraphs come after blank lines. + + - Bullet points are okay, too + + - Typically a hyphen or asterisk is used for the bullet, preceded + by a single space, with blank lines in between, but conventions + vary here + +If you use an issue tracker, put references to them at the bottom, +like this: + +Resolves: #123 +See also: #456, #789 +[ci skip] +``` + +(Example taken from [this source][commit_message_2]) + + [//]: # (LINKS) +[procxx]: https://procxx.github.io/ [telegram]: https://telegram.org/ [help_fork_repo]: https://help.github.com/articles/fork-a-repo/ [help_change_commit_message]: https://help.github.com/articles/changing-a-commit-message/ [commit_message]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html -[pr]: https://github.com/telegramdesktop/tdesktop/compare -[build_instructions]: https://github.com/telegramdesktop/tdesktop/blob/master/README.md#build-instructions +[commit_message_2]: https://chris.beams.io/posts/git-commit/ +[pr]: https://github.com/procxx/kepka/compare +[build_instructions]: https://github.com/procxx/kepka/blob/dev/README.md#build-instructions [closing-issues-via-commit-messages]: https://help.github.com/articles/closing-issues-via-commit-messages/ +[api-tos]: https://core.telegram.org/api/terms diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE/bug_report.md similarity index 64% rename from .github/ISSUE_TEMPLATE.md rename to .github/ISSUE_TEMPLATE/bug_report.md index 45aa8752f..ea2076307 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,5 +1,10 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- @@ -17,13 +22,13 @@ Tell us what happens instead ### Configuration **Operating system:** -**Version of Telegram Desktop:** +**Version of Kepka:** **Used theme**:
Logs: Insert logs here (if necessary) -
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..3564b4cd6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,13 @@ +--- +name: Feature Request +about: New feature that you want to see in Kepka +--- + +## Feature description + + + +## Feature check-list + - [ ] This feature has been implemented by + - [ ] This feature doesn't violate the Telegram [Terms of Service](https://telegram.org/tos) + diff --git a/.gitignore b/.gitignore index 63873b949..ef96865d5 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,19 @@ xcuserdata /Linux/ /Telegram/Makefile *.*~ + +### Vim service files ## +# swap +.sw[a-p] +.*.sw[a-p] +# session +Session.vim +# temporary +.netrwhist +*~ + +_build_ +_conan_build_ + +.idea/ +cmake-build-debug/ diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 288741058..000000000 --- a/.gitmodules +++ /dev/null @@ -1,12 +0,0 @@ -[submodule "Telegram/ThirdParty/libtgvoip"] - path = Telegram/ThirdParty/libtgvoip - url = https://github.com/telegramdesktop/libtgvoip -[submodule "Telegram/ThirdParty/variant"] - path = Telegram/ThirdParty/variant - url = https://github.com/mapbox/variant -[submodule "Telegram/ThirdParty/GSL"] - path = Telegram/ThirdParty/GSL - url = https://github.com/Microsoft/GSL.git -[submodule "Telegram/ThirdParty/Catch"] - path = Telegram/ThirdParty/Catch - url = https://github.com/philsquared/Catch diff --git a/.travis.yml b/.travis.yml index 13ba3348c..8072b1b08 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,65 +3,32 @@ dist: trusty language: cpp +services: docker + cache: directories: - $HOME/travisCacheDir -env: - matrix: - - BUILD_VERSION="" - - BUILD_VERSION="disable_autoupdate" - - BUILD_VERSION="disable_register_custom_scheme" - - BUILD_VERSION="disable_crash_reports" - - BUILD_VERSION="disable_network_proxy" - - BUILD_VERSION="disable_desktop_file_generation" - - BUILD_VERSION="disable_unity_integration" - - BUILD_VERSION="disable_gtk_integration" +branches: + only: + - master + - dev matrix: fast_finish: true -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - bison - - build-essential - - cmake - - devscripts - - dpatch - - equivs - - fakeroot - - g++-6 - - gcc-6 - - git - - gnome-common - - gobject-introspection - - gtk-doc-tools - - libappindicator-dev - - libasound2-dev - - libdbusmenu-glib-dev - - liblzma-dev - - libopus-dev - - libpulse-dev - - libssl-dev - - libunity-dev - - libva-dev - - libvdpau-dev - - libxcb-xkb-dev - - libxkbcommon-dev - - lintian - - quilt - - valac - - xutils-dev - - yasm +matrix: + include: + - os: linux + env: BUILD_TYPE=RelWithDebInfo + #- os: osx + # env: BUILD_TYPE=Debug + #- os: osx + # env: BUILD_TYPE=Release before_install: - - export CXX="g++-6" CC="gcc-6" - - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-6 60 --slave /usr/bin/g++ g++ /usr/bin/g++-6 - - sudo update-alternatives --config gcc - - g++ --version + - .travis/os_setup.sh script: - - .travis/build.sh + - mkdir _build_ + - .travis/os_build.sh diff --git a/.travis/build.sh b/.travis/build.sh index 506f8d4bb..7e5ed3799 100755 --- a/.travis/build.sh +++ b/.travis/build.sh @@ -1,661 +1,16 @@ #!/bin/bash -set -e - -REPO="$PWD" - -BUILD="$REPO/build" -UPSTREAM="$REPO/upstream" -EXTERNAL="$REPO/external" -CACHE="$HOME/travisCacheDir" - -QT_WAS_BUILT="0" - -QT_VERSION=5.6.2 - -XKB_PATH="$BUILD/libxkbcommon" -XKB_CACHE_VERSION="3" - -QT_PATH="$BUILD/qt" -QT_CACHE_VERSION="3" -QT_PATCH="$UPSTREAM/Telegram/Patches/qtbase_${QT_VERSION//\./_}.diff" - -BREAKPAD_PATH="$BUILD/breakpad" -BREAKPAD_CACHE_VERSION="3" - -GYP_PATH="$BUILD/gyp" -GYP_CACHE_VERSION="3" -GYP_PATCH="$UPSTREAM/Telegram/Patches/gyp.diff" - -VA_PATH="$BUILD/libva" -VA_CACHE_VERSION="3" - -VDPAU_PATH="$BUILD/libvdpau" -VDPAU_CACHE_VERSION="3" - -FFMPEG_PATH="$BUILD/ffmpeg" -FFMPEG_CACHE_VERSION="3" - -OPENAL_PATH="$BUILD/openal-soft" -OPENAL_CACHE_VERSION="3" - -GYP_DEFINES="" - -[[ ! $MAKE_ARGS ]] && MAKE_ARGS="--silent -j4" - -run() { - # Move files to subdir - cd .. - mv tdesktop tdesktop2 - mkdir tdesktop - mv tdesktop2 "$UPSTREAM" - - mkdir "$BUILD" - - build - check -} - -build() { - mkdir -p "$EXTERNAL" - - BUILD_VERSION_DATA=$(echo $BUILD_VERSION | cut -d'-' -f 1) - - # libxkbcommon - getXkbCommon - - # libva - getVa - - # libvdpau - getVdpau - - # ffmpeg - getFFmpeg - - # openal_soft - getOpenAL - - # Patched Qt - getCustomQt - - # Breakpad - getBreakpad - - # Patched GYP (supports cmake precompiled headers) - getGYP - - # Guideline Support Library - getGSL - - if [ "$QT_WAS_BUILT" == "1" ]; then - error_msg "Qt was built, please restart the job :(" +set -x + +cmake -G Ninja -DCMAKE_BUILD_TYPE=$BUILD_TYPE $EXTRA_CMAKE_FLAGS -DBUILD_TESTING=ON .. || exit 1 +# grep returns number of items found. each change is enclosed into +# tag in the xml. Thus if no changes needed, 0 will be returned +cmake --build . --target clang-format -- -v +if [[ $(git diff) ]]; then + git diff | cat exit 1 - fi - - # Configure the build - if [[ $BUILD_VERSION == *"disable_autoupdate"* ]]; then - GYP_DEFINES+=",TDESKTOP_DISABLE_AUTOUPDATE" - fi - - if [[ $BUILD_VERSION == *"disable_register_custom_scheme"* ]]; then - GYP_DEFINES+=",TDESKTOP_DISABLE_REGISTER_CUSTOM_SCHEME" - fi - - if [[ $BUILD_VERSION == *"disable_crash_reports"* ]]; then - GYP_DEFINES+=",TDESKTOP_DISABLE_CRASH_REPORTS" - fi - - if [[ $BUILD_VERSION == *"disable_network_proxy"* ]]; then - GYP_DEFINES+=",TDESKTOP_DISABLE_NETWORK_PROXY" - fi - - if [[ $BUILD_VERSION == *"disable_desktop_file_generation"* ]]; then - GYP_DEFINES+=",TDESKTOP_DISABLE_DESKTOP_FILE_GENERATION" - fi - - if [[ $BUILD_VERSION == *"disable_unity_integration"* ]]; then - GYP_DEFINES+=",TDESKTOP_DISABLE_UNITY_INTEGRATION" - fi - - if [[ $BUILD_VERSION == *"disable_gtk_integration"* ]]; then - GYP_DEFINES+=",TDESKTOP_DISABLE_GTK_INTEGRATION" - fi - - info_msg "Build defines: ${GYP_DEFINES}" - - buildTelegram - - travisEndFold -} - -getXkbCommon() { - travisStartFold "Getting xkbcommon" - - local XKB_CACHE="$CACHE/libxkbcommon" - local XKB_CACHE_FILE="$XKB_CACHE/.cache.txt" - local XKB_CACHE_KEY="${XKB_CACHE_VERSION}" - local XKB_CACHE_OUTDATED="1" - - if [ ! -d "$XKB_CACHE" ]; then - mkdir -p "$XKB_CACHE" - fi - - ln -sf "$XKB_CACHE" "$XKB_PATH" - - if [ -f "$XKB_CACHE_FILE" ]; then - local XKB_CACHE_KEY_FOUND=`tail -n 1 $XKB_CACHE_FILE` - if [ "$XKB_CACHE_KEY" == "$XKB_CACHE_KEY_FOUND" ]; then - XKB_CACHE_OUTDATED="0" - else - info_msg "Cache key '$XKB_CACHE_KEY_FOUND' does not match '$XKB_CACHE_KEY', rebuilding libxkbcommon" - fi - fi - if [ "$XKB_CACHE_OUTDATED" == "1" ]; then - buildXkbCommon - sudo echo $XKB_CACHE_KEY > "$XKB_CACHE_FILE" - else - info_msg "Using cached libxkbcommon" - fi -} - -buildXkbCommon() { - info_msg "Downloading and building libxkbcommon" - - if [ -d "$EXTERNAL/libxkbcommon" ]; then - rm -rf "$EXTERNAL/libxkbcommon" - fi - cd $XKB_PATH - rm -rf * - - cd "$EXTERNAL" - git clone https://github.com/xkbcommon/libxkbcommon.git - - cd "$EXTERNAL/libxkbcommon" - ./autogen.sh --prefix=$XKB_PATH - make $MAKE_ARGS - sudo make install - sudo ldconfig -} - -getVa() { - travisStartFold "Getting libva" - - local VA_CACHE="$CACHE/libva" - local VA_CACHE_FILE="$VA_CACHE/.cache.txt" - local VA_CACHE_KEY="${VA_CACHE_VERSION}" - local VA_CACHE_OUTDATED="1" - - if [ ! -d "$VA_CACHE" ]; then - mkdir -p "$VA_CACHE" - fi - - ln -sf "$VA_CACHE" "$VA_PATH" - - if [ -f "$VA_CACHE_FILE" ]; then - local VA_CACHE_KEY_FOUND=`tail -n 1 $VA_CACHE_FILE` - if [ "$VA_CACHE_KEY" == "$VA_CACHE_KEY_FOUND" ]; then - VA_CACHE_OUTDATED="0" - else - info_msg "Cache key '$VA_CACHE_KEY_FOUND' does not match '$VA_CACHE_KEY', rebuilding libva" - fi - fi - if [ "$VA_CACHE_OUTDATED" == "1" ]; then - buildVa - sudo echo $VA_CACHE_KEY > "$VA_CACHE_FILE" - else - info_msg "Using cached libva" - fi -} - -buildVa() { - info_msg "Downloading and building libva" - - if [ -d "$EXTERNAL/libva" ]; then - rm -rf "$EXTERNAL/libva" - fi - cd $VA_PATH - rm -rf * - - cd "$EXTERNAL" - git clone https://github.com/01org/libva - - cd "$EXTERNAL/libva" - ./autogen.sh --prefix=$VA_PATH --enable-static - make $MAKE_ARGS - sudo make install - sudo ldconfig -} - -getVdpau() { - travisStartFold "Getting libvdpau" - - local VDPAU_CACHE="$CACHE/libvdpau" - local VDPAU_CACHE_FILE="$VDPAU_CACHE/.cache.txt" - local VDPAU_CACHE_KEY="${VDPAU_CACHE_VERSION}" - local VDPAU_CACHE_OUTDATED="1" - - if [ ! -d "$VDPAU_CACHE" ]; then - mkdir -p "$VDPAU_CACHE" - fi - - ln -sf "$VDPAU_CACHE" "$VDPAU_PATH" - - if [ -f "$VDPAU_CACHE_FILE" ]; then - local VDPAU_CACHE_KEY_FOUND=`tail -n 1 $VDPAU_CACHE_FILE` - if [ "$VDPAU_CACHE_KEY" == "$VDPAU_CACHE_KEY_FOUND" ]; then - VDPAU_CACHE_OUTDATED="0" - else - info_msg "Cache key '$VDPAU_CACHE_KEY_FOUND' does not match '$VDPAU_CACHE_KEY', rebuilding libvdpau" - fi - fi - if [ "$VDPAU_CACHE_OUTDATED" == "1" ]; then - buildVdpau - sudo echo $VDPAU_CACHE_KEY > "$VDPAU_CACHE_FILE" - else - info_msg "Using cached libvdpau" - fi -} - -buildVdpau() { - info_msg "Downloading and building libvdpau" - - if [ -d "$EXTERNAL/libvdpau" ]; then - rm -rf "$EXTERNAL/libvdpau" - fi - cd $VDPAU_PATH - rm -rf * - - cd "$EXTERNAL" - git clone git://anongit.freedesktop.org/vdpau/libvdpau - - cd "$EXTERNAL/libvdpau" - ./autogen.sh --prefix=$VDPAU_PATH --enable-static - make $MAKE_ARGS - sudo make install - sudo ldconfig -} - -getFFmpeg() { - travisStartFold "Getting ffmpeg" - - local FFMPEG_CACHE="$CACHE/ffmpeg" - local FFMPEG_CACHE_FILE="$FFMPEG_CACHE/.cache.txt" - local FFMPEG_CACHE_KEY="${FFMPEG_CACHE_VERSION}" - local FFMPEG_CACHE_OUTDATED="1" - - if [ ! -d "$FFMPEG_CACHE" ]; then - mkdir -p "$FFMPEG_CACHE" - fi - - ln -sf "$FFMPEG_CACHE" "$FFMPEG_PATH" - - if [ -f "$FFMPEG_CACHE_FILE" ]; then - local FFMPEG_CACHE_KEY_FOUND=`tail -n 1 $FFMPEG_CACHE_FILE` - if [ "$FFMPEG_CACHE_KEY" == "$FFMPEG_CACHE_KEY_FOUND" ]; then - FFMPEG_CACHE_OUTDATED="0" - else - info_msg "Cache key '$FFMPEG_CACHE_KEY_FOUND' does not match '$FFMPEG_CACHE_KEY', rebuilding ffmpeg" - fi - fi - if [ "$FFMPEG_CACHE_OUTDATED" == "1" ]; then - buildFFmpeg - sudo echo $FFMPEG_CACHE_KEY > "$FFMPEG_CACHE_FILE" - else - info_msg "Using cached ffmpeg" - fi -} - -buildFFmpeg() { - info_msg "Downloading and building ffmpeg" - - if [ -d "$EXTERNAL/ffmpeg" ]; then - rm -rf "$EXTERNAL/ffmpeg" - fi - cd $FFMPEG_PATH - rm -rf * - - cd "$EXTERNAL" - git clone https://git.ffmpeg.org/ffmpeg.git - - cd "$EXTERNAL/ffmpeg" - ./configure \ - --prefix=$FFMPEG_PATH \ - --disable-debug \ - --disable-programs \ - --disable-doc \ - --disable-everything \ - --enable-gpl \ - --enable-version3 \ - --enable-libopus \ - --enable-decoder=aac \ - --enable-decoder=aac_latm \ - --enable-decoder=aasc \ - --enable-decoder=flac \ - --enable-decoder=gif \ - --enable-decoder=h264 \ - --enable-decoder=h264_vdpau \ - --enable-decoder=mp1 \ - --enable-decoder=mp1float \ - --enable-decoder=mp2 \ - --enable-decoder=mp2float \ - --enable-decoder=mp3 \ - --enable-decoder=mp3adu \ - --enable-decoder=mp3adufloat \ - --enable-decoder=mp3float \ - --enable-decoder=mp3on4 \ - --enable-decoder=mp3on4float \ - --enable-decoder=mpeg4 \ - --enable-decoder=mpeg4_vdpau \ - --enable-decoder=msmpeg4v2 \ - --enable-decoder=msmpeg4v3 \ - --enable-decoder=opus \ - --enable-decoder=vorbis \ - --enable-decoder=wavpack \ - --enable-decoder=wmalossless \ - --enable-decoder=wmapro \ - --enable-decoder=wmav1 \ - --enable-decoder=wmav2 \ - --enable-decoder=wmavoice \ - --enable-encoder=libopus \ - --enable-hwaccel=h264_vaapi \ - --enable-hwaccel=h264_vdpau \ - --enable-hwaccel=mpeg4_vaapi \ - --enable-hwaccel=mpeg4_vdpau \ - --enable-parser=aac \ - --enable-parser=aac_latm \ - --enable-parser=flac \ - --enable-parser=h264 \ - --enable-parser=mpeg4video \ - --enable-parser=mpegaudio \ - --enable-parser=opus \ - --enable-parser=vorbis \ - --enable-demuxer=aac \ - --enable-demuxer=flac \ - --enable-demuxer=gif \ - --enable-demuxer=h264 \ - --enable-demuxer=mov \ - --enable-demuxer=mp3 \ - --enable-demuxer=ogg \ - --enable-demuxer=wav \ - --enable-muxer=ogg \ - --enable-muxer=opus - make $MAKE_ARGS - sudo make install - sudo ldconfig -} - -getOpenAL() { - travisStartFold "Getting openal-soft" - - local OPENAL_CACHE="$CACHE/openal-soft" - local OPENAL_CACHE_FILE="$OPENAL_CACHE/.cache.txt" - local OPENAL_CACHE_KEY="${OPENAL_CACHE_VERSION}" - local OPENAL_CACHE_OUTDATED="1" - - if [ ! -d "$OPENAL_CACHE" ]; then - mkdir -p "$OPENAL_CACHE" - fi - - ln -sf "$OPENAL_CACHE" "$OPENAL_PATH" - - if [ -f "$OPENAL_CACHE_FILE" ]; then - local OPENAL_CACHE_KEY_FOUND=`tail -n 1 $OPENAL_CACHE_FILE` - if [ "$OPENAL_CACHE_KEY" == "$OPENAL_CACHE_KEY_FOUND" ]; then - OPENAL_CACHE_OUTDATED="0" - else - info_msg "Cache key '$OPENAL_CACHE_KEY_FOUND' does not match '$OPENAL_CACHE_KEY', rebuilding openal-soft" - fi - fi - if [ "$OPENAL_CACHE_OUTDATED" == "1" ]; then - buildOpenAL - sudo echo $OPENAL_CACHE_KEY > "$OPENAL_CACHE_FILE" - else - info_msg "Using cached openal-soft" - fi -} - -buildOpenAL() { - info_msg "Downloading and building openal-soft" - - if [ -d "$EXTERNAL/openal-soft" ]; then - rm -rf "$EXTERNAL/openal-soft" - fi - cd $OPENAL_PATH - rm -rf * - - cd "$EXTERNAL" - git clone https://github.com/kcat/openal-soft.git - - cd "$EXTERNAL/openal-soft/build" - cmake \ - -D CMAKE_INSTALL_PREFIX=$OPENAL_PATH \ - -D CMAKE_BUILD_TYPE=Release \ - -D LIBTYPE=STATIC \ - .. - make $MAKE_ARGS - sudo make install - sudo ldconfig -} - -getBreakpad() { - travisStartFold "Getting breakpad" - - local BREAKPAD_CACHE="$CACHE/breakpad" - local BREAKPAD_CACHE_FILE="$BREAKPAD_CACHE/.cache.txt" - local BREAKPAD_CACHE_KEY="${BREAKPAD_CACHE_VERSION}" - local BREAKPAD_CACHE_OUTDATED="1" - - if [ ! -d "$BREAKPAD_CACHE" ]; then - mkdir -p "$BREAKPAD_CACHE" - fi - - ln -sf "$BREAKPAD_CACHE" "$BREAKPAD_PATH" - - if [ -f "$BREAKPAD_CACHE_FILE" ]; then - local BREAKPAD_CACHE_KEY_FOUND=`tail -n 1 $BREAKPAD_CACHE_FILE` - if [ "$BREAKPAD_CACHE_KEY" == "$BREAKPAD_CACHE_KEY_FOUND" ]; then - BREAKPAD_CACHE_OUTDATED="0" - else - info_msg "Cache key '$BREAKPAD_CACHE_KEY_FOUND' does not match '$BREAKPAD_CACHE_KEY', rebuilding breakpad" - fi - fi - if [ "$BREAKPAD_CACHE_OUTDATED" == "1" ]; then - buildBreakpad - sudo echo $BREAKPAD_CACHE_KEY > "$BREAKPAD_CACHE_FILE" - else - info_msg "Using cached breakpad" - fi -} - -buildBreakpad() { - info_msg "Downloading and building breakpad" - - if [ -d "$EXTERNAL/breakpad" ]; then - rm -rf "$EXTERNAL/breakpad" - fi - cd $BREAKPAD_PATH - rm -rf * - - cd "$EXTERNAL" - git clone https://chromium.googlesource.com/breakpad/breakpad - - cd "$EXTERNAL/breakpad/src/third_party" - git clone https://chromium.googlesource.com/linux-syscall-support lss - - cd "$EXTERNAL/breakpad" - ./configure --prefix=$BREAKPAD_PATH - make $MAKE_ARGS - sudo make install - sudo ldconfig -} - -getCustomQt() { - travisStartFold "Getting patched Qt" - - local QT_CACHE="$CACHE/qtPatched" - local QT_CACHE_FILE="$QT_CACHE/.cache.txt" - local QT_PATCH_CHECKSUM=`sha1sum $QT_PATCH` - local QT_CACHE_KEY="${QT_VERSION}_${QT_CACHE_VERSION}_${QT_PATCH_CHECKSUM:0:32}" - local QT_CACHE_OUTDATED="1" - - if [ ! -d "$QT_CACHE" ]; then - mkdir -p "$QT_CACHE" - fi - - ln -sf "$QT_CACHE" "$QT_PATH" - - if [ -f "$QT_CACHE_FILE" ]; then - local QT_CACHE_KEY_FOUND=`tail -n 1 $QT_CACHE_FILE` - if [ "$QT_CACHE_KEY" == "$QT_CACHE_KEY_FOUND" ]; then - QT_CACHE_OUTDATED="0" - else - info_msg "Cache key '$QT_CACHE_KEY_FOUND' does not match '$QT_CACHE_KEY', rebuilding patched Qt" - fi - fi - if [ "$QT_CACHE_OUTDATED" == "1" ]; then - buildCustomQt - sudo echo $QT_CACHE_KEY > "$QT_CACHE_FILE" - else - info_msg "Using cached patched Qt" - fi - - export PATH="$QT_PATH/bin:$PATH" -} - -buildCustomQt() { - QT_WAS_BUILT="1" - info_msg "Downloading and building patched qt" - - if [ -d "$EXTERNAL/qt${QT_VERSION}" ]; then - rm -rf "$EXTERNAL/qt${QT_VERSION}" - fi - cd $QT_PATH - rm -rf * - - cd "$EXTERNAL" - git clone git://code.qt.io/qt/qt5.git qt${QT_VERSION} - - cd "$EXTERNAL/qt${QT_VERSION}" - perl init-repository --branch --module-subset=qtbase,qtimageformats - git checkout v${QT_VERSION} - cd qtbase && git checkout v${QT_VERSION} && cd .. - cd qtimageformats && git checkout v${QT_VERSION} && cd .. - - cd "$EXTERNAL/qt${QT_VERSION}/qtbase" - git apply "$QT_PATCH" - cd .. - - cd "$EXTERNAL/qt${QT_VERSION}/qtbase/src/plugins/platforminputcontexts" - git clone https://github.com/telegramdesktop/fcitx.git - git clone https://github.com/telegramdesktop/hime.git - cd ../../../.. - - ./configure -prefix $QT_PATH -release -opensource -confirm-license -qt-zlib \ - -qt-libpng -qt-libjpeg -qt-freetype -qt-harfbuzz -qt-pcre -qt-xcb \ - -qt-xkbcommon-x11 -no-opengl -no-gtkstyle -static \ - -nomake examples -nomake tests \ - -dbus-runtime -no-gstreamer -no-mtdev # <- Not sure about these - make $MAKE_ARGS - sudo make install -} - -getGSL() { - cd "$UPSTREAM" - git submodule init - git submodule update -} - -getGYP() { - travisStartFold "Getting patched GYP" - - local GYP_CACHE="$CACHE/gyp" - local GYP_CACHE_FILE="$GYP_CACHE/.cache.txt" - local GYP_PATCH_CHECKSUM=`sha1sum $GYP_PATCH` - local GYP_CACHE_KEY="${GYP_CACHE_VERSION}_${GYP_PATCH_CHECKSUM:0:32}" - local GYP_CACHE_OUTDATED="1" - - if [ ! -d "$GYP_CACHE" ]; then - mkdir -p "$GYP_CACHE" - fi - - ln -sf "$GYP_CACHE" "$GYP_PATH" - - if [ -f "$GYP_CACHE_FILE" ]; then - local GYP_CACHE_KEY_FOUND=`tail -n 1 $GYP_CACHE_FILE` - if [ "$GYP_CACHE_KEY" == "$GYP_CACHE_KEY_FOUND" ]; then - GYP_CACHE_OUTDATED="0" - else - info_msg "Cache key '$GYP_CACHE_KEY_FOUND' does not match '$GYP_CACHE_KEY', rebuilding patched GYP" - fi - fi - if [ "$GYP_CACHE_OUTDATED" == "1" ]; then - buildGYP - sudo echo $GYP_CACHE_KEY > "$GYP_CACHE_FILE" - else - info_msg "Using cached patched GYP" - fi -} - -buildGYP() { - info_msg "Downloading and building patched GYP" - - if [ -d "$EXTERNAL/gyp" ]; then - rm -rf "$EXTERNAL/gyp" - fi - cd $GYP_PATH - rm -rf * - - cd "$EXTERNAL" - git clone https://chromium.googlesource.com/external/gyp - - cd "$EXTERNAL/gyp" - git checkout 702ac58e47 - git apply "$GYP_PATCH" - cp -r * "$GYP_PATH/" -} - -buildTelegram() { - travisStartFold "Build tdesktop" - - cd "$UPSTREAM/Telegram/gyp" - "$GYP_PATH/gyp" \ - -Dbuild_defines=${GYP_DEFINES:1} \ - -Dlinux_path_xkbcommon=$XKB_PATH \ - -Dlinux_path_va=$VA_PATH \ - -Dlinux_path_vdpau=$VDPAU_PATH \ - -Dlinux_path_ffmpeg=$FFMPEG_PATH \ - -Dlinux_path_openal=$OPENAL_PATH \ - -Dlinux_path_qt=$QT_PATH \ - -Dlinux_path_breakpad=$BREAKPAD_PATH \ - -Dlinux_path_libexif_lib=/usr/local/lib \ - -Dlinux_path_opus_include=/usr/include/opus \ - -Dlinux_lib_ssl=-lssl \ - -Dlinux_lib_crypto=-lcrypto \ - -Dlinux_lib_icu=-licuuc\ -licutu\ -licui18n \ - --depth=. --generator-output=.. --format=cmake -Goutput_dir=../out \ - Telegram.gyp - cd "$UPSTREAM/out/Debug" - - export ASM="gcc" - cmake . - make $MAKE_ARGS -} - -check() { - local filePath="$UPSTREAM/out/Debug/Telegram" - if test -f "$filePath"; then - success_msg "Build successfully done! :)" - - local size; - size=$(stat -c %s "$filePath") - success_msg "File size of ${filePath}: ${size} Bytes" - else - error_msg "Build error, output file does not exist" - exit 1 - fi -} - -source ./.travis/common.sh - -run +else + echo "Success!" +fi +cmake --build . -- -v || exit 1 +ASAN_OPTIONS=alloc_dealloc_mismatch=0 ctest . || exit 1 diff --git a/.travis/common.sh b/.travis/common.sh deleted file mode 100755 index d9061ab51..000000000 --- a/.travis/common.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env bash -# set colors -RCol='\e[0m' # Text Reset - -# Regular Bold Underline High Intensity BoldHigh Intens Background High Intensity Backgrounds -Bla='\e[0;30m'; BBla='\e[1;30m'; UBla='\e[4;30m'; IBla='\e[0;90m'; BIBla='\e[1;90m'; On_Bla='\e[40m'; On_IBla='\e[0;100m'; -Red='\e[0;31m'; BRed='\e[1;31m'; URed='\e[4;31m'; IRed='\e[0;91m'; BIRed='\e[1;91m'; On_Red='\e[41m'; On_IRed='\e[0;101m'; -Gre='\e[0;32m'; BGre='\e[1;32m'; UGre='\e[4;32m'; IGre='\e[0;92m'; BIGre='\e[1;92m'; On_Gre='\e[42m'; On_IGre='\e[0;102m'; -Yel='\e[0;33m'; BYel='\e[1;33m'; UYel='\e[4;33m'; IYel='\e[0;93m'; BIYel='\e[1;93m'; On_Yel='\e[43m'; On_IYel='\e[0;103m'; -Blu='\e[0;34m'; BBlu='\e[1;34m'; UBlu='\e[4;34m'; IBlu='\e[0;94m'; BIBlu='\e[1;94m'; On_Blu='\e[44m'; On_IBlu='\e[0;104m'; -Pur='\e[0;35m'; BPur='\e[1;35m'; UPur='\e[4;35m'; IPur='\e[0;95m'; BIPur='\e[1;95m'; On_Pur='\e[45m'; On_IPur='\e[0;105m'; -Cya='\e[0;36m'; BCya='\e[1;36m'; UCya='\e[4;36m'; ICya='\e[0;96m'; BICya='\e[1;96m'; On_Cya='\e[46m'; On_ICya='\e[0;106m'; -Whi='\e[0;37m'; BWhi='\e[1;37m'; UWhi='\e[4;37m'; IWhi='\e[0;97m'; BIWhi='\e[1;97m'; On_Whi='\e[47m'; On_IWhi='\e[0;107m'; - -start_msg() { - echo -e "\n${Gre}$*${RCol}" -} - -info_msg() { - sameLineInfoMessage "\n$1" -} - -error_msg() { - echo -e "\n${BRed}$*${RCol}" -} - -success_msg() { - echo -e "\n${BGre}$*${RCol}" -} - -sameLineInfoMessage() { - echo -e "${Cya}$*${RCol}" -} - -TRAVIS_LAST_FOLD="" - -travisStartFold() { - local TITLE="$1" - local NAME=$(sanitizeName "$TITLE") - - if [ "$TRAVIS_LAST_FOLD" != "" ]; then - travisEndFold - fi - - echo "travis_fold:start:$NAME" - sameLineInfoMessage "$TITLE" - - TRAVIS_LAST_FOLD="$NAME" -} - -travisEndFold() { - if [ "$TRAVIS_LAST_FOLD" == "" ]; then - return - fi - - echo "travis_fold:end:$TRAVIS_LAST_FOLD" - TRAVIS_LAST_FOLD="" -} - -sanitizeName() { - local NAME="${1// /_}" - local NAME="${NAME,,}" - echo "$NAME" -} diff --git a/.travis/os_build.sh b/.travis/os_build.sh new file mode 100755 index 000000000..a3e425a0b --- /dev/null +++ b/.travis/os_build.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +set -x + +if [ "$TRAVIS_OS_NAME" == "linux" ]; then + docker run --rm -v $PWD:/repo -v ~/.travis:/travis procpp/docker-cpp-ci /bin/sh -c "cd /repo/_build_; conan install .. --build missing; /repo/.travis/build.sh" || exit 1 +fi + +if [ "$TRAVIS_OS_NAME" == "osx" ]; then + cd _build_ + export CC=clang + export CXX=clang++ + export EXTRA_CMAKE_FLAGS=-DCMAKE_PREFIX_PATH='/usr/local/opt/qt5/;/usr/local/opt/openal-soft' + conan install -s compiler=apple-clang .. --build missing + ../.travis/build.sh || exit 1 +fi diff --git a/.travis/os_setup.sh b/.travis/os_setup.sh new file mode 100755 index 000000000..6fc035ba4 --- /dev/null +++ b/.travis/os_setup.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +set -x + +if [ "$TRAVIS_OS_NAME" == "linux" ]; then + docker pull procpp/docker-cpp-ci:latest || exit 1 +fi + +brew_package() { + if brew ls --versions $1 > /dev/null; then + brew outdated $1 > /dev/null || brew upgrade $1 || exit 1 + else + brew install $1 || exit 1 + fi +} + +if [ "$TRAVIS_OS_NAME" == "osx" ]; then + brew update + brew_package conan + brew_package cmake + brew_package ninja + brew_package qt + brew_package ffmpeg + brew_package opus + brew_package openal-soft +fi diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..361f56cfb --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,127 @@ +cmake_minimum_required(VERSION 3.10) +project(Kepka + LANGUAGES C CXX + VERSION 2.0.0 + DESCRIPTION "Unofficial Telegram Desktop fork" +# HOMEPAGE_URL "https://github.com/procxx/kepka" +) + +set(PROJECT_COMPANY_NAME "pro.cxx Community") +set(PROJECT_VERSION_RC 2) + +if(PROJECT_VERSION_RC) + set(PROJECT_VERSION "${PROJECT_VERSION}-rc${PROJECT_VERSION_RC}") +endif() + +##================================================ +## Build customizations +##================================================ +option(KEPKA_OPTION_USE_YANDEX_MAPS "Use Yandex.Maps static API for locations (instead Google Maps)" ON) + +if(KEPKA_OPTION_USE_YANDEX_MAPS) + add_definitions("-DKEPKA_USE_YANDEX_MAPS") +endif() + +set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/modules/") + +if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.10) + cmake_policy(SET CMP0071 NEW) +endif() + +# includes block +include(CTest) +# clang-format +include(modules/clang-cxx-dev-tools.cmake) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED YES) +set(CMAKE_CXX_EXTENSIONS OFF) + +if (UNIX AND NOT APPLE) + set(LINUX 1) +endif() + +function(set_flag_if_supported target shortname flag) + include(CheckCXXCompilerFlag) + check_cxx_compiler_flag(${flag} ${shortname}_FLAG_SUPPORTED) + if (${shortname}_FLAG_SUPPORTED) + target_compile_options(${target} PRIVATE ${flag}) + endif() +endfunction() + +##================================================ +## Configure packages +##================================================ + +if (EXISTS ${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) + include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) + conan_basic_setup() +else() + find_package(OpenSSL REQUIRED) +endif() + +if (LINUX) + find_package(OpenAL REQUIRED) + find_package(ALSA) + find_package(PulseAudio) + find_package(Qt5 COMPONENTS DBus) +else() + # Needs OpenAL-SOFT + # Install via `brew install openal-soft` and configure with cmake call from README.md + find_package(OpenAL REQUIRED NO_MODULE) + set(OPENAL_LIBRARY OpenAL::OpenAL) +endif() + +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads) +find_package(ZLIB REQUIRED) +find_package(FFmpeg REQUIRED) +find_package(Opus REQUIRED) +find_package(Qt5 COMPONENTS Core Gui Widgets Network REQUIRED) + +if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.12.0") + find_package(Python3 REQUIRED) +else() + # TODO: remove when we will update cmake required version + find_package(PythonInterp) + if((PYTHONINTERP_FOUND) AND (PYTHON_VERSION_MAJOR GREATER 2)) + set(Python3_EXECUTABLE ${PYTHON_EXECUTABLE}) + else() + message(FATAL_ERROR "Python 3 is required") + endif() +endif() + +if (NOT SWSCALE_FOUND) + message(FATAL_ERROR "FFmpeg swscale is required") +endif() +if (NOT SWRESAMPLE_FOUND) + message(FATAL_ERROR "FFmpeg swresample is required") +endif() + +find_program(CCACHE ccache) +if (CCACHE) + message(STATUS "Enabling ccache") + set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE}) + set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE}) +endif() + +option(ENABLE_IPO "Enable IPO optimizations." OFF) +option(PACKAGED_BUILD "Enable packaged build." OFF) + +option(BUILD_DOC "Build documentation" OFF) +mark_as_advanced(BUILD_DOC) + +if(BUILD_DOC) + find_package(Doxygen) + if(DOXYGEN_FOUND) + add_custom_target( doc_doxygen ALL + COMMAND ${DOXYGEN_EXECUTABLE} ${PROJECT_SOURCE_DIR}/Doxyfile + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + COMMENT "Generating API documentation with Doxygen" + VERBATIM ) + endif() +endif() + +# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") +# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -O1 -fno-omit-frame-pointer -g") +add_subdirectory(Telegram) diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 000000000..1b15e6ec3 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,394 @@ +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = kepka +PROJECT_NUMBER = 2.0.0 +PROJECT_BRIEF = "Unofficial Telegram Desktop messaging app" +PROJECT_LOGO = Telegram/Resources/art/icon64.png +OUTPUT_DIRECTORY = doxyout +CREATE_SUBDIRS = NO +ALLOW_UNICODE_NAMES = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = YES +INLINE_INHERITED_MEMB = YES +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +QT_AUTOBRIEF = YES +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 4 +ALIASES = +TCL_SUBST = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +EXTENSION_MAPPING = +MARKDOWN_SUPPORT = YES +TOC_INCLUDE_HEADINGS = 0 +AUTOLINK_SUPPORT = YES +BUILTIN_STL_SUPPORT = YES +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +GROUP_NESTED_COMPOUNDS = NO +SUBGROUPING = YES +INLINE_GROUPED_CLASSES = NO +INLINE_SIMPLE_STRUCTS = NO +TYPEDEF_HIDES_STRUCT = NO +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +EXTRACT_ALL = NO +EXTRACT_PRIVATE = YES +EXTRACT_PACKAGE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = YES +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +HIDE_COMPOUND_REFERENCE= NO +SHOW_INCLUDE_FILES = YES +SHOW_GROUPED_MEMB_INC = NO +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = YES +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = YES +SORT_BY_SCOPE_NAME = NO +STRICT_PROTO_MATCHING = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = NO +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_AS_ERROR = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +INPUT = Telegram README.md docs +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f \ + *.for \ + *.tcl \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf + +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = ThirdParty* +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +FILTER_SOURCE_PATTERNS = +USE_MDFILE_AS_MAINPAGE = README.md + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +SOURCE_TOOLTIPS = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_EXTRA_STYLESHEET = +HTML_EXTRA_FILES = +HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +HTML_TIMESTAMP = NO +HTML_DYNAMIC_SECTIONS = NO +HTML_INDEX_NUM_ENTRIES = 100 +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_NAME = Publisher +GENERATE_HTMLHELP = NO +CHM_FILE = ecasbot.chm +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = UTF-8 +BINARY_TOC = YES +TOC_EXPAND = YES +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project +DISABLE_INDEX = NO +GENERATE_TREEVIEW = YES +ENUM_VALUES_PER_LINE = 4 +TREEVIEW_WIDTH = 200 +EXT_LINKS_IN_WINDOW = NO +FORMULA_FONTSIZE = 10 +FORMULA_TRANSPARENT = YES +USE_MATHJAX = NO +MATHJAX_FORMAT = HTML-CSS +MATHJAX_RELPATH = https://cdn.mathjax.org/mathjax/latest +MATHJAX_EXTENSIONS = +MATHJAX_CODEFILE = +SEARCHENGINE = NO +SERVER_BASED_SEARCH = NO +EXTERNAL_SEARCH = NO +SEARCHENGINE_URL = +SEARCHDATA_FILE = searchdata.xml +EXTERNAL_SEARCH_ID = +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4 +EXTRA_PACKAGES = +LATEX_HEADER = +LATEX_FOOTER = +LATEX_EXTRA_STYLESHEET = +LATEX_EXTRA_FILES = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +LATEX_SOURCE_CODE = NO +LATEX_BIB_STYLE = plain +LATEX_TIMESTAMP = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- + +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = YES +RTF_HYPERLINKS = YES +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +RTF_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- + +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_SUBDIR = +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- + +GENERATE_XML = NO +XML_OUTPUT = xml +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- + +GENERATE_DOCBOOK = NO +DOCBOOK_OUTPUT = docbook +DOCBOOK_PROGRAMLISTING = NO + +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- + +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +EXTERNAL_PAGES = YES +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +CLASS_DIAGRAMS = YES +MSCGEN_PATH = +DIA_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +DOT_NUM_THREADS = 0 +DOT_FONTNAME = Helvetica +DOT_FONTSIZE = 10 +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +UML_LIMIT_NUM_FIELDS = 10 +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +INTERACTIVE_SVG = NO +DOT_PATH = +DOTFILE_DIRS = +MSCFILE_DIRS = +DIAFILE_DIRS = +PLANTUML_JAR_PATH = +PLANTUML_CFG_FILE = +PLANTUML_INCLUDE_PATH = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES diff --git a/LICENSE b/LICENSE index 77e1f6119..d03583d1f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Telegram Desktop is licensed under the GNU General Public License +Kepka is licensed under the GNU General Public License version 3 with the addition of the following special exception: In addition, as a special exception, the copyright holders give diff --git a/README.md b/README.md index 683bea0a9..52c705b2c 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,128 @@ -# [Telegram Desktop][telegram_desktop] – Official Messenger +[![Version](https://badge.fury.io/gh/procxx%2Fkepka.svg)](https://github.com/procxx/kepka/releases) +[![Build Status](https://travis-ci.org/procxx/kepka.svg?branch=dev)](https://travis-ci.org/procxx/kepka) +[![Build status](https://ci.appveyor.com/api/projects/status/2kodvgwvlua3o6hp?svg=true +)](https://ci.appveyor.com/project/procxx/tdesktop) -This is the complete source code and the build instructions for the alpha version of the official desktop client for the [Telegram][telegram] messenger, based on the [Telegram API][telegram_api] and the [MTProto][telegram_proto] secure protocol. -[![Version](https://badge.fury.io/gh/telegramdesktop%2Ftdesktop.svg)](https://github.com/telegramdesktop/tdesktop/releases) -[![Build Status](https://travis-ci.org/telegramdesktop/tdesktop.svg?branch=dev)](https://travis-ci.org/telegramdesktop/tdesktop) -[![Build status](https://ci.appveyor.com/api/projects/status/uiw2y768iy4i5bu8/branch/dev?svg=true)](https://ci.appveyor.com/project/telegramdesktop/tdesktop) +# Kepka - Unofficial [Telegram Desktop][telegram_desktop] fork from pro.cxx community -[![Preview of Telegram Desktop][preview_image]][preview_image_url] +This is the complete source code and the build instructions for the Kepka's alpha version based on the [Telegram API][telegram_api] and the [MTProto][telegram_proto] secure protocol. + +## Key features and differences from upstream Telegram +* CMake-only build (with a bit of Conan/vcpkg/your package manager. No GYP or patched libraries required); +* Do not require GTK for dialogs and notifications. Kepka will use native from Qt; +* Removed some Qt private stuff from dependencies; +* Kepka can be built and dynamically linked against official Qt packages; +* Added support of native system-wide font settings. Kepka will inherit DE's configuration; +* Partial refactoring and code cleanup; + - reduced #includes coupling (increases compile times and improves program design); + - removed broken PCHs (they are only increases compile times and transform #includes into one big katamari); + - remove some Qt and custom types in favor of using C++ Standard Library types and classes; + - clang-format; + - fix almost all warnings; + - optional inter-procedural optimizations on \*nix (can be enabled by forwarding CMake's `-DENABLE_IPO:BOOL=ON` flag; improves performance but could significantly increase compilation times); + - optional packaged build for GNU/Linux maintainers (can be enabled by forwarding CMake's `-DPACKAGED_BUILD:BOOL=ON` flag; will disable automatic schema registration and icon generation); +* Ability to toggle "typographical" replaces (like replace << to « and another); +* Packages for Fedora and Arch Linux (packages for Debian and Ubuntu will be done soon); +* UI based on 1.1.21 before UI "mobilization" which degrades UX (e.g. group settings will be accessible from 5 clicks); +* Optional Yandex.Maps static API for geolocation preview (should be enabled at CMake configure time via `-DKEPKA_OPTION_USE_YANDEX_MAPS=ON` parameter); +* More features soon (see our [milestones](https://github.com/procxx/kepka/projects))! + +## Build instructions + +### Linux, macOS + +What you need to have installed: + +* Qt 5.9+ (with private modules, like qtbase5-private-dev) +* OpenSSL (conan installs this if you use conan) +* OpenAL-soft +* FFmpeg with swscale and swresample libs +* zlib +* opus (libopus-dev) + +#### Debian/Ubuntu: +```console +# apt-get install libssl-dev libavformat-dev libavdevice-dev libswscale-dev libavutil-dev libpulse-dev libasound2-dev libswresample-dev libavresample-dev libopus-dev qtbase5-private-dev zlib1g-dev libopenal-dev libavcodec-dev libopenal-data libopenal1 +``` + +You most likely have to rebuild ffmpeg with `--enable-swresample --enable-swscale` + +After that, go to the [next section](#configuring-and-building). + +#### Fedora: +```console +# dnf install rpm-build rpmdevtools mock mock-rpmfusion-free +``` + +Add yourself to `mock` group (you must run this only for the first time after installing mock): +```bash +sudo usermod -a -G mock $(whoami) +``` + +You need to relogin to your system or run: +```bash +newgrp mock +``` + +Create RPM build base directories: +```bash +rpmdev-setuptree +``` + +Download sources: +```bash +spectool -g -R kepka.spec +``` + +Generate SRPM: +```bash +rpmbuild -bs kepka.spec +``` + +Start mock build sequence: +```bash +mock -r fedora-$(rpm -E %fedora)-$(uname -m)-rpmfusion_free --rebuild ~/rpmbuild/SRPMS/kepka*.src.rpm +``` + +#### Configuring and building + +Provide paths to OpenAL-soft and Qt5 in CMAKE_PREFIX_PATH variable when configuring. + + ccache -o sloppiness=pch_defines,time_macros + mkdir _conan_build_ + cd _conan_build_ + conan install .. --build missing + cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH="/usr/local/opt/qt5/;/usr/local/opt/openal-soft" .. + ninja + +### Windows + +Install [vcpkg][] (no need to integrate, just install), [python][] 3.5, [cmake][], [Qt][qt] 5.9 or later and [Visual Studio][visual-studio] 2017 or later, and set the following environment variables: + +- `QTDIR`: directory where Qt binary distribution is installed, e.g. `C:\Qt\5.9.1\msvc2017_64` +- `VCPKG`: directory where VCPKG is installed, e.g. `C:\vcpkg` + +After that, execute the following `cmd` commands from Visual Studio developer command prompt: + +```console +$ set PATH=c:\Python35;%PATH% +$ "%VCPKG%\vcpkg" install --triplet x64-windows openal-soft openssl opus zlib ffmpeg +$ mkdir build +$ cd build +$ set PATH=%QTDIR%\bin;%PATH% +$ cmake -G"Visual Studio 15 2017 Win64" -DCMAKE_TOOLCHAIN_FILE="%VCPKG%\scripts\buildsystems\vcpkg.cmake" -DCMAKE_BUILD_TYPE=RelWithDebInfo .. +$ cmake --build . --config RelWithDebInfo +``` +![Preview of Telegram Desktop][preview_image] The source code is published under GPLv3 with OpenSSL exception, the license is available [here][license]. +The Kepka logo is available by CC-BY-SA 4.0 License. (c) 2018 leha-bot. The full CC-BY-SA 4.0 license text is available [here](https://creativecommons.org/licenses/by-sa/4.0/legalcode). + ## Supported systems -* Windows XP - Windows 10 (**not** RT) +* Windows 7 - Windows 10 (**not** RT) * Mac OS X 10.8 - Mac OS X 10.11 * Mac OS X 10.6 - Mac OS X 10.7 (separate build) * Ubuntu 12.04 - Ubuntu 16.04 @@ -20,15 +130,10 @@ The source code is published under GPLv3 with OpenSSL exception, the license is ## Third-party -* Qt 5.3.2 and 5.6.2, slightly patched ([LGPL](http://doc.qt.io/qt-5/lgpl.html)) +* [CMake 3.10+][cmake-build] +* Qt 5.9+ ([LGPL](http://doc.qt.io/qt-5/lgpl.html)) * OpenSSL 1.0.1g ([OpenSSL License](https://www.openssl.org/source/license.html)) * zlib 1.2.8 ([zlib License](http://www.zlib.net/zlib_license.html)) -* libexif 0.6.20 ([LGPL](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html)) -* LZMA SDK 9.20 ([public domain](http://www.7-zip.org/sdk.html)) -* liblzma ([public domain](http://tukaani.org/xz/)) -* Google Breakpad ([License](https://chromium.googlesource.com/breakpad/breakpad/+/master/LICENSE)) -* Google Crashpad ([Apache License 2.0](https://chromium.googlesource.com/crashpad/crashpad/+/master/LICENSE)) -* GYP ([BSD License](https://github.com/bnoordhuis/gyp/blob/master/LICENSE)) * Ninja ([Apache License 2.0](https://github.com/ninja-build/ninja/blob/master/COPYING)) * OpenAL Soft ([LGPL](http://kcat.strangesoft.net/openal.html)) * Opus codec ([BSD License](http://www.opus-codec.org/license/)) @@ -39,21 +144,16 @@ The source code is published under GPLv3 with OpenSSL exception, the license is * Emoji alpha codes ([MIT License](https://github.com/emojione/emojione/blob/master/extras/alpha-codes/LICENSE.md)) * Catch test framework ([Boost License](https://github.com/philsquared/Catch/blob/master/LICENSE.txt)) -## Build instructions - -* [Visual Studio 2017][msvc] -* [Xcode 8][xcode] -* [GYP/CMake on GNU/Linux][cmake] - [//]: # (LINKS) +[cmake]: https://cmake.org/ +[python]: https://python.org/ +[cmake-build]: docs/building-cmake.md +[qt]: https://www.qt.io/ [telegram]: https://telegram.org [telegram_desktop]: https://desktop.telegram.org [telegram_api]: https://core.telegram.org [telegram_proto]: https://core.telegram.org/mtproto [license]: LICENSE -[msvc]: docs/building-msvc.md -[xcode]: docs/building-xcode.md -[xcode_old]: docs/building-xcode-old.md -[cmake]: docs/building-cmake.md -[preview_image]: https://github.com/telegramdesktop/tdesktop/blob/dev/docs/assets/preview.png "Preview of Telegram Desktop" -[preview_image_url]: https://raw.githubusercontent.com/telegramdesktop/tdesktop/dev/docs/assets/preview.png +[preview_image]: docs/assets/preview.png +[vcpkg]: https://github.com/Microsoft/vcpkg +[visual-studio]: https://www.visualstudio.com/ diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt new file mode 100644 index 000000000..36ab4c50b --- /dev/null +++ b/Telegram/CMakeLists.txt @@ -0,0 +1,770 @@ +# defines +if (LINUX) + if (CMAKE_SIZEOF_VOID_P EQUAL 8) + add_definitions(-DQ_OS_LINUX64) + else() + add_definitions(-DQ_OS_LINUX32) + endif() +endif() + +##================================================ +## API tokens +##================================================ +if (DEFINED ENV{API_ID} AND DEFINED ENV{API_HASH}) + set(API_ID ENV{API_ID}) + set(API_HASH ENV{API_HASH}) +else() + message(WARNING "No custom API tokens detected. You must grab your own tokens from https://core.telegram.org/api/obtaining_api_id and export them using environment options. Will use default for testing purposes.") + set(API_ID 17349) + set(API_HASH "344583e45741c457fe1862106095a5eb") +endif() + +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -H") +set(CMAKE_INCLUDE_CURRENT_DIR ON) +##================================================ +## Codegen Tools +##================================================ +include_directories(SourceFiles) +add_subdirectory(SourceFiles/codegen) + +file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/styles) + +add_custom_command( + COMMENT "Generating palette" + OUTPUT + styles/palette.h + styles/palette.cpp + COMMAND + codegen_style -I${CMAKE_CURRENT_SOURCE_DIR}/Resources -I${CMAKE_CURRENT_SOURCE_DIR} + -o${CMAKE_CURRENT_BINARY_DIR}/styles -w${CMAKE_SOURCE_DIR} + colors.palette + WORKING_DIRECTORY styles + DEPENDS + codegen_style + ${CMAKE_CURRENT_SOURCE_DIR}/Resources/colors.palette + MAIN_DEPENDENCY + ${CMAKE_CURRENT_SOURCE_DIR}/Resources/colors.palette +) +add_custom_target(palette_output + DEPENDS styles/palette.h styles/palette.cpp) + +add_custom_command( + COMMENT "Generating numbers" + OUTPUT + numbers.h + numbers.cpp + COMMAND + codegen_numbers -o${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/Resources/numbers.txt + WORKING_DIRECTORY . + DEPENDS + codegen_numbers + ${CMAKE_CURRENT_SOURCE_DIR}/Resources/numbers.txt + MAIN_DEPENDENCY + ${CMAKE_CURRENT_SOURCE_DIR}/Resources/numbers.txt +) +add_custom_target(numbers_output + DEPENDS numbers.h numbers.cpp) + +add_custom_command( + COMMENT "Generating langs" + OUTPUT + lang_auto.h + lang_auto.cpp + COMMAND + codegen_lang -o${CMAKE_CURRENT_BINARY_DIR} -w${CMAKE_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/Resources/langs/lang.strings + WORKING_DIRECTORY . + DEPENDS + codegen_lang + ${CMAKE_CURRENT_SOURCE_DIR}/Resources/langs/lang.strings + MAIN_DEPENDENCY + ${CMAKE_CURRENT_SOURCE_DIR}/Resources/langs/lang.strings +) + +add_custom_target(lang_output + DEPENDS lang_auto.h lang_auto.cpp) + +add_custom_command( + COMMENT "Generating emoji" + OUTPUT + emoji.cpp + emoji.h + emoji_suggestions_data.cpp + emoji_suggestions_data.h + COMMAND + codegen_emoji ${CMAKE_CURRENT_SOURCE_DIR}/Resources/emoji_autocomplete.json + -o ${CMAKE_CURRENT_BINARY_DIR} + WORKING_DIRECTORY . + DEPENDS + codegen_emoji + ${CMAKE_CURRENT_SOURCE_DIR}/Resources/emoji_autocomplete.json + VERBATIM +) +add_custom_target(emoji_output + DEPENDS + emoji.h + emoji.cpp + emoji_suggestions_data.cpp + emoji_suggestions_data.h +) + +add_custom_command( + COMMENT "Generating scheme" + OUTPUT + scheme.cpp + scheme.h + COMMAND + ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/SourceFiles/codegen/scheme/codegen_scheme.py + -o${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/Resources/scheme.tl + WORKING_DIRECTORY . + DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/SourceFiles/codegen/scheme/codegen_scheme.py + ${CMAKE_CURRENT_SOURCE_DIR}/Resources/scheme.tl + MAIN_DEPENDENCY + ${CMAKE_CURRENT_SOURCE_DIR}/Resources/scheme.tl + VERBATIM +) +add_custom_target(scheme_output + DEPENDS scheme.h scheme.cpp) + +##================================================ + +list(APPEND style_files + Resources/basic + SourceFiles/boxes/boxes + SourceFiles/calls/calls + SourceFiles/chat_helpers/chat_helpers + SourceFiles/dialogs/dialogs + SourceFiles/history/history + SourceFiles/intro/intro + SourceFiles/media/player/media_player + SourceFiles/media/view/mediaview + SourceFiles/overview/overview + SourceFiles/profile/profile + SourceFiles/settings/settings + SourceFiles/ui/widgets/widgets + SourceFiles/window/window +) + +foreach (src ${style_files}) + get_filename_component(src_file ${src} NAME) + add_custom_command( + COMMENT "Generating ${src_file}" + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/styles/style_${src_file}.h + ${CMAKE_CURRENT_BINARY_DIR}/styles/style_${src_file}.cpp + COMMAND + codegen_style -I${CMAKE_CURRENT_SOURCE_DIR}/Resources -I${CMAKE_CURRENT_SOURCE_DIR} + -I${CMAKE_CURRENT_SOURCE_DIR}/SourceFiles + -o${CMAKE_CURRENT_BINARY_DIR}/styles -w${CMAKE_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/${src}.style + DEPENDS + codegen_style + ${CMAKE_CURRENT_SOURCE_DIR}/${src}.style + MAIN_DEPENDENCY + ${CMAKE_CURRENT_SOURCE_DIR}/${src}.style + ) + add_custom_target(${src_file}_styles_output + DEPENDS + ${CMAKE_CURRENT_BINARY_DIR}/styles/style_${src_file}.h + ${CMAKE_CURRENT_BINARY_DIR}/styles/style_${src_file}.cpp + ) + + list(APPEND style_sources + ${CMAKE_CURRENT_BINARY_DIR}/styles/style_${src_file}.cpp) + +endforeach() + +##================================================ +## Branding +##================================================ +configure_file(SourceFiles/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) + +##================================================ +## Kepka app +##================================================ +add_executable(Kepka WIN32 MACOSX_BUNDLE + ${CMAKE_CURRENT_BINARY_DIR}/styles/palette.cpp + ${CMAKE_CURRENT_BINARY_DIR}/numbers.cpp + ${CMAKE_CURRENT_BINARY_DIR}/lang_auto.cpp + ${CMAKE_CURRENT_BINARY_DIR}/scheme.cpp + ${CMAKE_CURRENT_BINARY_DIR}/emoji.cpp + ${CMAKE_CURRENT_BINARY_DIR}/emoji_suggestions_data.cpp + ${style_sources} + + SourceFiles/base/observer.cpp + SourceFiles/base/parse_helper.cpp + SourceFiles/base/qthelp_url.cpp + SourceFiles/base/runtime_composer.cpp + SourceFiles/base/task_queue.cpp + SourceFiles/base/timer.cpp + + SourceFiles/boxes/about_box.cpp + SourceFiles/boxes/abstract_box.cpp + SourceFiles/boxes/add_contact_box.cpp + SourceFiles/boxes/autolock_box.cpp + SourceFiles/boxes/background_box.cpp + SourceFiles/boxes/calendar_box.cpp + SourceFiles/boxes/change_phone_box.cpp + SourceFiles/boxes/confirm_box.cpp + SourceFiles/boxes/confirm_phone_box.cpp + SourceFiles/boxes/connection_box.cpp + SourceFiles/boxes/download_path_box.cpp + SourceFiles/boxes/edit_color_box.cpp + SourceFiles/boxes/edit_participant_box.cpp + SourceFiles/boxes/edit_privacy_box.cpp + SourceFiles/boxes/language_box.cpp + SourceFiles/boxes/local_storage_box.cpp + SourceFiles/boxes/mute_settings_box.cpp + SourceFiles/boxes/notifications_box.cpp + SourceFiles/boxes/passcode_box.cpp + SourceFiles/boxes/peer_list_box.cpp + SourceFiles/boxes/peer_list_controllers.cpp + SourceFiles/boxes/photo_crop_box.cpp + SourceFiles/boxes/rate_call_box.cpp + SourceFiles/boxes/report_box.cpp + SourceFiles/boxes/self_destruction_box.cpp + SourceFiles/boxes/send_files_box.cpp + SourceFiles/boxes/sessions_box.cpp + SourceFiles/boxes/share_box.cpp + SourceFiles/boxes/sticker_set_box.cpp + SourceFiles/boxes/stickers_box.cpp + SourceFiles/boxes/username_box.cpp + + SourceFiles/calls/calls_box_controller.cpp + SourceFiles/calls/calls_call.cpp + SourceFiles/calls/calls_emoji_fingerprint.cpp + SourceFiles/calls/calls_instance.cpp + SourceFiles/calls/calls_panel.cpp + SourceFiles/calls/calls_top_bar.cpp + + SourceFiles/chat_helpers/bot_keyboard.cpp + SourceFiles/chat_helpers/emoji_list_widget.cpp + SourceFiles/chat_helpers/emoji_suggestions_widget.cpp + SourceFiles/chat_helpers/field_autocomplete.cpp + SourceFiles/chat_helpers/gifs_list_widget.cpp + SourceFiles/chat_helpers/message_field.cpp + SourceFiles/chat_helpers/stickers.cpp + SourceFiles/chat_helpers/stickers_list_widget.cpp + SourceFiles/chat_helpers/tabbed_panel.cpp + SourceFiles/chat_helpers/tabbed_section.cpp + SourceFiles/chat_helpers/tabbed_selector.cpp + + SourceFiles/core/click_handler.cpp + SourceFiles/core/click_handler_types.cpp + SourceFiles/core/file_utilities.cpp + SourceFiles/core/single_timer.cpp + SourceFiles/core/utils.cpp + + SourceFiles/data/data_abstract_structure.cpp + SourceFiles/data/data_document.cpp + SourceFiles/data/data_drafts.cpp + SourceFiles/data/data_game.cpp + SourceFiles/data/data_photo.cpp + + SourceFiles/dialogs/dialogs_indexed_list.cpp + SourceFiles/dialogs/dialogs_inner_widget.cpp + SourceFiles/dialogs/dialogs_layout.cpp + SourceFiles/dialogs/dialogs_list.cpp + SourceFiles/dialogs/dialogs_row.cpp + SourceFiles/dialogs/dialogs_search_from_controllers.cpp + SourceFiles/dialogs/dialogs_widget.cpp + + SourceFiles/history/history.cpp + SourceFiles/history/history_admin_log_filter.cpp + SourceFiles/history/history_admin_log_inner.cpp + SourceFiles/history/history_admin_log_item.cpp + SourceFiles/history/history_admin_log_section.cpp + SourceFiles/history/history_drag_area.cpp + SourceFiles/history/history_inner_widget.cpp + SourceFiles/history/history_item.cpp + SourceFiles/history/history_location_manager.cpp + SourceFiles/history/history_media_types.cpp + SourceFiles/history/history_message.cpp + SourceFiles/history/history_service.cpp + SourceFiles/history/history_service_layout.cpp + SourceFiles/history/history_widget.cpp + + SourceFiles/inline_bots/inline_bot_layout_internal.cpp + SourceFiles/inline_bots/inline_bot_layout_item.cpp + SourceFiles/inline_bots/inline_bot_result.cpp + SourceFiles/inline_bots/inline_bot_send_data.cpp + SourceFiles/inline_bots/inline_results_widget.cpp + + SourceFiles/intro/introcode.cpp + SourceFiles/intro/introphone.cpp + SourceFiles/intro/intropwdcheck.cpp + SourceFiles/intro/introsignup.cpp + SourceFiles/intro/introstart.cpp + SourceFiles/intro/introwidget.cpp + + SourceFiles/lang/lang_cloud_manager.cpp + SourceFiles/lang/lang_file_parser.cpp + SourceFiles/lang/lang_instance.cpp + SourceFiles/lang/lang_keys.cpp + SourceFiles/lang/lang_tag.cpp + SourceFiles/lang/lang_translator.cpp + + SourceFiles/media/player/media_player_button.cpp + SourceFiles/media/player/media_player_cover.cpp + SourceFiles/media/player/media_player_float.cpp + SourceFiles/media/player/media_player_instance.cpp + SourceFiles/media/player/media_player_list.cpp + SourceFiles/media/player/media_player_panel.cpp + SourceFiles/media/player/media_player_volume_controller.cpp + SourceFiles/media/player/media_player_widget.cpp + + SourceFiles/media/view/media_clip_controller.cpp + SourceFiles/media/view/media_clip_playback.cpp + SourceFiles/media/view/media_clip_volume_controller.cpp + + SourceFiles/media/media_audio.cpp + SourceFiles/media/media_audio_capture.cpp + SourceFiles/media/media_audio_ffmpeg_loader.cpp + SourceFiles/media/media_audio_loader.cpp + SourceFiles/media/media_audio_loaders.cpp + SourceFiles/media/media_audio_track.cpp + SourceFiles/media/media_child_ffmpeg_loader.cpp + SourceFiles/media/media_clip_ffmpeg.cpp + SourceFiles/media/media_clip_implementation.cpp + SourceFiles/media/media_clip_qtgif.cpp + SourceFiles/media/media_clip_reader.cpp + + SourceFiles/mtproto/auth_key.cpp + SourceFiles/mtproto/config_loader.cpp + SourceFiles/mtproto/connection.cpp + SourceFiles/mtproto/connection_abstract.cpp + SourceFiles/mtproto/connection_auto.cpp + SourceFiles/mtproto/connection_http.cpp + SourceFiles/mtproto/connection_tcp.cpp + SourceFiles/mtproto/core_types.cpp + SourceFiles/mtproto/dc_options.cpp + SourceFiles/mtproto/dcenter.cpp + SourceFiles/mtproto/facade.cpp + SourceFiles/mtproto/mtp_instance.cpp + SourceFiles/mtproto/rpc_sender.cpp + SourceFiles/mtproto/rsa_public_key.cpp + SourceFiles/mtproto/session.cpp + SourceFiles/mtproto/special_config_request.cpp + SourceFiles/mtproto/type_utils.cpp + + SourceFiles/overview/overview_layout.cpp + + SourceFiles/profile/profile_back_button.cpp + SourceFiles/profile/profile_block_actions.cpp + SourceFiles/profile/profile_block_channel_members.cpp + SourceFiles/profile/profile_block_group_members.cpp + SourceFiles/profile/profile_block_info.cpp + SourceFiles/profile/profile_block_invite_link.cpp + SourceFiles/profile/profile_block_peer_list.cpp + SourceFiles/profile/profile_block_settings.cpp + SourceFiles/profile/profile_block_shared_media.cpp + SourceFiles/profile/profile_block_widget.cpp + SourceFiles/profile/profile_channel_controllers.cpp + SourceFiles/profile/profile_common_groups_section.cpp + SourceFiles/profile/profile_cover.cpp + SourceFiles/profile/profile_cover_drop_area.cpp + SourceFiles/profile/profile_fixed_bar.cpp + SourceFiles/profile/profile_inner_widget.cpp + SourceFiles/profile/profile_section_memento.cpp + SourceFiles/profile/profile_userpic_button.cpp + SourceFiles/profile/profile_widget.cpp + + SourceFiles/settings/settings_advanced_widget.cpp + SourceFiles/settings/settings_background_widget.cpp + SourceFiles/settings/settings_block_widget.cpp + SourceFiles/settings/settings_chat_settings_widget.cpp + SourceFiles/settings/settings_cover.cpp + SourceFiles/settings/settings_fixed_bar.cpp + SourceFiles/settings/settings_general_widget.cpp + SourceFiles/settings/settings_info_widget.cpp + SourceFiles/settings/settings_inner_widget.cpp + SourceFiles/settings/settings_layer.cpp + SourceFiles/settings/settings_notifications_widget.cpp + SourceFiles/settings/settings_privacy_controllers.cpp + SourceFiles/settings/settings_privacy_widget.cpp + SourceFiles/settings/settings_scale_widget.cpp + SourceFiles/settings/settings_widget.cpp + + SourceFiles/storage/file_download.cpp + SourceFiles/storage/file_upload.cpp + SourceFiles/storage/localimageloader.cpp + SourceFiles/storage/localstorage.cpp + SourceFiles/storage/serialize_common.cpp + SourceFiles/storage/serialize_document.cpp + + SourceFiles/ui/effects/cross_animation.cpp + SourceFiles/ui/effects/panel_animation.cpp + SourceFiles/ui/effects/radial_animation.cpp + SourceFiles/ui/effects/ripple_animation.cpp + SourceFiles/ui/effects/round_checkbox.cpp + SourceFiles/ui/effects/send_action_animations.cpp + SourceFiles/ui/effects/slide_animation.cpp + SourceFiles/ui/effects/widget_fade_wrap.cpp + SourceFiles/ui/effects/widget_slide_wrap.cpp + + SourceFiles/ui/style/style_core.cpp + SourceFiles/ui/style/style_core_color.cpp + SourceFiles/ui/style/style_core_font.cpp + SourceFiles/ui/style/style_core_icon.cpp + SourceFiles/ui/style/style_core_types.cpp + + SourceFiles/ui/text/text.cpp + SourceFiles/ui/text/text_block.cpp + SourceFiles/ui/text/text_entity.cpp + + SourceFiles/ui/toast/toast.cpp + SourceFiles/ui/toast/toast_manager.cpp + SourceFiles/ui/toast/toast_widget.cpp + + SourceFiles/ui/widgets/buttons.cpp + SourceFiles/ui/widgets/checkbox.cpp + SourceFiles/ui/widgets/continuous_sliders.cpp + SourceFiles/ui/widgets/discrete_sliders.cpp + SourceFiles/ui/widgets/dropdown_menu.cpp + SourceFiles/ui/widgets/inner_dropdown.cpp + SourceFiles/ui/widgets/input_fields.cpp + SourceFiles/ui/widgets/labels.cpp + SourceFiles/ui/widgets/menu.cpp + SourceFiles/ui/widgets/multi_select.cpp + SourceFiles/ui/widgets/popup_menu.cpp + SourceFiles/ui/widgets/scroll_area.cpp + SourceFiles/ui/widgets/shadow.cpp + SourceFiles/ui/widgets/tooltip.cpp + + SourceFiles/ui/abstract_button.cpp + SourceFiles/ui/animation.cpp + SourceFiles/ui/countryinput.cpp + SourceFiles/ui/emoji_config.cpp + SourceFiles/ui/images.cpp + SourceFiles/ui/special_buttons.cpp + SourceFiles/ui/twidget.cpp + + SourceFiles/window/themes/window_theme.cpp + SourceFiles/window/themes/window_theme_editor.cpp + SourceFiles/window/themes/window_theme_editor_block.cpp + SourceFiles/window/themes/window_theme_preview.cpp + SourceFiles/window/themes/window_theme_warning.cpp + + SourceFiles/window/main_window.cpp + SourceFiles/window/notifications_manager.cpp + SourceFiles/window/notifications_manager_default.cpp + SourceFiles/window/notifications_utilities.cpp + SourceFiles/window/player_wrap_widget.cpp + SourceFiles/window/section_widget.cpp + SourceFiles/window/top_bar_widget.cpp + SourceFiles/window/window_controller.cpp + SourceFiles/window/window_main_menu.cpp + SourceFiles/window/window_slide_animation.cpp + + SourceFiles/apiwrap.cpp + SourceFiles/app.cpp + SourceFiles/application.cpp + SourceFiles/auth_session.cpp + SourceFiles/config.cpp + SourceFiles/facades.cpp + SourceFiles/layerwidget.cpp + SourceFiles/layout.cpp + SourceFiles/logs.cpp + SourceFiles/main.cpp + SourceFiles/mainwidget.cpp + SourceFiles/mainwindow.cpp + SourceFiles/mediaview.cpp + SourceFiles/messenger.cpp + SourceFiles/observer_peer.cpp + SourceFiles/overviewwidget.cpp + SourceFiles/passcodewidget.cpp + SourceFiles/qt_functions.cpp + SourceFiles/settings.cpp + SourceFiles/shortcuts.cpp + SourceFiles/structs.cpp +) + +if (APPLE) + target_sources(Kepka PRIVATE + SourceFiles/platform/mac/file_utilities_mac.mm + SourceFiles/platform/mac/mac_utilities.mm + SourceFiles/platform/mac/main_window_mac.mm + SourceFiles/platform/mac/notifications_manager_mac.mm + SourceFiles/platform/mac/specific_mac.mm + SourceFiles/platform/mac/specific_mac_p.mm + SourceFiles/platform/mac/window_title_mac.mm + ) + set(tg_RESOURCES Resources/qrc/telegram_mac.qrc) +endif() + +if (WIN32) + configure_file(Resources/winrc/Kepka.rc.in Resources/winrc/Kepka.rc) + target_sources(Kepka PRIVATE + SourceFiles/platform/win/audio_win.cpp + SourceFiles/platform/win/file_utilities_win.cpp + SourceFiles/platform/win/main_window_win.cpp + SourceFiles/platform/win/notifications_manager_win.cpp + SourceFiles/platform/win/specific_win.cpp + SourceFiles/platform/win/window_title_win.cpp + SourceFiles/platform/win/windows_app_user_model_id.cpp + SourceFiles/platform/win/windows_dlls.cpp + SourceFiles/platform/win/windows_event_filter.cpp + + ${CMAKE_CURRENT_BINARY_DIR}/Resources/winrc/Kepka.rc + ) + set(tg_RESOURCES Resources/qrc/telegram_wnd.qrc) +endif() + +if (WINRT) + target_sources(Kepka PRIVATE + SourceFiles/platform/winrt/main_window_winrt.cpp + ) +endif() + +if (LINUX) + target_sources(Kepka PRIVATE + SourceFiles/platform/linux/file_utilities_linux.cpp + SourceFiles/platform/linux/linux_desktop_environment.cpp + SourceFiles/platform/linux/linux_gdk_helper.cpp + SourceFiles/platform/linux/linux_libnotify.cpp + SourceFiles/platform/linux/linux_libs.cpp + SourceFiles/platform/linux/main_window_linux.cpp + SourceFiles/platform/linux/notifications_manager_linux.cpp + SourceFiles/platform/linux/specific_linux.cpp + ) +endif() + +list(APPEND tg_RESOURCES + Resources/qrc/telegram.qrc + Resources/qrc/telegram_sounds.qrc + Resources/qrc/telegram_emoji.qrc + Resources/qrc/telegram_emoji_large.qrc +) + +qt5_add_resources(tg_RESOURCES_RCC ${tg_RESOURCES}) + +target_sources(Kepka PRIVATE + ${tg_RESOURCES_RCC} +) + +if (APPLE) + target_sources(Kepka PRIVATE + ThirdParty/SPMediaKeyTap/SPMediaKeyTap.m + ThirdParty/SPMediaKeyTap/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.m + ) + target_include_directories(Kepka PRIVATE ThirdParty/SPMediaKeyTap) +endif() + +target_sources(Kepka PRIVATE + ThirdParty/minizip/ioapi.c + ThirdParty/minizip/zip.c + ThirdParty/minizip/unzip.c + + ThirdParty/emoji_suggestions/emoji_suggestions.cpp +) + +include_directories(ThirdParty/GSL/include + ThirdParty/variant/include + ThirdParty/emoji_suggestions + ThirdParty/libtgvoip + ThirdParty +) + +add_subdirectory(ThirdParty/libtgvoip) + +if(NOT WIN32) + add_definitions(-Wno-switch) +endif() + +if (WIN32) + add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS + -DWIN32 -D_WINDOWS -D_UNICODE -DUNICODE + -DWINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP + -DHAVE_STDINT_H -DNOMINMAX) +endif() + +add_definitions(-DAL_ALEXT_PROTOTYPES) + +if (LINUX) + add_definitions(-D_REENTRANT) +endif() + +# TODO check if needs libexif in deps + +if (APPLE) + set(MACOSX_BUNDLE_ICON_FILE Icon.icns) + + add_custom_command( + COMMENT "Generating icon file" + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/${MACOSX_BUNDLE_ICON_FILE} + COMMAND + iconutil -c icns -o ${CMAKE_CURRENT_BINARY_DIR}/${MACOSX_BUNDLE_ICON_FILE} + ${CMAKE_CURRENT_SOURCE_DIR}/Telegram/Images.xcassets/Icon.iconset/ + WORKING_DIRECTORY . + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/Telegram/Images.xcassets/Icon.iconset + MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/Telegram/Images.xcassets/Icon.iconset + ) + add_custom_target(iconset_output + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${MACOSX_BUNDLE_ICON_FILE}) + + set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/${MACOSX_BUNDLE_ICON_FILE} + PROPERTIES + MACOSX_PACKAGE_LOCATION Resources) + + target_sources(Kepka PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}/${MACOSX_BUNDLE_ICON_FILE} + ) + + foreach(langpack en de es it nl ko pt-BR) + set(LOCALIZABLE_STRINGS Resources/langs/${langpack}.lproj/Localizable.strings) + set_source_files_properties(${LOCALIZABLE_STRINGS} + PROPERTIES + MACOSX_PACKAGE_LOCATION ${LOCALIZABLE_STRINGS}) + target_sources(Kepka PRIVATE + ${LOCALIZABLE_STRINGS} + ) + endforeach(langpack) +endif() + +# Disable a single annoying warning about c++17 +if(NOT WIN32) + set_flag_if_supported(Kepka WNCE -Wno-c++1z-extensions) +endif() + +target_compile_definitions(Kepka PRIVATE + TDESKTOP_DISABLE_CRASH_REPORTS + ${FFMPEG_DEFINITIONS}) + +if (PACKAGED_BUILD) + target_compile_definitions(Kepka PRIVATE + TDESKTOP_DISABLE_REGISTER_CUSTOM_SCHEME + TDESKTOP_DISABLE_DESKTOP_FILE_GENERATION) +endif() + +if(MSVC AND MSVC_VERSION GREATER_EQUAL 1912) + target_compile_options(Kepka PRIVATE /permissive-) +endif() + +target_include_directories(Kepka PRIVATE ${OPENAL_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} + ${OPUS_INCLUDE_DIR} ${FFMPEG_INCLUDE_DIRS} ${ALSA_INCLUDE_DIRS} ${PULSEAUDIO_INCLUDE_DIR} ) + +target_link_libraries(Kepka + Qt5::Core + Qt5::Widgets + Qt5::Network + Qt5::GuiPrivate + Threads::Threads + tgvoip + ${OPENAL_LIBRARY} + ${FFMPEG_LIBRARIES} + ${ZLIB_LIBRARIES} + ${SWRESAMPLE_LIBRARIES} + ${SWSCALE_LIBRARIES} + ${OPENSSL_LIBRARIES} + ${OPUS_LIBRARIES} + ${CONAN_LIBS} +) # crashpad::crashpad_client) + +if (APPLE) + add_dependencies(Kepka iconset_output) + + set_target_properties(Kepka + PROPERTIES + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Telegram.plist + ) + foreach(framework + Cocoa + CoreFoundation + CoreServices + ApplicationServices + CoreText + CoreGraphics + Foundation + OpenGL + QuartzCore + AGL + Security + SystemConfiguration + Carbon + CoreAudio + AudioToolbox + AudioUnit + AppKit + CoreWLAN + IOKit + ) + set(FW_LIB FW_LIB-NOTFOUND) + find_library(FW_LIB ${framework}) + message(STATUS "Found framework ${FW_LIB}") + target_link_libraries(Kepka ${FW_LIB}) + endforeach(framework) + set(FW_LIB FW_LIB-NOTFOUND) +endif() + +if(WIN32) + target_link_libraries(Kepka + winmm imm32 ws2_32 kernel32 user32 gdi32 winspool comdlg32 advapi32 shell32 ole32 + oleaut32 uuid odbc32 odbccp32 Shlwapi Iphlpapi Gdiplus Strmiids + ) +endif() + +if (LINUX) + target_link_libraries(Kepka Qt5::DBus dl ${ALSA_LIBRARIES} ${PULSEAUDIO_LIBRARIES}) +endif() + +# Enable LTO optimizations... +if(ENABLE_IPO) + include(CheckIPOSupported) + check_ipo_supported(RESULT ipo_result OUTPUT ipo_output) + + if(ipo_result) + message(STATUS "IPO optimizations enabled.") + if(LINUX AND (CMAKE_CXX_COMPILER_ID MATCHES "GNU")) + set(CMAKE_AR "/usr/bin/gcc-ar") + set(CMAKE_RANLIB "/usr/bin/gcc-ranlib") + set(CMAKE_NM "/usr/bin/gcc-nm") + endif() + set_property(TARGET Kepka PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) + else() + message(WARNING "IPO is not supported: ${ipo_output}") + endif() +endif() + +##================================================ +## Installlation +##================================================ + +include(GNUInstallDirs) + +set_target_properties(Kepka PROPERTIES + OUTPUT_NAME "kepka" + AUTOMOC ON +) + +install(TARGETS Kepka + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR}) + +install(FILES "${CMAKE_SOURCE_DIR}/lib/xdg/kepka.desktop" + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications +) +install(FILES "${CMAKE_SOURCE_DIR}/lib/xdg/tg.protocol" + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/kservices5 +) +install(FILES "${CMAKE_SOURCE_DIR}/lib/xdg/kepka.appdata.xml" + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/metainfo +) + +foreach(icon_size 16 32 48 64 128 256 512) + install(FILES "${CMAKE_SOURCE_DIR}/Telegram/Resources/art/icon${icon_size}.png" + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/${icon_size}x${icon_size}/apps + RENAME kepka.png + ) +endforeach(icon_size) + +##================================================ +## Tests +##================================================ + +if(BUILD_TESTING) + include_directories(ThirdParty/Catch/single_include) + add_subdirectory(SourceFiles/base/tests) +endif() diff --git a/Telegram/Patches/breakpad.diff b/Telegram/Patches/breakpad.diff deleted file mode 100644 index bde669862..000000000 --- a/Telegram/Patches/breakpad.diff +++ /dev/null @@ -1,481 +0,0 @@ -diff --git a/src/build/common.gypi b/src/build/common.gypi -index b9466a3..9fb31aa 100644 ---- a/src/build/common.gypi -+++ b/src/build/common.gypi -@@ -330,6 +330,7 @@ - 'VCCLCompilerTool': { - 'WarnAsError': 'true', - 'Detect64BitPortabilityProblems': 'false', -+ 'TreatWChar_tAsBuiltInType': 'false', - }, - }, - }], -diff --git a/src/client/mac/Breakpad.xcodeproj/project.pbxproj b/src/client/mac/Breakpad.xcodeproj/project.pbxproj -index 1a93ce6..1c1d643 100644 ---- a/src/client/mac/Breakpad.xcodeproj/project.pbxproj -+++ b/src/client/mac/Breakpad.xcodeproj/project.pbxproj -@@ -35,6 +35,19 @@ - /* End PBXAggregateTarget section */ - - /* Begin PBXBuildFile section */ -+ 0748C0431C63C409004489BF /* MachIPC.mm in Sources */ = {isa = PBXBuildFile; fileRef = F92C53790ECCE635009BE4BA /* MachIPC.mm */; }; -+ 0748C0441C63C43C004489BF /* minidump_generator.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C536F0ECCE3FD009BE4BA /* minidump_generator.cc */; }; -+ 0748C0451C63C46C004489BF /* string_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53820ECCE635009BE4BA /* string_utilities.cc */; }; -+ 0748C0461C63C484004489BF /* minidump_file_writer.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C538F0ECCE70A009BE4BA /* minidump_file_writer.cc */; }; -+ 0748C0471C63C4A1004489BF /* dynamic_images.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C536B0ECCE3FD009BE4BA /* dynamic_images.cc */; }; -+ 0748C0491C63C4CF004489BF /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C537A0ECCE635009BE4BA /* macho_id.cc */; }; -+ 0748C04A1C63C4D4004489BF /* string_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53850ECCE6AD009BE4BA /* string_conversion.cc */; }; -+ 0748C04B1C63C4DB004489BF /* convert_UTF.c in Sources */ = {isa = PBXBuildFile; fileRef = F92C53870ECCE6C0009BE4BA /* convert_UTF.c */; }; -+ 0748C04C1C63C4EA004489BF /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C537C0ECCE635009BE4BA /* macho_utilities.cc */; }; -+ 0748C04D1C63C50F004489BF /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53740ECCE635009BE4BA /* file_id.cc */; }; -+ 0748C04E1C63C51C004489BF /* md5.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D72CA0D13DFAD5C006CABE3 /* md5.cc */; }; -+ 0748C04F1C63C523004489BF /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C537E0ECCE635009BE4BA /* macho_walker.cc */; }; -+ 0748C0501C63C52D004489BF /* bootstrap_compat.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D61A25D14F43CFC002D5862 /* bootstrap_compat.cc */; }; - 162F64F2161C577500CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64F0161C577500CD68D5 /* arch_utilities.cc */; }; - 162F64F3161C577500CD68D5 /* arch_utilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 162F64F1161C577500CD68D5 /* arch_utilities.h */; }; - 162F64F4161C579B00CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64F0161C577500CD68D5 /* arch_utilities.cc */; }; -@@ -170,11 +183,8 @@ - F92C564A0ECD10CA009BE4BA /* string_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53850ECCE6AD009BE4BA /* string_conversion.cc */; }; - F92C564C0ECD10DD009BE4BA /* breakpadUtilities.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F92C563C0ECD10B3009BE4BA /* breakpadUtilities.dylib */; }; - F92C56570ECD113E009BE4BA /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F92C554A0ECCF530009BE4BA /* Carbon.framework */; }; -- F92C565C0ECD1158009BE4BA /* breakpadUtilities.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F92C563C0ECD10B3009BE4BA /* breakpadUtilities.dylib */; }; - F92C565F0ECD116B009BE4BA /* protected_memory_allocator.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53720ECCE3FD009BE4BA /* protected_memory_allocator.cc */; }; - F92C56630ECD1179009BE4BA /* exception_handler.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C536D0ECCE3FD009BE4BA /* exception_handler.cc */; }; -- F92C56650ECD1185009BE4BA /* breakpadUtilities.dylib in Resources */ = {isa = PBXBuildFile; fileRef = F92C563C0ECD10B3009BE4BA /* breakpadUtilities.dylib */; }; -- F92C568A0ECD15F9009BE4BA /* Inspector in Resources */ = {isa = PBXBuildFile; fileRef = F92C53540ECCE349009BE4BA /* Inspector */; }; - F92C56A90ECE04C5009BE4BA /* crash_report_sender.m in Sources */ = {isa = PBXBuildFile; fileRef = F92C56A80ECE04C5009BE4BA /* crash_report_sender.m */; }; - F93803CD0F8083B7004D428B /* dynamic_images.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C536B0ECCE3FD009BE4BA /* dynamic_images.cc */; }; - F93803CE0F8083B7004D428B /* exception_handler.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C536D0ECCE3FD009BE4BA /* exception_handler.cc */; }; -@@ -213,7 +223,6 @@ - F9C44DBD0EF072A0003AEBAA /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = F9C44DBA0EF072A0003AEBAA /* MainMenu.xib */; }; - F9C44E000EF077CD003AEBAA /* Breakpad.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Breakpad.framework */; }; - F9C44E3C0EF08B12003AEBAA /* Breakpad.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Breakpad.framework */; }; -- F9C44E980EF09F56003AEBAA /* crash_report_sender.app in Resources */ = {isa = PBXBuildFile; fileRef = F92C56A00ECE04A7009BE4BA /* crash_report_sender.app */; }; - F9C44EA20EF09F93003AEBAA /* HTTPMultipartUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = F92C53770ECCE635009BE4BA /* HTTPMultipartUpload.m */; }; - F9C44EE50EF0A006003AEBAA /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9C44EE40EF0A006003AEBAA /* SystemConfiguration.framework */; }; - F9C44EE90EF0A3C1003AEBAA /* GTMLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = F9C44EE80EF0A3C1003AEBAA /* GTMLogger.m */; }; -@@ -410,20 +419,6 @@ - remoteGlobalIDString = F92C563B0ECD10B3009BE4BA; - remoteInfo = breakpadUtilities; - }; -- F92C56850ECD15EF009BE4BA /* PBXContainerItemProxy */ = { -- isa = PBXContainerItemProxy; -- containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; -- proxyType = 1; -- remoteGlobalIDString = F92C563B0ECD10B3009BE4BA; -- remoteInfo = breakpadUtilities; -- }; -- F92C56870ECD15F1009BE4BA /* PBXContainerItemProxy */ = { -- isa = PBXContainerItemProxy; -- containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; -- proxyType = 1; -- remoteGlobalIDString = F92C53530ECCE349009BE4BA; -- remoteInfo = Inspector; -- }; - F93DE2FB0F82C3C600608B94 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; -@@ -536,13 +531,6 @@ - remoteGlobalIDString = 8DC2EF4F0486A6940098B216; - remoteInfo = Breakpad; - }; -- F9C44E960EF09F4B003AEBAA /* PBXContainerItemProxy */ = { -- isa = PBXContainerItemProxy; -- containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; -- proxyType = 1; -- remoteGlobalIDString = F92C569F0ECE04A7009BE4BA; -- remoteInfo = crash_report_sender; -- }; - /* End PBXContainerItemProxy section */ - - /* Begin PBXCopyFilesBuildPhase section */ -@@ -714,7 +702,6 @@ - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( -- F92C565C0ECD1158009BE4BA /* breakpadUtilities.dylib in Frameworks */, - 8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; -@@ -1181,18 +1168,13 @@ - isa = PBXNativeTarget; - buildConfigurationList = 1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "Breakpad" */; - buildPhases = ( -- F97A0E850ED4EC15008784D3 /* Change install name of breakpadUtilities */, - 8DC2EF500486A6940098B216 /* Headers */, -- 8DC2EF520486A6940098B216 /* Resources */, - 8DC2EF540486A6940098B216 /* Sources */, - 8DC2EF560486A6940098B216 /* Frameworks */, - ); - buildRules = ( - ); - dependencies = ( -- F92C56860ECD15EF009BE4BA /* PBXTargetDependency */, -- F92C56880ECD15F1009BE4BA /* PBXTargetDependency */, -- F9C44E970EF09F4B003AEBAA /* PBXTargetDependency */, - ); - name = Breakpad; - productInstallPath = "$(HOME)/Library/Frameworks"; -@@ -1399,6 +1381,8 @@ - /* Begin PBXProject section */ - 0867D690FE84028FC02AAC07 /* Project object */ = { - isa = PBXProject; -+ attributes = { -+ }; - buildConfigurationList = 1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "Breakpad" */; - compatibilityVersion = "Xcode 3.1"; - developmentRegion = English; -@@ -1583,16 +1567,6 @@ - /* End PBXReferenceProxy section */ - - /* Begin PBXResourcesBuildPhase section */ -- 8DC2EF520486A6940098B216 /* Resources */ = { -- isa = PBXResourcesBuildPhase; -- buildActionMask = 2147483647; -- files = ( -- F9C44E980EF09F56003AEBAA /* crash_report_sender.app in Resources */, -- F92C568A0ECD15F9009BE4BA /* Inspector in Resources */, -- F92C56650ECD1185009BE4BA /* breakpadUtilities.dylib in Resources */, -- ); -- runOnlyForDeploymentPostprocessing = 0; -- }; - F92C569C0ECE04A7009BE4BA /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; -@@ -1640,20 +1614,6 @@ - shellPath = /bin/sh; - shellScript = "install_name_tool -id \"@executable_path/../Resources/breakpadUtilities.dylib\" \"${BUILT_PRODUCTS_DIR}/breakpadUtilities.dylib\"\n"; - }; -- F97A0E850ED4EC15008784D3 /* Change install name of breakpadUtilities */ = { -- isa = PBXShellScriptBuildPhase; -- buildActionMask = 2147483647; -- files = ( -- ); -- inputPaths = ( -- ); -- name = "Change install name of breakpadUtilities"; -- outputPaths = ( -- ); -- runOnlyForDeploymentPostprocessing = 0; -- shellPath = /bin/sh; -- shellScript = "#!/bin/bash\ninstall_name_tool -id \"@executable_path/../Frameworks/Breakpad.framework/Resources/breakpadUtilities.dylib\" \"${BUILT_PRODUCTS_DIR}/breakpadUtilities.dylib\"\n"; -- }; - F9C77DD80F7DD5CF0045F7DB /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; -@@ -1674,6 +1634,19 @@ - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( -+ 0748C0501C63C52D004489BF /* bootstrap_compat.cc in Sources */, -+ 0748C04F1C63C523004489BF /* macho_walker.cc in Sources */, -+ 0748C04E1C63C51C004489BF /* md5.cc in Sources */, -+ 0748C04D1C63C50F004489BF /* file_id.cc in Sources */, -+ 0748C04C1C63C4EA004489BF /* macho_utilities.cc in Sources */, -+ 0748C04B1C63C4DB004489BF /* convert_UTF.c in Sources */, -+ 0748C04A1C63C4D4004489BF /* string_conversion.cc in Sources */, -+ 0748C0491C63C4CF004489BF /* macho_id.cc in Sources */, -+ 0748C0471C63C4A1004489BF /* dynamic_images.cc in Sources */, -+ 0748C0461C63C484004489BF /* minidump_file_writer.cc in Sources */, -+ 0748C0451C63C46C004489BF /* string_utilities.cc in Sources */, -+ 0748C0441C63C43C004489BF /* minidump_generator.cc in Sources */, -+ 0748C0431C63C409004489BF /* MachIPC.mm in Sources */, - F92C565F0ECD116B009BE4BA /* protected_memory_allocator.cc in Sources */, - F92C56630ECD1179009BE4BA /* exception_handler.cc in Sources */, - F92C55D10ECD0064009BE4BA /* Breakpad.mm in Sources */, -@@ -1955,16 +1928,6 @@ - target = F92C563B0ECD10B3009BE4BA /* breakpadUtilities */; - targetProxy = F92C564D0ECD10E5009BE4BA /* PBXContainerItemProxy */; - }; -- F92C56860ECD15EF009BE4BA /* PBXTargetDependency */ = { -- isa = PBXTargetDependency; -- target = F92C563B0ECD10B3009BE4BA /* breakpadUtilities */; -- targetProxy = F92C56850ECD15EF009BE4BA /* PBXContainerItemProxy */; -- }; -- F92C56880ECD15F1009BE4BA /* PBXTargetDependency */ = { -- isa = PBXTargetDependency; -- target = F92C53530ECCE349009BE4BA /* Inspector */; -- targetProxy = F92C56870ECD15F1009BE4BA /* PBXContainerItemProxy */; -- }; - F93DE2FC0F82C3C600608B94 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = F93803BD0F80820F004D428B /* generator_test */; -@@ -2025,11 +1988,6 @@ - target = 8DC2EF4F0486A6940098B216 /* Breakpad */; - targetProxy = F9C44E190EF0790F003AEBAA /* PBXContainerItemProxy */; - }; -- F9C44E970EF09F4B003AEBAA /* PBXTargetDependency */ = { -- isa = PBXTargetDependency; -- target = F92C569F0ECE04A7009BE4BA /* crash_report_sender */; -- targetProxy = F9C44E960EF09F4B003AEBAA /* PBXContainerItemProxy */; -- }; - /* End PBXTargetDependency section */ - - /* Begin PBXVariantGroup section */ -@@ -2126,8 +2084,12 @@ - isa = XCBuildConfiguration; - baseConfigurationReference = 8B31027711F0D3AF00FCF3E4 /* BreakpadDebug.xcconfig */; - buildSettings = { -+ CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; -+ CLANG_CXX_LIBRARY = "libc++"; - GCC_TREAT_WARNINGS_AS_ERRORS = NO; -- SDKROOT = macosx10.5; -+ GCC_VERSION = ""; -+ MACOSX_DEPLOYMENT_TARGET = 10.8; -+ SDKROOT = macosx; - }; - name = Debug; - }; -@@ -2135,7 +2097,12 @@ - isa = XCBuildConfiguration; - baseConfigurationReference = 8B31027811F0D3AF00FCF3E4 /* BreakpadRelease.xcconfig */; - buildSettings = { -+ CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; -+ CLANG_CXX_LIBRARY = "libc++"; - GCC_TREAT_WARNINGS_AS_ERRORS = NO; -+ GCC_VERSION = ""; -+ MACOSX_DEPLOYMENT_TARGET = 10.8; -+ SDKROOT = macosx; - }; - name = Release; - }; -@@ -2454,7 +2421,12 @@ - isa = XCBuildConfiguration; - baseConfigurationReference = 8B31027711F0D3AF00FCF3E4 /* BreakpadDebug.xcconfig */; - buildSettings = { -+ CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; -+ CLANG_CXX_LIBRARY = "libc++"; - GCC_TREAT_WARNINGS_AS_ERRORS = NO; -+ GCC_VERSION = ""; -+ MACOSX_DEPLOYMENT_TARGET = 10.8; -+ SDKROOT = macosx; - }; - name = "Debug With Code Coverage"; - }; -diff --git a/src/client/mac/Framework/Breakpad.mm b/src/client/mac/Framework/Breakpad.mm -index 1d2e519..943310f 100644 ---- a/src/client/mac/Framework/Breakpad.mm -+++ b/src/client/mac/Framework/Breakpad.mm -@@ -355,10 +355,10 @@ bool Breakpad::Initialize(NSDictionary *parameters) { - return false; - } - -- if ([[parameters objectForKey:@BREAKPAD_IN_PROCESS] boolValue]) -+// if ([[parameters objectForKey:@BREAKPAD_IN_PROCESS] boolValue]) - return InitializeInProcess(parameters); -- else -- return InitializeOutOfProcess(parameters); -+// else -+// return InitializeOutOfProcess(parameters); - } - - //============================================================================= -@@ -373,52 +373,52 @@ bool Breakpad::InitializeInProcess(NSDictionary* parameters) { - } - - //============================================================================= --bool Breakpad::InitializeOutOfProcess(NSDictionary* parameters) { -- // Get path to Inspector executable. -- NSString *inspectorPathString = KeyValue(@BREAKPAD_INSPECTOR_LOCATION); -- -- // Standardize path (resolve symlinkes, etc.) and escape spaces -- inspectorPathString = [inspectorPathString stringByStandardizingPath]; -- inspectorPathString = [[inspectorPathString componentsSeparatedByString:@" "] -- componentsJoinedByString:@"\\ "]; -- -- // Create an on-demand server object representing the Inspector. -- // In case of a crash, we simply need to call the LaunchOnDemand() -- // method on it, then send a mach message to its service port. -- // It will then launch and perform a process inspection of our crashed state. -- // See the HandleException() method for the details. --#define RECEIVE_PORT_NAME "com.Breakpad.Inspector" -- -- name_t portName; -- snprintf(portName, sizeof(name_t), "%s%d", RECEIVE_PORT_NAME, getpid()); -- -- // Save the location of the Inspector -- strlcpy(inspector_path_, [inspectorPathString fileSystemRepresentation], -- sizeof(inspector_path_)); -- -- // Append a single command-line argument to the Inspector path -- // representing the bootstrap name of the launch-on-demand receive port. -- // When the Inspector is launched, it can use this to lookup the port -- // by calling bootstrap_check_in(). -- strlcat(inspector_path_, " ", sizeof(inspector_path_)); -- strlcat(inspector_path_, portName, sizeof(inspector_path_)); -- -- kern_return_t kr = inspector_.Initialize(inspector_path_, -- portName, -- true); // shutdown on exit -- -- if (kr != KERN_SUCCESS) { -- return false; -- } -- -- // Create the handler (allocating it in our special protected pool) -- handler_ = -- new (gBreakpadAllocator->Allocate( -- sizeof(google_breakpad::ExceptionHandler))) -- google_breakpad::ExceptionHandler( -- Breakpad::ExceptionHandlerDirectCallback, this, true); -- return true; --} -+//bool Breakpad::InitializeOutOfProcess(NSDictionary* parameters) { -+// // Get path to Inspector executable. -+// NSString *inspectorPathString = KeyValue(@BREAKPAD_INSPECTOR_LOCATION); -+// -+// // Standardize path (resolve symlinkes, etc.) and escape spaces -+// inspectorPathString = [inspectorPathString stringByStandardizingPath]; -+// inspectorPathString = [[inspectorPathString componentsSeparatedByString:@" "] -+// componentsJoinedByString:@"\\ "]; -+// -+// // Create an on-demand server object representing the Inspector. -+// // In case of a crash, we simply need to call the LaunchOnDemand() -+// // method on it, then send a mach message to its service port. -+// // It will then launch and perform a process inspection of our crashed state. -+// // See the HandleException() method for the details. -+//#define RECEIVE_PORT_NAME "com.Breakpad.Inspector" -+// -+// name_t portName; -+// snprintf(portName, sizeof(name_t), "%s%d", RECEIVE_PORT_NAME, getpid()); -+// -+// // Save the location of the Inspector -+// strlcpy(inspector_path_, [inspectorPathString fileSystemRepresentation], -+// sizeof(inspector_path_)); -+// -+// // Append a single command-line argument to the Inspector path -+// // representing the bootstrap name of the launch-on-demand receive port. -+// // When the Inspector is launched, it can use this to lookup the port -+// // by calling bootstrap_check_in(). -+// strlcat(inspector_path_, " ", sizeof(inspector_path_)); -+// strlcat(inspector_path_, portName, sizeof(inspector_path_)); -+// -+// kern_return_t kr = inspector_.Initialize(inspector_path_, -+// portName, -+// true); // shutdown on exit -+// -+// if (kr != KERN_SUCCESS) { -+// return false; -+// } -+// -+// // Create the handler (allocating it in our special protected pool) -+// handler_ = -+// new (gBreakpadAllocator->Allocate( -+// sizeof(google_breakpad::ExceptionHandler))) -+// google_breakpad::ExceptionHandler( -+// Breakpad::ExceptionHandlerDirectCallback, this, true); -+// return true; -+//} - - //============================================================================= - Breakpad::~Breakpad() { -@@ -445,10 +445,10 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) { - NSString *version = [parameters objectForKey:@BREAKPAD_VERSION]; - NSString *urlStr = [parameters objectForKey:@BREAKPAD_URL]; - NSString *interval = [parameters objectForKey:@BREAKPAD_REPORT_INTERVAL]; -- NSString *inspectorPathString = -- [parameters objectForKey:@BREAKPAD_INSPECTOR_LOCATION]; -- NSString *reporterPathString = -- [parameters objectForKey:@BREAKPAD_REPORTER_EXE_LOCATION]; -+// NSString *inspectorPathString = -+// [parameters objectForKey:@BREAKPAD_INSPECTOR_LOCATION]; -+// NSString *reporterPathString = -+// [parameters objectForKey:@BREAKPAD_REPORTER_EXE_LOCATION]; - NSString *timeout = [parameters objectForKey:@BREAKPAD_CONFIRM_TIMEOUT]; - NSArray *logFilePaths = [parameters objectForKey:@BREAKPAD_LOGFILES]; - NSString *logFileTailSize = -@@ -536,39 +536,39 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) { - } - - // Find the helper applications if not specified in user config. -- NSString *resourcePath = nil; -- if (!inspectorPathString || !reporterPathString) { -- resourcePath = GetResourcePath(); -- if (!resourcePath) { -- return false; -- } -- } -+// NSString *resourcePath = nil; -+// if (!inspectorPathString || !reporterPathString) { -+// resourcePath = GetResourcePath(); -+// if (!resourcePath) { -+// return false; -+// } -+// } - - // Find Inspector. -- if (!inspectorPathString) { -- inspectorPathString = -- [resourcePath stringByAppendingPathComponent:@"Inspector"]; -- } -- -- // Verify that there is an Inspector tool. -- if (![[NSFileManager defaultManager] fileExistsAtPath:inspectorPathString]) { -- return false; -- } -+// if (!inspectorPathString) { -+// inspectorPathString = -+// [resourcePath stringByAppendingPathComponent:@"Inspector"]; -+// } -+// -+// // Verify that there is an Inspector tool. -+// if (![[NSFileManager defaultManager] fileExistsAtPath:inspectorPathString]) { -+// return false; -+// } - - // Find Reporter. -- if (!reporterPathString) { -- reporterPathString = -- [resourcePath -- stringByAppendingPathComponent:@"crash_report_sender.app"]; -- reporterPathString = -- [[NSBundle bundleWithPath:reporterPathString] executablePath]; -- } -+// if (!reporterPathString) { -+// reporterPathString = -+// [resourcePath -+// stringByAppendingPathComponent:@"crash_report_sender.app"]; -+// reporterPathString = -+// [[NSBundle bundleWithPath:reporterPathString] executablePath]; -+// } - - // Verify that there is a Reporter application. -- if (![[NSFileManager defaultManager] -- fileExistsAtPath:reporterPathString]) { -- return false; -- } -+// if (![[NSFileManager defaultManager] -+// fileExistsAtPath:reporterPathString]) { -+// return false; -+// } - - if (!dumpSubdirectory) { - dumpSubdirectory = @""; -@@ -601,10 +601,10 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) { - dictionary.SetKeyValue(BREAKPAD_REPORT_INTERVAL, [interval UTF8String]); - dictionary.SetKeyValue(BREAKPAD_SKIP_CONFIRM, [skipConfirm UTF8String]); - dictionary.SetKeyValue(BREAKPAD_CONFIRM_TIMEOUT, [timeout UTF8String]); -- dictionary.SetKeyValue(BREAKPAD_INSPECTOR_LOCATION, -- [inspectorPathString fileSystemRepresentation]); -- dictionary.SetKeyValue(BREAKPAD_REPORTER_EXE_LOCATION, -- [reporterPathString fileSystemRepresentation]); -+// dictionary.SetKeyValue(BREAKPAD_INSPECTOR_LOCATION, -+// [inspectorPathString fileSystemRepresentation]); -+// dictionary.SetKeyValue(BREAKPAD_REPORTER_EXE_LOCATION, -+// [reporterPathString fileSystemRepresentation]); - dictionary.SetKeyValue(BREAKPAD_LOGFILE_UPLOAD_SIZE, - [logFileTailSize UTF8String]); - dictionary.SetKeyValue(BREAKPAD_REQUEST_COMMENTS, -@@ -762,9 +762,9 @@ bool Breakpad::HandleException(int exception_type, - bool Breakpad::HandleMinidump(const char *dump_dir, const char *minidump_id) { - google_breakpad::ConfigFile config_file; - config_file.WriteFile(dump_dir, config_params_, dump_dir, minidump_id); -- google_breakpad::LaunchReporter( -- config_params_->GetValueForKey(BREAKPAD_REPORTER_EXE_LOCATION), -- config_file.GetFilePath()); -+// google_breakpad::LaunchReporter( -+// config_params_->GetValueForKey(BREAKPAD_REPORTER_EXE_LOCATION), -+// config_file.GetFilePath()); - return true; - } - diff --git a/Telegram/Patches/build_ffmpeg_win.sh b/Telegram/Patches/build_ffmpeg_win.sh deleted file mode 100644 index 412034fef..000000000 --- a/Telegram/Patches/build_ffmpeg_win.sh +++ /dev/null @@ -1,18 +0,0 @@ -set -e -FullExecPath=$PWD -pushd `dirname $0` > /dev/null -FullScriptPath=`pwd` -popd > /dev/null - -pacman --noconfirm -Sy -pacman --noconfirm -S msys/make -pacman --noconfirm -S mingw64/mingw-w64-x86_64-opus -pacman --noconfirm -S diffutils -pacman --noconfirm -S pkg-config - -PKG_CONFIG_PATH="/mingw64/lib/pkgconfig:$PKG_CONFIG_PATH" - -./configure --toolchain=msvc --disable-programs --disable-doc --disable-everything --enable-protocol=file --enable-libopus --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=aasc --enable-decoder=flac --enable-decoder=gif --enable-decoder=h264 --enable-decoder=mp1 --enable-decoder=mp1float --enable-decoder=mp2 --enable-decoder=mp2float --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mp3adufloat --enable-decoder=mp3float --enable-decoder=mp3on4 --enable-decoder=mp3on4float --enable-decoder=mpeg4 --enable-decoder=msmpeg4v2 --enable-decoder=msmpeg4v3 --enable-decoder=wavpack --enable-decoder=opus --enable-decoder=pcm_alaw --enable-decoder=pcm_alaw_at --enable-decoder=pcm_f32be --enable-decoder=pcm_f32le --enable-decoder=pcm_f64be --enable-decoder=pcm_f64le --enable-decoder=pcm_lxf --enable-decoder=pcm_mulaw --enable-decoder=pcm_mulaw_at --enable-decoder=pcm_s16be --enable-decoder=pcm_s16be_planar --enable-decoder=pcm_s16le --enable-decoder=pcm_s16le_planar --enable-decoder=pcm_s24be --enable-decoder=pcm_s24daud --enable-decoder=pcm_s24le --enable-decoder=pcm_s24le_planar --enable-decoder=pcm_s32be --enable-decoder=pcm_s32le --enable-decoder=pcm_s32le_planar --enable-decoder=pcm_s64be --enable-decoder=pcm_s64le --enable-decoder=pcm_s8 --enable-decoder=pcm_s8_planar --enable-decoder=pcm_u16be --enable-decoder=pcm_u16le --enable-decoder=pcm_u24be --enable-decoder=pcm_u24le --enable-decoder=pcm_u32be --enable-decoder=pcm_u32le --enable-decoder=pcm_u8 --enable-decoder=pcm_zork --enable-decoder=vorbis --enable-decoder=wmalossless --enable-decoder=wmapro --enable-decoder=wmav1 --enable-decoder=wmav2 --enable-decoder=wmavoice --enable-encoder=libopus --enable-hwaccel=h264_d3d11va --enable-hwaccel=h264_dxva2 --enable-parser=aac --enable-parser=aac_latm --enable-parser=flac --enable-parser=h264 --enable-parser=mpeg4video --enable-parser=mpegaudio --enable-parser=opus --enable-parser=vorbis --enable-demuxer=aac --enable-demuxer=flac --enable-demuxer=gif --enable-demuxer=h264 --enable-demuxer=mov --enable-demuxer=mp3 --enable-demuxer=ogg --enable-demuxer=wav --enable-muxer=ogg --enable-muxer=opus --extra-ldflags="-libpath:$FullExecPath/../opus/win32/VS2015/Win32/Release" - -make -j4 -make -j4 install diff --git a/Telegram/Patches/gyp.diff b/Telegram/Patches/gyp.diff deleted file mode 100644 index e0b55c1c5..000000000 --- a/Telegram/Patches/gyp.diff +++ /dev/null @@ -1,80 +0,0 @@ -diff --git a/pylib/gyp/generator/cmake.py b/pylib/gyp/generator/cmake.py -index a2b9629..68d7020 100644 ---- a/pylib/gyp/generator/cmake.py -+++ b/pylib/gyp/generator/cmake.py -@@ -1070,6 +1070,23 @@ def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use, - - output.write(')\n') - -+ # Precompile header -+ precompiled_header = config.get('cmake_precompiled_header', '') -+ if precompiled_header: -+ precompiled_header_script = config.get('cmake_precompiled_header_script', '') -+ if not precompiled_header_script: -+ print ('ERROR: cmake_precompiled_header requires cmake_precompiled_header_script') -+ cmake_precompiled_header = NormjoinPath(path_from_cmakelists_to_gyp, precompiled_header) -+ cmake_precompiled_header_script = NormjoinPathForceCMakeSource(path_from_cmakelists_to_gyp, precompiled_header_script) -+ output.write('include(') -+ output.write(cmake_precompiled_header_script) -+ output.write(')\n') -+ output.write('add_precompiled_header(') -+ output.write(cmake_target_name) -+ output.write(' ') -+ output.write(cmake_precompiled_header) -+ output.write(')\n') -+ - UnsetVariable(output, 'TOOLSET') - UnsetVariable(output, 'TARGET') - -diff --git a/pylib/gyp/generator/xcode.py b/pylib/gyp/generator/xcode.py -index db99d6a..8d56baf 100644 ---- a/pylib/gyp/generator/xcode.py -+++ b/pylib/gyp/generator/xcode.py -@@ -72,6 +72,10 @@ generator_additional_non_configuration_keys = [ - 'ios_app_extension', - 'ios_watch_app', - 'ios_watchkit_extension', -+ -+ 'mac_sandbox', # sandbox support -+ 'mac_sandbox_development_team', -+ - 'mac_bundle', - 'mac_bundle_resources', - 'mac_framework_headers', -@@ -772,6 +776,26 @@ def GenerateOutput(target_list, target_dicts, data, params): - xcode_targets[qualified_target] = xct - xcode_target_to_target_dict[xct] = spec - -+ # sandbox support -+ is_sandbox = int(spec.get('mac_sandbox', 0)) -+ if is_sandbox: -+ dev_team = spec.get('mac_sandbox_development_team', '%%ERROR%%') -+ assert dev_team != '%%ERROR%%', ( -+ 'mac_sandbox must be accompanied by mac_sandbox_development_team (target "%s")' % -+ target_name) -+ try: -+ tmp = pbxp._properties['attributes']['TargetAttributes'] -+ except KeyError: -+ pbxp._properties['attributes']['TargetAttributes'] = {} -+ pbxp._properties['attributes']['TargetAttributes'][xct] = { -+ 'DevelopmentTeam': dev_team, -+ 'SystemCapabilities': { -+ 'com.apple.Sandbox': { -+ 'enabled': 1, -+ }, -+ }, -+ } -+ - spec_actions = spec.get('actions', []) - spec_rules = spec.get('rules', []) - -@@ -1141,7 +1165,8 @@ exit 1 - groups = [x for x in groups if not x.endswith('_excluded')] - for group in groups: - for item in rule.get(group, []): -- pbxp.AddOrGetFileInRootGroup(item) -+ concrete_item = ExpandXcodeVariables(item, rule_input_dict) -+ pbxp.AddOrGetFileInRootGroup(concrete_item) - - # Add "sources". - for source in spec.get('sources', []): diff --git a/Telegram/Patches/macold/crashpad.diff b/Telegram/Patches/macold/crashpad.diff deleted file mode 100644 index 7aa23102b..000000000 --- a/Telegram/Patches/macold/crashpad.diff +++ /dev/null @@ -1,20 +0,0 @@ -diff --git a/build/crashpad.gypi b/build/crashpad.gypi -index 027c7b6..4bfdfb5 100644 ---- a/build/crashpad.gypi -+++ b/build/crashpad.gypi -@@ -25,5 +25,15 @@ - 4201, # nonstandard extension used : nameless struct/union. - 4324, # structure was padded due to __declspec(align()). - ], -+ 'xcode_settings': { -+ 'OTHER_CPLUSPLUSFLAGS': [ '-nostdinc++' ], -+ 'OTHER_LDFLAGS': [ -+ '/usr/local/macold/lib/libc++.a', -+ '/usr/local/macold/lib/libc++abi.a', -+ ], -+ }, -+ 'include_dirs': [ -+ '/usr/local/macold/include/c++/v1', -+ ], - }, - } diff --git a/Telegram/Patches/macold/mini_chromium.diff b/Telegram/Patches/macold/mini_chromium.diff deleted file mode 100644 index 50aa1dc3e..000000000 --- a/Telegram/Patches/macold/mini_chromium.diff +++ /dev/null @@ -1,26 +0,0 @@ -diff --git a/build/common.gypi b/build/common.gypi -index 1affc70..c0d2f6a 100644 ---- a/build/common.gypi -+++ b/build/common.gypi -@@ -66,6 +66,11 @@ - 'conditions': [ - ['clang!=0', { - 'CLANG_CXX_LANGUAGE_STANDARD': 'c++11', # -std=c++11 -+ 'OTHER_CPLUSPLUSFLAGS': [ '-nostdinc++' ], -+ 'OTHER_LDFLAGS': [ -+ '/usr/local/macold/lib/libc++.a', -+ '/usr/local/macold/lib/libc++abi.a', -+ ], - - # Don't link in libarclite_macosx.a, see http://crbug.com/156530. - 'CLANG_LINK_OBJC_RUNTIME': 'NO', # -fno-objc-link-runtime -@@ -116,6 +121,9 @@ - ], - - }, -+ 'include_dirs': [ -+ '/usr/local/macold/include/c++/v1', -+ ], - }], - - ['OS=="linux"', { diff --git a/Telegram/Patches/macold/qtbase_5_3_2.diff b/Telegram/Patches/macold/qtbase_5_3_2.diff deleted file mode 100644 index 552623148..000000000 --- a/Telegram/Patches/macold/qtbase_5_3_2.diff +++ /dev/null @@ -1,784 +0,0 @@ -diff --git a/configure b/configure -index cb8d78f..cadb3f0 100755 ---- a/configure -+++ b/configure -@@ -511,7 +511,8 @@ if [ "$BUILD_ON_MAC" = "yes" ]; then - exit 2 - fi - -- if ! /usr/bin/xcrun -find xcrun >/dev/null 2>&1; then -+ # Patch: Fix Qt for working with Xcode 8. -+ if ! /usr/bin/xcrun -find xcodebuild >/dev/null 2>&1; then - echo >&2 - echo " Xcode not set up properly. You may need to confirm the license" >&2 - echo " agreement by running /usr/bin/xcodebuild without arguments." >&2 -diff --git a/mkspecs/common/g++-macx.conf b/mkspecs/common/g++-macx.conf -index 086510d..c485967 100644 ---- a/mkspecs/common/g++-macx.conf -+++ b/mkspecs/common/g++-macx.conf -@@ -14,7 +14,13 @@ QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -gdwarf-2 - QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO += -gdwarf-2 - QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO += -g -gdwarf-2 - --QMAKE_LFLAGS_STATIC_LIB += -all_load -+# Patch: Don't remember :( -+#QMAKE_LFLAGS_STATIC_LIB += -all_load -+ -+# Patch: Use C++14 with custom libc++ build. -+QMAKE_CXXFLAGS_CXX11 = -std=c++1y -+QMAKE_CXXFLAGS += -nostdinc++ -I/usr/local/macold/include/c++/v1 -+QMAKE_LFLAGS += /usr/local/macold/lib/libc++.a /usr/local/macold/lib/libc++abi.a - - QMAKE_XCODE_GCC_VERSION = com.apple.compilers.llvmgcc42 - -diff --git a/mkspecs/features/mac/default_pre.prf b/mkspecs/features/mac/default_pre.prf -index 0cc8cd6..ca9725b 100644 ---- a/mkspecs/features/mac/default_pre.prf -+++ b/mkspecs/features/mac/default_pre.prf -@@ -12,7 +12,9 @@ isEmpty(QMAKE_XCODE_DEVELOPER_PATH) { - error("Xcode is not installed in $${QMAKE_XCODE_DEVELOPER_PATH}. Please use xcode-select to choose Xcode installation path.") - - # Make sure Xcode is set up properly -- isEmpty($$list($$system("/usr/bin/xcrun -find xcrun 2>/dev/null"))): \ -+ -+ # Patch: Fix Qt for working with Xcode 8. -+ isEmpty($$list($$system("/usr/bin/xcrun -find xcodebuild 2>/dev/null"))): \ - error("Xcode not set up properly. You may need to confirm the license agreement by running /usr/bin/xcodebuild.") - } - -diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp -index bb79a13..5d595bc 100644 ---- a/src/gui/image/qbmphandler.cpp -+++ b/src/gui/image/qbmphandler.cpp -@@ -220,6 +220,10 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int - int blue_scale = 0; - int alpha_scale = 0; - -+ // Patch: Backport a fix for bmp reader. -+ if (!d->isSequential()) -+ d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap -+ - if (bi.biSize >= BMP_WIN4 || (comp == BMP_BITFIELDS && (nbits == 16 || nbits == 32))) { - if (d->read((char *)&red_mask, sizeof(red_mask)) != sizeof(red_mask)) - return false; -@@ -307,8 +311,9 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int - image.setDotsPerMeterX(bi.biXPelsPerMeter); - image.setDotsPerMeterY(bi.biYPelsPerMeter); - -- if (!d->isSequential()) -- d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap -+ // Patch: Backport a fix for bmp reader. -+ //if (!d->isSequential()) -+ // d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap - - if (ncols > 0) { // read color table - uchar rgb[4]; -diff --git a/src/gui/painting/qpaintengine_p.h b/src/gui/painting/qpaintengine_p.h -index ebff950..4300ca4 100644 ---- a/src/gui/painting/qpaintengine_p.h -+++ b/src/gui/painting/qpaintengine_p.h -@@ -87,8 +87,18 @@ public: - if (hasSystemTransform) { - if (systemTransform.type() <= QTransform::TxTranslate) - systemClip.translate(qRound(systemTransform.dx()), qRound(systemTransform.dy())); -- else -+ // Patch: 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. -+ else { -+#ifdef Q_OS_MAC -+ QTransform scaleTransform; -+ const qreal invDevicePixelRatio = 1. / pdev->devicePixelRatio(); -+ scaleTransform.scale(invDevicePixelRatio, invDevicePixelRatio); -+ systemClip = systemTransform.map(scaleTransform.map(systemClip)); -+#else - systemClip = systemTransform.map(systemClip); -+#endif -+ } - } - - // Make sure we're inside the viewport. -diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp -index 4879ae5..56cdcba 100644 ---- a/src/gui/text/qtextlayout.cpp -+++ b/src/gui/text/qtextlayout.cpp -@@ -654,6 +654,9 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const - while (oldPos < len && !attributes[oldPos].graphemeBoundary) - oldPos++; - } else { -+ // Patch: Skip to the end of the current word, not to the start of the next one. -+ while (oldPos < len && attributes[oldPos].whiteSpace) -+ oldPos++; - if (oldPos < len && d->atWordSeparator(oldPos)) { - oldPos++; - while (oldPos < len && d->atWordSeparator(oldPos)) -@@ -662,8 +665,9 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const - while (oldPos < len && !d->atSpace(oldPos) && !d->atWordSeparator(oldPos)) - oldPos++; - } -- while (oldPos < len && d->atSpace(oldPos)) -- oldPos++; -+ // Patch: Skip to the end of the current word, not to the start of the next one. -+ //while (oldPos < len && d->atSpace(oldPos)) -+ // oldPos++; - } - - return oldPos; -@@ -1602,6 +1606,9 @@ namespace { - int currentPosition; - glyph_t previousGlyph; - -+ // Patch: Backport a crash fix. -+ QFontEngine *previousGlyphFontEngine; -+ - QFixed minw; - QFixed softHyphenWidth; - QFixed rightBearing; -@@ -1634,13 +1641,19 @@ namespace { - if (currentPosition > 0 && - logClusters[currentPosition - 1] < glyphs.numGlyphs) { - previousGlyph = currentGlyph(); // needed to calculate right bearing later -+ -+ // Patch: Backport a crash fix. -+ previousGlyphFontEngine = fontEngine; - } - } - -- inline void adjustRightBearing(glyph_t glyph) -+ // Patch: Backport a crash fix. -+ inline void adjustRightBearing(QFontEngine *engine, glyph_t glyph) - { - qreal rb; -- fontEngine->getGlyphBearings(glyph, 0, &rb); -+ -+ // Patch: Backport a crash fix. -+ engine->getGlyphBearings(glyph, 0, &rb); - rightBearing = qMin(QFixed(), QFixed::fromReal(rb)); - } - -@@ -1648,13 +1661,16 @@ namespace { - { - if (currentPosition <= 0) - return; -- adjustRightBearing(currentGlyph()); -+ -+ // Patch: Backport a crash fix. -+ adjustRightBearing(fontEngine, currentGlyph()); - } - - inline void adjustPreviousRightBearing() - { - if (previousGlyph > 0) -- adjustRightBearing(previousGlyph); -+ // Patch: Backport a crash fix. -+ adjustRightBearing(previousGlyphFontEngine, previousGlyph); - } - - inline void resetRightBearing() -diff --git a/src/gui/text/qtextlayout.h b/src/gui/text/qtextlayout.h -index cbe42c3..b273db7 100644 ---- a/src/gui/text/qtextlayout.h -+++ b/src/gui/text/qtextlayout.h -@@ -194,6 +194,9 @@ private: - QRectF *brect, int tabstops, int* tabarray, int tabarraylen, - QPainter *painter); - QTextEngine *d; -+ -+ // Patch: Give access to the internal api. -+ friend class TextBlock; - }; - - -diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm -index ca7afb7..25ae500 100644 ---- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm -+++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm -@@ -256,6 +256,13 @@ static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd) - - fd->foundryName = QStringLiteral("CoreText"); - fd->familyName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute); -+ -+ // Patch: Fix open sans semibold loading. -+ QCFString _displayName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontDisplayNameAttribute); -+ if (_displayName == QStringLiteral("Open Sans Semibold")) { -+ fd->familyName = _displayName; -+ } -+ - fd->styleName = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontStyleNameAttribute); - fd->weight = QFont::Normal; - fd->style = QFont::StyleNormal; -diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm -index 92358ec..694fee7 100644 ---- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm -+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm -@@ -213,7 +213,8 @@ static void cleanupCocoaApplicationDelegate() - if (reflectionDelegate) { - if ([reflectionDelegate respondsToSelector:@selector(applicationShouldTerminate:)]) - return [reflectionDelegate applicationShouldTerminate:sender]; -- return NSTerminateNow; -+ // Patch: Don't terminate if reflectionDelegate does not respond to that selector, just use the default. -+ //return NSTerminateNow; - } - - if ([self canQuit]) { -@@ -289,6 +290,11 @@ static void cleanupCocoaApplicationDelegate() - - - (void)applicationDidFinishLaunching:(NSNotification *)aNotification - { -+ // Patch: We need to receive this notification in the delegate as well. -+ if (reflectionDelegate -+ && [reflectionDelegate respondsToSelector:@selector(applicationDidFinishLaunching:)]) -+ [reflectionDelegate applicationDidFinishLaunching:aNotification]; -+ - Q_UNUSED(aNotification); - inLaunch = false; - // qt_release_apple_event_handler(); -@@ -411,7 +417,9 @@ static void cleanupCocoaApplicationDelegate() - { - Q_UNUSED(replyEvent); - NSString *urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue]; -- QWindowSystemInterface::handleFileOpenEvent(QUrl(QCFString::toQString(urlString))); -+ -+ // Patch: Fix opening of an external url by a protocol handler. -+ QWindowSystemInterface::handleFileOpenEvent(QUrl::fromNSURL([NSURL URLWithString:urlString])); - } - - - (void)appleEventQuit:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent -diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm -index b81b9a0..4e59e83 100644 ---- a/src/plugins/platforms/cocoa/qcocoacursor.mm -+++ b/src/plugins/platforms/cocoa/qcocoacursor.mm -@@ -81,7 +81,7 @@ void QCocoaCursor::setPos(const QPoint &position) - pos.x = position.x(); - pos.y = position.y(); - -- CGEventRef e = CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, 0); -+ CGEventRef e = CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, kCGMouseButtonLeft); - CGEventPost(kCGHIDEventTap, e); - CFRelease(e); - } -diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm -index 9fd05a6..dea6072 100644 ---- a/src/plugins/platforms/cocoa/qcocoaintegration.mm -+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm -@@ -402,14 +402,24 @@ void QCocoaIntegration::updateScreens() - } - siblings << screen; - } -+ -+ // Patch: Backport crash fix from Qt 5.6.1. -+ // Set virtual siblings list. All screens in mScreens are siblings, because we ignored the -+ // mirrors. Note that some of the screens we update the siblings list for here may be deleted -+ // below, but update anyway to keep the to-be-deleted screens out of the siblings list. -+ foreach (QCocoaScreen* screen, mScreens) -+ screen->setVirtualSiblings(siblings); -+ - // Now the leftovers in remainingScreens are no longer current, so we can delete them. - foreach (QCocoaScreen* screen, remainingScreens) { - mScreens.removeOne(screen); - delete screen; - } -+ -+ // Patch: Backport crash fix from Qt 5.6.1. - // All screens in mScreens are siblings, because we ignored the mirrors. -- foreach (QCocoaScreen* screen, mScreens) -- screen->setVirtualSiblings(siblings); -+ //foreach (QCocoaScreen* screen, mScreens) -+ // screen->setVirtualSiblings(siblings); - } - - QCocoaScreen *QCocoaIntegration::screenAtIndex(int index) -diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.mm b/src/plugins/platforms/cocoa/qcocoakeymapper.mm -index e46eaff..c62db53 100644 ---- a/src/plugins/platforms/cocoa/qcocoakeymapper.mm -+++ b/src/plugins/platforms/cocoa/qcocoakeymapper.mm -@@ -382,6 +382,12 @@ bool QCocoaKeyMapper::updateKeyboard() - keyboardInputLocale = QLocale::c(); - keyboardInputDirection = Qt::LeftToRight; - } -+ -+ // Patch: Backport a fix for layout-independent keyboard shortcuts. -+ const auto newMode = keyboard_mode; -+ deleteLayouts(); -+ keyboard_mode = newMode; -+ - return true; - } - -@@ -464,7 +470,8 @@ QList QCocoaKeyMapper::possibleKeys(const QKeyEvent *event) const - Qt::KeyboardModifiers neededMods = ModsTbl[i]; - int key = kbItem->qtKey[i]; - if (key && key != baseKey && ((keyMods & neededMods) == neededMods)) { -- ret << int(key + (keyMods & ~neededMods)); -+ // Patch: Backport a fix for layout-independent keyboard shortcuts. -+ ret << int(key + neededMods); - } - } - return ret; -diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm -index 83c960d..03ae969 100755 ---- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm -+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm -@@ -102,7 +102,10 @@ QT_USE_NAMESPACE - QCocoaSystemTrayIcon *systray; - NSStatusItem *item; - QCocoaMenu *menu; -- bool menuVisible; -+ -+ // Patch: Nice macOS tray icon support. -+ bool menuVisible, iconSelected; -+ - QIcon icon; - QT_MANGLE_NAMESPACE(QNSImageView) *imageCell; - } -@@ -124,6 +127,10 @@ QT_USE_NAMESPACE - QT_MANGLE_NAMESPACE(QNSStatusItem) *parent; - } - -(id)initWithParent:(QT_MANGLE_NAMESPACE(QNSStatusItem)*)myParent; -+ -+// Patch: Nice macOS tray icon support. -+-(void)updateIconSelection; -+ - -(void)menuTrackingDone:(NSNotification*)notification; - -(void)mousePressed:(NSEvent *)mouseEvent button:(Qt::MouseButton)mouseButton; - @end -@@ -187,6 +194,19 @@ void QCocoaSystemTrayIcon::cleanup() - m_sys = 0; - } - -+// Patch: Nice macOS tray icon support. -+namespace { -+ -+qreal getDevicePixelRatio() { -+ qreal result = 1.0; -+ foreach (QScreen *screen, QGuiApplication::screens()) { -+ result = qMax(result, screen->devicePixelRatio()); -+ } -+ return result; -+} -+ -+} // namespace -+ - void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon) - { - if (!m_sys) -@@ -194,13 +214,18 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon) - - m_sys->item->icon = icon; - -- const bool menuVisible = m_sys->item->menu && m_sys->item->menuVisible; -+ // Patch: Nice macOS tray icon support. -+ //const bool menuVisible = m_sys->item->menu && m_sys->item->menuVisible; - -- CGFloat hgt = [[[NSApplication sharedApplication] mainMenu] menuBarHeight]; -- const short scale = hgt - 4; -+ const int padding = 0; -+ const int menuHeight = [[NSStatusBar systemStatusBar] thickness]; -+ const int maxImageHeight = menuHeight - padding; -+ -+ const short scale = maxImageHeight * getDevicePixelRatio(); - - QPixmap pm = m_sys->item->icon.pixmap(QSize(scale, scale), -- menuVisible ? QIcon::Selected : QIcon::Normal); -+ // Patch: Nice macOS tray icon support. -+ m_sys->item->iconSelected ? QIcon::Selected : QIcon::Normal); - if (pm.isNull()) { - pm = QPixmap(scale, scale); - pm.fill(Qt::transparent); -@@ -322,15 +347,16 @@ QT_END_NAMESPACE - return self; - } - ---(void)menuTrackingDone:(NSNotification*)notification -+// Patch: Nice macOS tray icon support. -+-(void)updateIconSelection - { -- Q_UNUSED(notification); -- down = NO; -+ const int padding = 0; -+ const int menuHeight = [[NSStatusBar systemStatusBar] thickness]; -+ const int maxImageHeight = menuHeight - padding; - -- CGFloat hgt = [[[NSApplication sharedApplication] mainMenu] menuBarHeight]; -- const short scale = hgt - 4; -- -- QPixmap pm = parent->icon.pixmap(QSize(scale, scale), QIcon::Normal); -+ const short scale = maxImageHeight * getDevicePixelRatio(); -+ QPixmap pm = parent->icon.pixmap(QSize(scale, scale), -+ parent->iconSelected ? QIcon::Selected : QIcon::Normal); - if (pm.isNull()) { - pm = QPixmap(scale, scale); - pm.fill(Qt::transparent); -@@ -338,9 +364,19 @@ QT_END_NAMESPACE - NSImage *nsaltimage = static_cast(qt_mac_create_nsimage(pm)); - [self setImage: nsaltimage]; - [nsaltimage release]; -+} -+ -+-(void)menuTrackingDone:(NSNotification*)notification -+{ -+ Q_UNUSED(notification); -+ down = NO; - - parent->menuVisible = false; - -+ // Patch: Nice macOS tray icon support. -+ parent->iconSelected = false; -+ [self updateIconSelection]; -+ - [self setNeedsDisplay:YES]; - } - -@@ -350,18 +386,9 @@ QT_END_NAMESPACE - int clickCount = [mouseEvent clickCount]; - [self setNeedsDisplay:YES]; - -- CGFloat hgt = [[[NSApplication sharedApplication] mainMenu] menuBarHeight]; -- const short scale = hgt - 4; -- -- QPixmap pm = parent->icon.pixmap(QSize(scale, scale), -- parent->menuVisible ? QIcon::Selected : QIcon::Normal); -- if (pm.isNull()) { -- pm = QPixmap(scale, scale); -- pm.fill(Qt::transparent); -- } -- NSImage *nsaltimage = static_cast(qt_mac_create_nsimage(pm)); -- [self setImage: nsaltimage]; -- [nsaltimage release]; -+ // Patch: Nice macOS tray icon support. -+ parent->iconSelected = (clickCount != 2) && parent->menu; -+ [self updateIconSelection]; - - if (clickCount == 2) { - [self menuTrackingDone:nil]; -@@ -380,6 +407,10 @@ QT_END_NAMESPACE - { - Q_UNUSED(mouseEvent); - [self menuTrackingDone:nil]; -+ -+ // Patch: Nice macOS tray icon support. -+ parent->iconSelected = false; -+ [self updateIconSelection]; - } - - - (void)rightMouseDown:(NSEvent *)mouseEvent -@@ -391,6 +422,10 @@ QT_END_NAMESPACE - { - Q_UNUSED(mouseEvent); - [self menuTrackingDone:nil]; -+ -+ // Patch: Nice macOS tray icon support. -+ parent->iconSelected = false; -+ [self updateIconSelection]; - } - - - (void)otherMouseDown:(NSEvent *)mouseEvent -@@ -405,7 +440,8 @@ QT_END_NAMESPACE - } - - -(void)drawRect:(NSRect)rect { -- [[parent item] drawStatusBarBackgroundInRect:rect withHighlight:down]; -+ // Patch: Nice macOS tray icon support. -+ [[parent item] drawStatusBarBackgroundInRect:rect withHighlight:parent->menu ? down : NO]; - [super drawRect:rect]; - } - @end -diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm -index 4d0458a..3357a5e 100644 ---- a/src/plugins/platforms/cocoa/qcocoawindow.mm -+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm -@@ -167,7 +167,8 @@ static bool isMouseEvent(NSEvent *ev) - if (!self.window.delegate) - return; // Already detached, pending NSAppKitDefined event - -- if (pw && pw->frameStrutEventsEnabled() && isMouseEvent(theEvent)) { -+ // Patch: Fix events loss if the window was minimized or hidden. -+ if (pw && pw->frameStrutEventsEnabled() && pw->m_synchedWindowState != Qt::WindowMinimized && pw->m_isExposed && isMouseEvent(theEvent)) { - NSPoint loc = [theEvent locationInWindow]; - NSRect windowFrame = [self.window legacyConvertRectFromScreen:[self.window frame]]; - NSRect contentFrame = [[self.window contentView] frame]; -@@ -795,6 +796,16 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags) - { - Qt::WindowType type = static_cast(int(flags & Qt::WindowType_Mask)); - NSInteger styleMask = NSBorderlessWindowMask; -+ -+ // Patch: allow creating panels floating on all spaces in macOS. -+ // If you call "setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary" before -+ // setting the "NSNonactivatingPanelMask" bit in the style mask it won't work after that. -+ // So we need a way to set that bit before Qt sets collection behavior the way it does. -+ QVariant nonactivatingPanelMask = window()->property("_td_macNonactivatingPanelMask"); -+ if (nonactivatingPanelMask.isValid() && nonactivatingPanelMask.toBool()) { -+ styleMask |= NSNonactivatingPanelMask; -+ } -+ - if (flags & Qt::FramelessWindowHint) - return styleMask; - if ((type & Qt::Popup) == Qt::Popup) { -@@ -914,6 +925,19 @@ void QCocoaWindow::setWindowFilePath(const QString &filePath) - [m_nsWindow setRepresentedFilename: fi.exists() ? QCFString::toNSString(filePath) : @""]; - } - -+// Patch: Nice macOS window icon. -+namespace { -+ -+qreal getDevicePixelRatio() { -+ qreal result = 1.0; -+ foreach (QScreen *screen, QGuiApplication::screens()) { -+ result = qMax(result, screen->devicePixelRatio()); -+ } -+ return result; -+} -+ -+} // namespace -+ - void QCocoaWindow::setWindowIcon(const QIcon &icon) - { - QCocoaAutoReleasePool pool; -@@ -929,7 +953,10 @@ void QCocoaWindow::setWindowIcon(const QIcon &icon) - if (icon.isNull()) { - [iconButton setImage:nil]; - } else { -- QPixmap pixmap = icon.pixmap(QSize(22, 22)); -+ // Patch: Nice macOS window icon. -+ CGFloat hgt = 16. * getDevicePixelRatio(); -+ QPixmap pixmap = icon.pixmap(QSize(hgt, hgt)); -+ - NSImage *image = static_cast(qt_mac_create_nsimage(pixmap)); - [iconButton setImage:image]; - [image release]; -diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm -index a18ee7f..1f91feb 100644 ---- a/src/plugins/platforms/cocoa/qnsview.mm -+++ b/src/plugins/platforms/cocoa/qnsview.mm -@@ -393,7 +393,9 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; - [self notifyWindowStateChanged:newState]; - // NSWindowDidOrderOnScreenAndFinishAnimatingNotification is private API, and not - // emitted in 10.6, so we bring back the old behavior for that case alone. -- if (newState == Qt::WindowNoState && QSysInfo::QSysInfo::MacintoshVersion == QSysInfo::MV_10_6) -+ -+ // Patch: Fix macOS window show after window was hidden. -+ if (newState == Qt::WindowNoState/* && QSysInfo::QSysInfo::MacintoshVersion == QSysInfo::MV_10_6*/) - m_platformWindow->exposeWindow(); - } else if ([notificationName isEqualToString: @"NSWindowDidOrderOffScreenNotification"]) { - m_platformWindow->obscureWindow(); -@@ -1300,7 +1302,9 @@ 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) -+ -+ // Patch: Actual begin should be treated as begin as well. -+ if (phase == NSEventPhaseMayBegin || phase == NSEventPhaseBegan) - ph = Qt::ScrollBegin; - } else - #endif -@@ -1366,14 +1370,22 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) - quint32 nativeVirtualKey = [nsevent keyCode]; - - QChar ch = QChar::ReplacementCharacter; -- int keyCode = Qt::Key_unknown; -- if ([characters length] != 0) { -- if (((modifiers & Qt::MetaModifier) || (modifiers & Qt::AltModifier)) && ([charactersIgnoringModifiers length] != 0)) -- ch = QChar([charactersIgnoringModifiers characterAtIndex:0]); -- else -- ch = QChar([characters characterAtIndex:0]); -- keyCode = [self convertKeyCode:ch]; -- } -+ -+ // Patch: Backport a fix for layout-independent shortcuts. -+ if ([characters length] != 0) // https://bugreports.qt.io/browse/QTBUG-42584 -+ ch = QChar([characters characterAtIndex:0]); -+ else if ([charactersIgnoringModifiers length] != 0 && ((modifiers & Qt::MetaModifier) || (modifiers & Qt::AltModifier))) -+ ch = QChar([charactersIgnoringModifiers characterAtIndex:0]); -+ -+ int keyCode = [self convertKeyCode:ch]; -+ //int keyCode = Qt::Key_unknown; -+ //if ([characters length] != 0) { -+ // if (((modifiers & Qt::MetaModifier) || (modifiers & Qt::AltModifier)) && ([charactersIgnoringModifiers length] != 0)) -+ // ch = QChar([charactersIgnoringModifiers characterAtIndex:0]); -+ // else -+ // ch = QChar([characters characterAtIndex:0]); -+ // keyCode = [self convertKeyCode:ch]; -+ //} - - // we will send a key event unless the input method sets m_sendKeyEvent to false - m_sendKeyEvent = true; -@@ -1437,6 +1449,11 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) - && qtKey == Qt::Key_Period) { - [self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)]; - return YES; -+ -+ // Patch: Allow us to handle Ctrl+Tab and Ctrl+Backtab in the app. -+ } 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/src/tools/qlalr/lalr.cpp b/src/tools/qlalr/lalr.cpp -index c680764..e2a7aaf 100644 ---- a/src/tools/qlalr/lalr.cpp -+++ b/src/tools/qlalr/lalr.cpp -@@ -246,11 +246,13 @@ void Grammar::buildExtendedGrammar () - non_terminals.insert (accept_symbol); - } - --struct _Nullable: public std::unary_function -+// Patch: Fix building with the new SDK. -+struct __Nullable: public std::unary_function - { - Automaton *_M_automaton; - -- _Nullable (Automaton *aut): -+ // Patch: Fix building with the new SDK. -+ __Nullable (Automaton *aut): - _M_automaton (aut) {} - - bool operator () (Name name) const -@@ -308,7 +310,8 @@ void Automaton::buildNullables () - - for (RulePointer rule = _M_grammar->rules.begin (); rule != _M_grammar->rules.end (); ++rule) - { -- NameList::iterator nn = std::find_if (rule->rhs.begin (), rule->rhs.end (), std::not1 (_Nullable (this))); -+ // Patch: Fix building with the new SDK. -+ NameList::iterator nn = std::find_if (rule->rhs.begin (), rule->rhs.end (), std::not1 (__Nullable (this))); - - if (nn == rule->rhs.end ()) - changed |= nullables.insert (rule->lhs).second; -@@ -643,7 +646,8 @@ void Automaton::buildIncludesDigraph () - if (! _M_grammar->isNonTerminal (*A)) - continue; - -- NameList::iterator first_not_nullable = std::find_if (dot, rule->rhs.end (), std::not1 (_Nullable (this))); -+ // Patch: Fix building with the new SDK. -+ NameList::iterator first_not_nullable = std::find_if (dot, rule->rhs.end (), std::not1 (__Nullable (this))); - if (first_not_nullable != rule->rhs.end ()) - continue; - -diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp -index 7396808..7178aec 100644 ---- a/src/widgets/kernel/qwidget.cpp -+++ b/src/widgets/kernel/qwidget.cpp -@@ -4722,6 +4722,17 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset, - return; // Fully transparent. - - Q_D(QWidget); -+ -+ // Patch: save and restore dirtyOpaqueChildren field. -+ // -+ // Just like in QWidget::grab() this field should be restored -+ // after the d->render() call, because it will be set to 1 and -+ // opaqueChildren field will be filled with empty region in -+ // case the widget is hidden (because all the opaque children -+ // will be skipped in isVisible() check). -+ // -+ const bool oldDirtyOpaqueChildren = d->dirtyOpaqueChildren; -+ - const bool inRenderWithPainter = d->extra && d->extra->inRenderWithPainter; - const QRegion toBePainted = !inRenderWithPainter ? d->prepareToRender(sourceRegion, renderFlags) - : sourceRegion; -@@ -4743,6 +4754,10 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset, - if (!inRenderWithPainter && (opacity < 1.0 || (target->devType() == QInternal::Printer))) { - d->render_helper(painter, targetOffset, toBePainted, renderFlags); - d->extra->inRenderWithPainter = inRenderWithPainter; -+ -+ // Patch: save and restore dirtyOpaqueChildren field. -+ d->dirtyOpaqueChildren = oldDirtyOpaqueChildren; -+ - return; - } - -@@ -4774,6 +4789,9 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset, - d->setSharedPainter(oldPainter); - - d->extra->inRenderWithPainter = inRenderWithPainter; -+ -+ // Patch: save and restore dirtyOpaqueChildren field. -+ d->dirtyOpaqueChildren = oldDirtyOpaqueChildren; - } - - static void sendResizeEvents(QWidget *target) -@@ -7983,7 +8001,8 @@ bool QWidget::event(QEvent *event) - case QEvent::KeyPress: { - QKeyEvent *k = (QKeyEvent *)event; - bool res = false; -- if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) { //### Add MetaModifier? -+ // Patch: Allow us to handle Ctrl+Tab and Ctrl+Backtab in the app. -+ 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/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm -index 0845a5e..5735cb6 100644 ---- a/src/widgets/styles/qmacstyle_mac.mm -+++ b/src/widgets/styles/qmacstyle_mac.mm -@@ -3667,9 +3667,11 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter - - NSBezierPath *pushButtonFocusRingPath; - if (bdi.kind == kThemeBevelButton) -- pushButtonFocusRingPath = [NSBezierPath bezierPathWithRect:focusRect]; -+ // Patch: Fix building with the new SDK. -+ pushButtonFocusRingPath = [NSBezierPath bezierPathWithRect:NSRectFromCGRect(focusRect)]; - else -- pushButtonFocusRingPath = [NSBezierPath bezierPathWithRoundedRect:focusRect xRadius:4 yRadius:4]; -+ // Patch: Fix building with the new SDK. -+ pushButtonFocusRingPath = [NSBezierPath bezierPathWithRoundedRect:NSRectFromCGRect(focusRect) xRadius:4 yRadius:4]; - qt_drawFocusRingOnPath(cg, pushButtonFocusRingPath); - } - -diff --git a/src/widgets/util/qsystemtrayicon_qpa.cpp b/src/widgets/util/qsystemtrayicon_qpa.cpp -index f98aeaf..00c0734 100644 ---- a/src/widgets/util/qsystemtrayicon_qpa.cpp -+++ b/src/widgets/util/qsystemtrayicon_qpa.cpp -@@ -99,13 +99,18 @@ void QSystemTrayIconPrivate::updateIcon_sys() - - void QSystemTrayIconPrivate::updateMenu_sys() - { -- if (qpa_sys && menu) { -- if (!menu->platformMenu()) { -- QPlatformMenu *platformMenu = qpa_sys->createMenu(); -- if (platformMenu) -- menu->setPlatformMenu(platformMenu); -+ // Patch: Nice macOS tray icon support. -+ if (qpa_sys) { -+ if (menu) { -+ if (!menu->platformMenu()) { -+ QPlatformMenu *platformMenu = qpa_sys->createMenu(); -+ if (platformMenu) -+ menu->setPlatformMenu(platformMenu); -+ } -+ qpa_sys->updateMenu(menu->platformMenu()); -+ } else { -+ qpa_sys->updateMenu(0); - } -- qpa_sys->updateMenu(menu->platformMenu()); - } - } - -diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp -index 75f3059..980f2be 100644 ---- a/src/widgets/widgets/qwidgetlinecontrol.cpp -+++ b/src/widgets/widgets/qwidgetlinecontrol.cpp -@@ -1867,7 +1867,8 @@ void QWidgetLineControl::processKeyEvent(QKeyEvent* event) - - if (unknown && !isReadOnly()) { - QString t = event->text(); -- if (!t.isEmpty() && t.at(0).isPrint()) { -+ // Patch: Enable ZWJ and ZWNJ characters to be in text input. -+ 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/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp -index 96438a0..b0b7206 100644 ---- a/src/widgets/widgets/qwidgettextcontrol.cpp -+++ b/src/widgets/widgets/qwidgettextcontrol.cpp -@@ -1342,7 +1342,8 @@ void QWidgetTextControlPrivate::keyPressEvent(QKeyEvent *e) - process: - { - QString text = e->text(); -- if (!text.isEmpty() && (text.at(0).isPrint() || text.at(0) == QLatin1Char('\t'))) { -+ // Patch: Enable ZWJ and ZWNJ characters to be in text input. -+ 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/Telegram/Patches/macold/qtimageformats_5_3_2.diff b/Telegram/Patches/macold/qtimageformats_5_3_2.diff deleted file mode 100644 index b1f04103b..000000000 --- a/Telegram/Patches/macold/qtimageformats_5_3_2.diff +++ /dev/null @@ -1,47 +0,0 @@ -diff --git a/src/3rdparty/libwebp/src/dec/vp8l.c b/src/3rdparty/libwebp/src/dec/vp8l.c -index ea0254d..953ff01 100644 ---- a/src/3rdparty/libwebp/src/dec/vp8l.c -+++ b/src/3rdparty/libwebp/src/dec/vp8l.c -@@ -12,7 +12,7 @@ - // Authors: Vikas Arora (vikaas.arora@gmail.com) - // Jyrki Alakuijala (jyrki@google.com) - --#include -+// Patch: Backport of a crash fix. - #include - #include "./alphai.h" - #include "./vp8li.h" -@@ -740,6 +740,10 @@ 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); -+ -+ // Patch: Backport of a crash fix. -+ assert(pos < end); -+ - assert(last_row <= height); - assert(Is8bOptimizable(hdr)); - -@@ -830,6 +834,10 @@ 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); -+ -+ // Patch: Backport of a crash fix. -+ assert(src < src_end); -+ - assert(src_last <= src_end); - - while (!br->eos_ && src < src_last) { -@@ -1294,6 +1302,11 @@ int VP8LDecodeAlphaImageStream(ALPHDecoder* const alph_dec, int last_row) { - assert(dec->action_ == READ_DATA); - assert(last_row <= dec->height_); - -+ // Patch: Backport of a crash fix. -+ 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_, diff --git a/Telegram/Patches/mini_chromium.diff b/Telegram/Patches/mini_chromium.diff deleted file mode 100644 index 3dab62ec2..000000000 --- a/Telegram/Patches/mini_chromium.diff +++ /dev/null @@ -1,52 +0,0 @@ -diff --git a/base/mac/scoped_nsobject.h b/base/mac/scoped_nsobject.h -index 2e157a4..5a306a1 100644 ---- a/base/mac/scoped_nsobject.h -+++ b/base/mac/scoped_nsobject.h -@@ -11,6 +11,7 @@ - - #include "base/compiler_specific.h" - #include "base/mac/scoped_typeref.h" -+#include "base/template_util.h" - - namespace base { - -@@ -55,7 +56,7 @@ class scoped_nsobject : public scoped_nsprotocol { - public: - using scoped_nsprotocol::scoped_nsprotocol; - -- static_assert(std::is_same::value == false, -+ static_assert(is_same::value == false, - "Use ScopedNSAutoreleasePool instead"); - }; - -diff --git a/base/macros.h b/base/macros.h -index 5d96783..096704c 100644 ---- a/base/macros.h -+++ b/base/macros.h -@@ -42,8 +42,9 @@ char (&ArraySizeHelper(const T (&array)[N]))[N]; - - template - inline Dest bit_cast(const Source& source) { -+#if __cplusplus >= 201103L - static_assert(sizeof(Dest) == sizeof(Source), "sizes must be equal"); -- -+#endif - Dest dest; - memcpy(&dest, &source, sizeof(dest)); - return dest; -diff --git a/build/common.gypi b/build/common.gypi -index 1affc70..6e8f292 100644 ---- a/build/common.gypi -+++ b/build/common.gypi -@@ -66,6 +66,11 @@ - 'conditions': [ - ['clang!=0', { - 'CLANG_CXX_LANGUAGE_STANDARD': 'c++11', # -std=c++11 -+ 'conditions': [ -+ ['mac_deployment_target=="10.8"', { -+ 'CLANG_CXX_LIBRARY': 'libc++', # force -stdlib=libc++ for 10.8 -+ }] -+ ], - - # Don't link in libarclite_macosx.a, see http://crbug.com/156530. - 'CLANG_LINK_OBJC_RUNTIME': 'NO', # -fno-objc-link-runtime diff --git a/Telegram/Patches/openal.diff b/Telegram/Patches/openal.diff deleted file mode 100644 index b2a71ad17..000000000 --- a/Telegram/Patches/openal.diff +++ /dev/null @@ -1,22 +0,0 @@ -diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c -index 9d8f8e9..8c8e44a 100644 ---- a/Alc/backends/winmm.c -+++ b/Alc/backends/winmm.c -@@ -219,7 +219,7 @@ FORCE_ALIGN static int ALCwinmmPlayback_mixerProc(void *arg) - SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); - -- while(GetMessage(&msg, NULL, 0, 0)) -+ if (!self->killNow) while(GetMessage(&msg, NULL, 0, 0)) - { - if(msg.message != WOM_DONE) - continue; -@@ -504,7 +504,7 @@ static int ALCwinmmCapture_captureProc(void *arg) - - althrd_setname(althrd_current(), RECORD_THREAD_NAME); - -- while(GetMessage(&msg, NULL, 0, 0)) -+ if (!self->killNow) while(GetMessage(&msg, NULL, 0, 0)) - { - if(msg.message != WIM_DATA) - continue; diff --git a/Telegram/Patches/qtbase_5_6_2.diff b/Telegram/Patches/qtbase_5_6_2.diff deleted file mode 100644 index 85fddbd27..000000000 --- a/Telegram/Patches/qtbase_5_6_2.diff +++ /dev/null @@ -1,1451 +0,0 @@ -diff --git a/mkspecs/common/msvc-desktop.conf b/mkspecs/common/msvc-desktop.conf -index eec9e1f..7ae53c7 100644 ---- a/mkspecs/common/msvc-desktop.conf -+++ b/mkspecs/common/msvc-desktop.conf -@@ -30,9 +30,10 @@ QMAKE_YACCFLAGS = -d - QMAKE_CFLAGS = -nologo -Zc:wchar_t - QMAKE_CFLAGS_WARN_ON = -W3 - QMAKE_CFLAGS_WARN_OFF = -W0 --QMAKE_CFLAGS_RELEASE = -O2 -MD --QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -O2 -MD -Zi --QMAKE_CFLAGS_DEBUG = -Zi -MDd -+# Patch: Make this build use static runtime library. -+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_SSE2 = -arch:SSE2 -diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp -index 391fbcc..d07802b 100644 ---- a/src/corelib/io/qfsfileengine_win.cpp -+++ b/src/corelib/io/qfsfileengine_win.cpp -@@ -427,11 +427,12 @@ qint64 QFSFileEnginePrivate::nativeWrite(const char *data, qint64 len) - - // Writing on Windows fails with ERROR_NO_SYSTEM_RESOURCES when - // the chunks are too large, so we limit the block size to 32MB. -- const DWORD blockSize = DWORD(qMin(bytesToWrite, qint64(32 * 1024 * 1024))); - qint64 totalWritten = 0; - do { -+ // Patch: backport critical bugfix from '683c9bc4a8' commit. -+ const DWORD currentBlockSize = DWORD(qMin(bytesToWrite, qint64(32 * 1024 * 1024))); - DWORD bytesWritten; -- if (!WriteFile(fileHandle, data + totalWritten, blockSize, &bytesWritten, NULL)) { -+ if (!WriteFile(fileHandle, data + totalWritten, currentBlockSize, &bytesWritten, NULL)) { - if (totalWritten == 0) { - // Note: Only return error if the first WriteFile failed. - q->setError(QFile::WriteError, qt_error_string()); -diff --git a/src/corelib/tools/qunicodetables.cpp b/src/corelib/tools/qunicodetables.cpp -index 14e4fd1..0619a17 100644 ---- a/src/corelib/tools/qunicodetables.cpp -+++ b/src/corelib/tools/qunicodetables.cpp -@@ -6227,7 +6227,8 @@ 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 }, -- { 25, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 12, 17, 2 }, -+ // Patch: Some bad characters appeared in ui in case 2 was here instead of 11. -+ { 25, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 12, 17, 11 }, - { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 14, 9, 11, 11 }, - { 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/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp -index 2d00b9d..eeba86e 100644 ---- a/src/gui/kernel/qhighdpiscaling.cpp -+++ b/src/gui/kernel/qhighdpiscaling.cpp -@@ -51,6 +51,9 @@ static const char screenFactorsEnvVar[] = "QT_SCREEN_SCALE_FACTORS"; - - static inline qreal initialGlobalScaleFactor() - { -+ // Patch: Disable environment variable dpi scaling changing. -+ // It is not supported by Telegram Desktop :( -+ return 1.; - - qreal result = 1; - if (qEnvironmentVariableIsSet(scaleFactorEnvVar)) { -diff --git a/src/gui/kernel/qplatformdialoghelper.h b/src/gui/kernel/qplatformdialoghelper.h -index 5b2f4ec..790db46 100644 ---- a/src/gui/kernel/qplatformdialoghelper.h -+++ b/src/gui/kernel/qplatformdialoghelper.h -@@ -386,6 +386,10 @@ public: - virtual QUrl directory() const = 0; - virtual void selectFile(const QUrl &filename) = 0; - virtual QList selectedFiles() const = 0; -+ -+ // Patch: Adding select-by-url for Windows file dialog. -+ virtual QByteArray selectedRemoteContent() const { return QByteArray(); } -+ - virtual void setFilter() = 0; - virtual void selectNameFilter(const QString &filter) = 0; - virtual QString selectedNameFilter() const = 0; -diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp -index bcd29b6..bcb0672 100644 ---- a/src/gui/kernel/qwindow.cpp -+++ b/src/gui/kernel/qwindow.cpp -@@ -2525,7 +2525,8 @@ void QWindowPrivate::setCursor(const QCursor *newCursor) - void QWindowPrivate::applyCursor() - { - Q_Q(QWindow); -- if (platformWindow) { -+ // Patch: Fixing possible crash (crashdumps point on this code line). -+ if (platformWindow && q->screen() && q->screen()->handle()) { - if (QPlatformCursor *platformCursor = q->screen()->handle()->cursor()) { - QCursor *c = QGuiApplication::overrideCursor(); - if (!c && hasCursor) -diff --git a/src/gui/painting/qpaintengine_p.h b/src/gui/painting/qpaintengine_p.h -index 918c989..4158259 100644 ---- a/src/gui/painting/qpaintengine_p.h -+++ b/src/gui/painting/qpaintengine_p.h -@@ -80,8 +80,18 @@ public: - if (hasSystemTransform) { - if (systemTransform.type() <= QTransform::TxTranslate) - systemClip.translate(qRound(systemTransform.dx()), qRound(systemTransform.dy())); -- else -+ // Patch: 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. -+ else { -+#ifdef Q_OS_MAC -+ QTransform scaleTransform; -+ const qreal invDevicePixelRatio = 1. / pdev->devicePixelRatio(); -+ scaleTransform.scale(invDevicePixelRatio, invDevicePixelRatio); -+ systemClip = systemTransform.map(scaleTransform.map(systemClip)); -+#else - systemClip = systemTransform.map(systemClip); -+#endif -+ } - } - - // Make sure we're inside the viewport. -diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h -index 7e507bb..936e7a9 100644 ---- a/src/gui/text/qtextengine_p.h -+++ b/src/gui/text/qtextengine_p.h -@@ -283,7 +283,8 @@ private: - - struct QScriptItem; - /// Internal QTextItem --class QTextItemInt : public QTextItem -+// Patch: Enable access to QTextItemInt in .dll for WinRT build. -+class Q_GUI_EXPORT QTextItemInt : public QTextItem - { - public: - inline QTextItemInt() -diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp -index aca475a..5fa0be2 100644 ---- a/src/gui/text/qtextlayout.cpp -+++ b/src/gui/text/qtextlayout.cpp -@@ -694,6 +694,9 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const - while (oldPos < len && !attributes[oldPos].graphemeBoundary) - oldPos++; - } else { -+ // Patch: Skip to the end of the current word, not to the start of the next one. -+ while (oldPos < len && attributes[oldPos].whiteSpace) -+ oldPos++; - if (oldPos < len && d->atWordSeparator(oldPos)) { - oldPos++; - while (oldPos < len && d->atWordSeparator(oldPos)) -@@ -702,8 +705,9 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const - while (oldPos < len && !attributes[oldPos].whiteSpace && !d->atWordSeparator(oldPos)) - oldPos++; - } -- while (oldPos < len && attributes[oldPos].whiteSpace) -- oldPos++; -+ // Patch: Skip to the end of the current word, not to the start of the next one. -+ //while (oldPos < len && attributes[oldPos].whiteSpace) -+ // oldPos++; - } - - return oldPos; -@@ -1645,6 +1649,9 @@ namespace { - int currentPosition; - glyph_t previousGlyph; - -+ // Patch: Fix a crash in right bearing calculation. -+ QFontEngine *previousGlyphFontEngine; -+ - QFixed minw; - QFixed softHyphenWidth; - QFixed rightBearing; -@@ -1677,13 +1684,19 @@ namespace { - if (currentPosition > 0 && - logClusters[currentPosition - 1] < glyphs.numGlyphs) { - previousGlyph = currentGlyph(); // needed to calculate right bearing later -+ -+ // Patch: Fix a crash in right bearing calculation. -+ previousGlyphFontEngine = fontEngine; - } - } - -- inline void calculateRightBearing(glyph_t glyph) -+ // Patch: Fix a crash in right bearing calculation. -+ inline void calculateRightBearing(QFontEngine *engine, glyph_t glyph) - { - qreal rb; -- fontEngine->getGlyphBearings(glyph, 0, &rb); -+ -+ // Patch: Fix a crash in right bearing calculation. -+ engine->getGlyphBearings(glyph, 0, &rb); - - // We only care about negative right bearings, so we limit the range - // of the bearing here so that we can assume it's negative in the rest -@@ -1696,13 +1709,16 @@ namespace { - { - if (currentPosition <= 0) - return; -- calculateRightBearing(currentGlyph()); -+ -+ // Patch: Fix a crash in right bearing calculation. -+ calculateRightBearing(fontEngine, currentGlyph()); - } - - inline void calculateRightBearingForPreviousGlyph() - { - if (previousGlyph > 0) -- calculateRightBearing(previousGlyph); -+ // Patch: Fix a crash in right bearing calculation. -+ calculateRightBearing(previousGlyphFontEngine, previousGlyph); - } - - static const QFixed RightBearingNotCalculated; -diff --git a/src/gui/text/qtextlayout.h b/src/gui/text/qtextlayout.h -index f74d4d4..8ad672c 100644 ---- a/src/gui/text/qtextlayout.h -+++ b/src/gui/text/qtextlayout.h -@@ -196,6 +196,9 @@ private: - QRectF *brect, int tabstops, int* tabarray, int tabarraylen, - QPainter *painter); - QTextEngine *d; -+ -+ // Patch: Allow access to private constructor. -+ friend class TextBlock; - }; - - -diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp -index 41834b2..8cdf4ab 100644 ---- a/src/network/socket/qnativesocketengine_win.cpp -+++ b/src/network/socket/qnativesocketengine_win.cpp -@@ -675,6 +675,13 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &address, quin - errorDetected = true; - break; - } -+ // Patch: Handle network unreachable the same as host unreachable. -+ if (value == WSAENETUNREACH) { -+ setError(QAbstractSocket::NetworkError, NetworkUnreachableErrorString); -+ socketState = QAbstractSocket::UnconnectedState; -+ errorDetected = true; -+ break; -+ } - if (value == WSAEADDRNOTAVAIL) { - setError(QAbstractSocket::NetworkError, AddressNotAvailableErrorString); - socketState = QAbstractSocket::UnconnectedState; -diff --git a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp -index 728b166..1dc6459 100644 ---- a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp -+++ b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp -@@ -172,6 +172,79 @@ void QBasicFontDatabase::releaseHandle(void *handle) - - extern FT_Library qt_getFreetype(); - -+// Patch: Enable Open Sans Semibold font family reading. -+// Copied from freetype with some modifications. -+ -+#ifndef FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY -+#define FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY FT_MAKE_TAG('i', 'g', 'p', 'f') -+#endif -+ -+#ifndef FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY -+#define FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY FT_MAKE_TAG('i', 'g', 'p', 's') -+#endif -+ -+/* there's a Mac-specific extended implementation of FT_New_Face() */ -+/* in src/base/ftmac.c */ -+ -+#if !defined( FT_MACINTOSH ) || defined( DARWIN_NO_CARBON ) -+ -+/* documentation is in freetype.h */ -+ -+FT_Error __ft_New_Face(FT_Library library, const char* pathname, FT_Long face_index, FT_Face *aface) { -+ FT_Open_Args args; -+ -+ /* test for valid `library' and `aface' delayed to FT_Open_Face() */ -+ if (!pathname) -+ return FT_Err_Invalid_Argument; -+ -+ FT_Parameter params[2]; -+ params[0].tag = FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY; -+ params[0].data = 0; -+ params[1].tag = FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY; -+ params[1].data = 0; -+ args.flags = FT_OPEN_PATHNAME | FT_OPEN_PARAMS; -+ args.pathname = (char*)pathname; -+ args.stream = NULL; -+ args.num_params = 2; -+ args.params = params; -+ -+ return FT_Open_Face(library, &args, face_index, aface); -+} -+ -+#else -+ -+FT_Error __ft_New_Face(FT_Library library, const char* pathname, FT_Long face_index, FT_Face *aface) { -+ return FT_New_Face(library, pathname, face_index, aface); -+} -+ -+#endif /* defined( FT_MACINTOSH ) && !defined( DARWIN_NO_CARBON ) */ -+ -+/* documentation is in freetype.h */ -+ -+FT_Error __ft_New_Memory_Face(FT_Library library, const FT_Byte* file_base, FT_Long file_size, FT_Long face_index, FT_Face *aface) { -+ FT_Open_Args args; -+ -+ /* test for valid `library' and `face' delayed to FT_Open_Face() */ -+ if (!file_base) -+ return FT_Err_Invalid_Argument; -+ -+ FT_Parameter params[2]; -+ params[0].tag = FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY; -+ params[0].data = 0; -+ params[1].tag = FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY; -+ params[1].data = 0; -+ args.flags = FT_OPEN_MEMORY | FT_OPEN_PARAMS; -+ args.memory_base = file_base; -+ args.memory_size = file_size; -+ args.stream = NULL; -+ args.num_params = 2; -+ args.params = params; -+ -+ return FT_Open_Face(library, &args, face_index, aface); -+} -+ -+// end -+ - QStringList QBasicFontDatabase::addTTFile(const QByteArray &fontData, const QByteArray &file) - { - FT_Library library = qt_getFreetype(); -@@ -183,9 +256,11 @@ 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); -+ // Patch: Enable Open Sans Semibold font family reading. -+ 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); -+ // Patch: Enable Open Sans Semibold font family reading. -+ error = __ft_New_Face(library, file.constData(), index, &face); - } - if (error != FT_Err_Ok) { - qDebug() << "FT_New_Face failed with index" << index << ':' << hex << error; -diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp -index 8ebabf3..7bb8abd 100644 ---- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp -+++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp -@@ -375,6 +375,17 @@ static void populateFromPattern(FcPattern *pattern) - - familyName = QString::fromUtf8((const char *)value); - -+ // Patch: Enable Open Sans Semibold font family reading. -+ if (familyName == QLatin1String("Open Sans")) { -+ FcChar8 *styl = 0; -+ if (FcPatternGetString(pattern, FC_STYLE, 0, &styl) == FcResultMatch) { -+ QString style = QString::fromUtf8(reinterpret_cast(styl)); -+ if (style == QLatin1String("Semibold")) { -+ familyName.append(QChar(QChar::Space)).append(style); -+ } -+ } -+ } -+ - slant_value = FC_SLANT_ROMAN; - weight_value = FC_WEIGHT_REGULAR; - spacing_value = FC_PROPORTIONAL; -@@ -718,7 +729,19 @@ QStringList QFontconfigDatabase::fallbacksForFamily(const QString &family, QFont - if (FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch) - continue; - // capitalize(value); -- const QString familyName = QString::fromUtf8((const char *)value); -+ -+ // Patch: Enable Open Sans Semibold font family reading. -+ QString familyName = QString::fromUtf8((const char *)value); -+ if (familyName == QLatin1String("Open Sans")) { -+ FcChar8 *styl = 0; -+ if (FcPatternGetString(fontSet->fonts[i], FC_STYLE, 0, &styl) == FcResultMatch) { -+ QString style = QString::fromUtf8(reinterpret_cast(styl)); -+ if (style == QLatin1String("Semibold")) { -+ familyName.append(QChar(QChar::Space)).append(style); -+ } -+ } -+ } -+ - const QString familyNameCF = familyName.toCaseFolded(); - if (!duplicates.contains(familyNameCF)) { - fallbackFamilies << familyName; -@@ -784,6 +807,18 @@ QStringList QFontconfigDatabase::addApplicationFont(const QByteArray &fontData, - FcChar8 *fam = 0; - if (FcPatternGetString(pattern, FC_FAMILY, 0, &fam) == FcResultMatch) { - QString family = QString::fromUtf8(reinterpret_cast(fam)); -+ -+ // Patch: Enable Open Sans Semibold font family reading. -+ if (family == QLatin1String("Open Sans")) { -+ FcChar8 *styl = 0; -+ if (FcPatternGetString(pattern, FC_STYLE, 0, &styl) == FcResultMatch) { -+ QString style = QString::fromUtf8(reinterpret_cast(styl)); -+ if (style == QLatin1String("Semibold")) { -+ family.append(QChar(QChar::Space)).append(style); -+ } -+ } -+ } -+ - families << family; - } - populateFromPattern(pattern); -diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm -index 566abf2..5b9c714 100644 ---- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm -+++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm -@@ -265,6 +265,13 @@ static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd) - - fd->foundryName = QStringLiteral("CoreText"); - fd->familyName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute); -+ -+ // Patch: Enable Open Sans Semibold font family reading. -+ QCFString _displayName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontDisplayNameAttribute); -+ if (_displayName == QStringLiteral("Open Sans Semibold")) { -+ fd->familyName = _displayName; -+ } -+ - fd->styleName = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontStyleNameAttribute); - fd->weight = QFont::Normal; - fd->style = QFont::StyleNormal; -diff --git a/src/plugins/platforminputcontexts/compose/compose.pro b/src/plugins/platforminputcontexts/compose/compose.pro -index 86bdd47..9b9c8de 100644 ---- a/src/plugins/platforminputcontexts/compose/compose.pro -+++ b/src/plugins/platforminputcontexts/compose/compose.pro -@@ -15,7 +15,8 @@ HEADERS += $$PWD/qcomposeplatforminputcontext.h \ - contains(QT_CONFIG, xkbcommon-qt): { - # dont't need x11 dependency for compose key plugin - QT_CONFIG -= use-xkbcommon-x11support -- include(../../../3rdparty/xkbcommon.pri) -+ # Patch: Adding fcitx input context plugin to our static build. -+ #include(../../../3rdparty/xkbcommon.pri) - } else { - LIBS += $$QMAKE_LIBS_XKBCOMMON - QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_XKBCOMMON -diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp -index d1bea9a..36a15a6 100644 ---- a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp -+++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp -@@ -232,6 +232,12 @@ bool QComposeInputContext::checkComposeTable() - - void QComposeInputContext::commitText(uint character) const - { -+ // Patch: Crash fix when not focused widget still receives input events. -+ if (!m_focusObject) { -+ qWarning("QComposeInputContext::commitText: m_focusObject == nullptr, cannot commit text"); -+ return; -+ } -+ - QInputMethodEvent event; - event.setCommitString(QChar(character)); - QCoreApplication::sendEvent(m_focusObject, &event); -diff --git a/src/plugins/platforminputcontexts/platforminputcontexts.pro b/src/plugins/platforminputcontexts/platforminputcontexts.pro -index faea54b..0f96509 100644 ---- a/src/plugins/platforminputcontexts/platforminputcontexts.pro -+++ b/src/plugins/platforminputcontexts/platforminputcontexts.pro -@@ -1,7 +1,8 @@ - TEMPLATE = subdirs - - qtHaveModule(dbus) { --!mac:!win32:SUBDIRS += ibus -+# Patch: Adding fcitx/hime input context plugin to our static build. -+!mac:!win32:SUBDIRS += ibus fcitx hime - } - - contains(QT_CONFIG, xcb-plugin): SUBDIRS += compose -diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm -index caa8884..9dc3bc1 100644 ---- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm -+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm -@@ -210,7 +210,8 @@ QT_END_NAMESPACE - if (reflectionDelegate) { - if ([reflectionDelegate respondsToSelector:@selector(applicationShouldTerminate:)]) - return [reflectionDelegate applicationShouldTerminate:sender]; -- return NSTerminateNow; -+ // Patch: Don't terminate if reflectionDelegate does not respond to that selector, just use the default. -+ //return NSTerminateNow; - } - - if ([self canQuit]) { -@@ -287,11 +288,15 @@ QT_END_NAMESPACE - - - (void)applicationDidFinishLaunching:(NSNotification *)aNotification - { -+ // Patch: We need to catch that notification in delegate. -+ if (reflectionDelegate -+ && [reflectionDelegate respondsToSelector:@selector(applicationDidFinishLaunching:)]) -+ [reflectionDelegate applicationDidFinishLaunching:aNotification]; -+ - Q_UNUSED(aNotification); - inLaunch = false; - // qt_release_apple_event_handler(); - -- - // Insert code here to initialize your application - } - -diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h -index 934f68a..3ece698 100644 ---- a/src/plugins/platforms/cocoa/qcocoabackingstore.h -+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h -@@ -64,6 +64,9 @@ public: - private: - QImage m_qImage; - QSize m_requestedSize; -+ -+ // Patch: Optimize redraw - don't clear image if it will be fully redrawn. -+ bool m_qImageNeedsClear; - }; - - QT_END_NAMESPACE -diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm -index ca92103..f27ea15 100644 ---- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm -+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm -@@ -38,7 +38,8 @@ - QT_BEGIN_NAMESPACE - - QCocoaBackingStore::QCocoaBackingStore(QWindow *window) -- : QPlatformBackingStore(window) -+ // Patch: Optimize redraw - don't clear image if it will be fully redrawn. -+ : QPlatformBackingStore(window), m_qImageNeedsClear(false) - { - } - -@@ -59,9 +60,12 @@ QPaintDevice *QCocoaBackingStore::paintDevice() - if (m_qImage.size() != effectiveBufferSize) { - QImage::Format format = (window()->format().hasAlpha() || cocoaWindow->m_drawContentBorderGradient) - ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; -+ -+ // Patch: Optimize redraw - don't clear image if it will be fully redrawn. -+ m_qImageNeedsClear = window()->requestedFormat().hasAlpha() || cocoaWindow->m_drawContentBorderGradient; - m_qImage = QImage(effectiveBufferSize, format); - m_qImage.setDevicePixelRatio(windowDevicePixelRatio); -- if (format == QImage::Format_ARGB32_Premultiplied) -+ if (m_qImageNeedsClear) - m_qImage.fill(Qt::transparent); - } - return &m_qImage; -@@ -100,7 +104,8 @@ bool QCocoaBackingStore::scroll(const QRegion &area, int dx, int dy) - - void QCocoaBackingStore::beginPaint(const QRegion ®ion) - { -- if (m_qImage.hasAlphaChannel()) { -+ // Patch: Optimize redraw - don't clear image if it will be fully redrawn. -+ if (m_qImageNeedsClear && m_qImage.hasAlphaChannel()) { - QPainter p(&m_qImage); - p.setCompositionMode(QPainter::CompositionMode_Source); - const QVector rects = region.rects(); -diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.mm b/src/plugins/platforms/cocoa/qcocoakeymapper.mm -index c2d206f..9b97398 100644 ---- a/src/plugins/platforms/cocoa/qcocoakeymapper.mm -+++ b/src/plugins/platforms/cocoa/qcocoakeymapper.mm -@@ -384,6 +384,12 @@ bool QCocoaKeyMapper::updateKeyboard() - keyboardInputLocale = QLocale::c(); - keyboardInputDirection = Qt::LeftToRight; - } -+ -+ // Patch: Fix layout-independent global shortcuts. -+ const auto newMode = keyboard_mode; -+ deleteLayouts(); -+ keyboard_mode = newMode; -+ - return true; - } - -@@ -466,7 +472,8 @@ QList QCocoaKeyMapper::possibleKeys(const QKeyEvent *event) const - Qt::KeyboardModifiers neededMods = ModsTbl[i]; - int key = kbItem->qtKey[i]; - if (key && key != baseKey && ((keyMods & neededMods) == neededMods)) { -- ret << int(key + (keyMods & ~neededMods)); -+ // Patch: Fix layout-independent global shortcuts. -+ ret << int(key + neededMods); - } - } - return ret; -diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm -index 8152c57..5ddd7b3 100644 ---- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm -+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm -@@ -94,6 +94,8 @@ QT_USE_NAMESPACE - QCocoaSystemTrayIcon *systray; - NSStatusItem *item; - QCocoaMenu *menu; -+ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). -+ bool menuVisible, iconSelected; - QIcon icon; - QT_MANGLE_NAMESPACE(QNSImageView) *imageCell; - } -@@ -197,7 +199,9 @@ 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. -- const int padding = 4; -+ -+ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). -+ const int padding = 0; - const int menuHeight = [[NSStatusBar systemStatusBar] thickness]; - const int maxImageHeight = menuHeight - padding; - -@@ -207,8 +211,11 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon) - // devicePixelRatio for the "best" screen on the system. - qreal devicePixelRatio = qApp->devicePixelRatio(); - const int maxPixmapHeight = maxImageHeight * devicePixelRatio; -+ -+ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). -+ const QIcon::Mode mode = m_sys->item->iconSelected ? QIcon::Selected : QIcon::Normal; - QSize selectedSize; -- 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 - // with a height smaller or equal to maxPixmapHeight. The pixmap - // may rectangular; assume it has a reasonable size. If there is -@@ -224,9 +231,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. -@@ -374,6 +381,11 @@ QT_END_NAMESPACE - Q_UNUSED(notification); - down = NO; - -+ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). -+ parent->iconSelected = false; -+ parent->systray->updateIcon(parent->icon); -+ parent->menuVisible = false; -+ - [self setNeedsDisplay:YES]; - } - -@@ -383,6 +395,10 @@ QT_END_NAMESPACE - int clickCount = [mouseEvent clickCount]; - [self setNeedsDisplay:YES]; - -+ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). -+ parent->iconSelected = (clickCount != 2) && parent->menu; -+ parent->systray->updateIcon(parent->icon); -+ - if (clickCount == 2) { - [self menuTrackingDone:nil]; - [parent doubleClickSelector:self]; -@@ -399,6 +415,11 @@ QT_END_NAMESPACE - -(void)mouseUp:(NSEvent *)mouseEvent - { - Q_UNUSED(mouseEvent); -+ -+ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). -+ parent->iconSelected = false; -+ parent->systray->updateIcon(parent->icon); -+ - [self menuTrackingDone:nil]; - } - -@@ -410,6 +431,11 @@ QT_END_NAMESPACE - -(void)rightMouseUp:(NSEvent *)mouseEvent - { - Q_UNUSED(mouseEvent); -+ -+ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). -+ parent->iconSelected = false; -+ parent->systray->updateIcon(parent->icon); -+ - [self menuTrackingDone:nil]; - } - -@@ -425,7 +451,8 @@ QT_END_NAMESPACE - } - - -(void)drawRect:(NSRect)rect { -- [[parent item] drawStatusBarBackgroundInRect:rect withHighlight:down]; -+ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). -+ [[parent item] drawStatusBarBackgroundInRect:rect withHighlight:parent->menu ? down : NO]; - [super drawRect:rect]; - } - @end -@@ -438,6 +465,10 @@ QT_END_NAMESPACE - if (self) { - item = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain]; - menu = 0; -+ -+ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). -+ menuVisible = false; -+ - systray = sys; - imageCell = [[QNSImageView alloc] initWithParent:self]; - [item setView: imageCell]; -@@ -482,6 +513,10 @@ QT_END_NAMESPACE - selector:@selector(menuTrackingDone:) - name:NSMenuDidEndTrackingNotification - object:m]; -+ -+ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). -+ menuVisible = true; -+ - [item popUpStatusItemMenu: m]; - } - } -diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm -index c0d5904..f3c2047 100644 ---- a/src/plugins/platforms/cocoa/qcocoawindow.mm -+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm -@@ -141,7 +141,8 @@ static bool isMouseEvent(NSEvent *ev) - if (!self.window.delegate) - return; // Already detached, pending NSAppKitDefined event - -- if (pw && pw->frameStrutEventsEnabled() && isMouseEvent(theEvent)) { -+ // Patch: Fix restore after minimize or close by window buttons. -+ if (pw && pw->frameStrutEventsEnabled() && pw->m_synchedWindowState != Qt::WindowMinimized && pw->m_isExposed && isMouseEvent(theEvent)) { - NSPoint loc = [theEvent locationInWindow]; - NSRect windowFrame = [self.window convertRectFromScreen:[self.window frame]]; - NSRect contentFrame = [[self.window contentView] frame]; -@@ -811,6 +812,16 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags) - { - Qt::WindowType type = static_cast(int(flags & Qt::WindowType_Mask)); - NSInteger styleMask = NSBorderlessWindowMask; -+ -+ // Patch: allow creating panels floating on all spaces in macOS. -+ // If you call "setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary" before -+ // setting the "NSNonactivatingPanelMask" bit in the style mask it won't work after that. -+ // So we need a way to set that bit before Qt sets collection behavior the way it does. -+ QVariant nonactivatingPanelMask = window()->property("_td_macNonactivatingPanelMask"); -+ if (nonactivatingPanelMask.isValid() && nonactivatingPanelMask.toBool()) { -+ styleMask |= NSNonactivatingPanelMask; -+ } -+ - if (flags & Qt::FramelessWindowHint) - return styleMask; - if ((type & Qt::Popup) == Qt::Popup) { -@@ -943,6 +954,19 @@ void QCocoaWindow::setWindowFilePath(const QString &filePath) - [m_nsWindow setRepresentedFilename: fi.exists() ? QCFString::toNSString(filePath) : @""]; - } - -+// Patch: Create a good os x window icon (pixel-perfect). -+namespace { -+ -+qreal getDevicePixelRatio() { -+ qreal result = 1.0; -+ foreach (QScreen *screen, QGuiApplication::screens()) { -+ result = qMax(result, screen->devicePixelRatio()); -+ } -+ return result; -+} -+ -+} // namespace -+ - void QCocoaWindow::setWindowIcon(const QIcon &icon) - { - QMacAutoReleasePool pool; -@@ -958,7 +982,9 @@ void QCocoaWindow::setWindowIcon(const QIcon &icon) - if (icon.isNull()) { - [iconButton setImage:nil]; - } else { -- QPixmap pixmap = icon.pixmap(QSize(22, 22)); -+ // Patch: Create a good os x window icon (pixel-perfect). -+ CGFloat hgt = 16. * getDevicePixelRatio(); -+ QPixmap pixmap = icon.pixmap(QSize(hgt, hgt)); - NSImage *image = static_cast(qt_mac_create_nsimage(pixmap)); - [iconButton setImage:image]; - [image release]; -diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm -index c67bcfd..4498a17 100644 ---- a/src/plugins/platforms/cocoa/qnsview.mm -+++ b/src/plugins/platforms/cocoa/qnsview.mm -@@ -1431,7 +1431,9 @@ 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) { -+ -+ // Patch: Fix actual begin handle of swipe on trackpad. -+ if (phase == NSEventPhaseMayBegin || phase == NSEventPhaseBegan) { - m_scrolling = true; - ph = Qt::ScrollBegin; - } -@@ -1496,14 +1498,14 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) - quint32 nativeVirtualKey = [nsevent keyCode]; - - QChar ch = QChar::ReplacementCharacter; -- int keyCode = Qt::Key_unknown; -- if ([characters length] != 0) { -- if (((modifiers & Qt::MetaModifier) || (modifiers & Qt::AltModifier)) && ([charactersIgnoringModifiers length] != 0)) -- ch = QChar([charactersIgnoringModifiers characterAtIndex:0]); -- else -- ch = QChar([characters characterAtIndex:0]); -- keyCode = [self convertKeyCode:ch]; -- } -+ -+ // Patch: Fix Alt+.. shortcuts in OS X. See https://bugreports.qt.io/browse/QTBUG-42584 at the end. -+ if ([characters length] != 0) -+ ch = QChar([characters characterAtIndex:0]); -+ else if ([charactersIgnoringModifiers length] != 0 && ((modifiers & Qt::MetaModifier) || (modifiers & Qt::AltModifier))) -+ ch = QChar([charactersIgnoringModifiers characterAtIndex:0]); -+ -+ int keyCode = [self convertKeyCode:ch]; - - // we will send a key event unless the input method sets m_sendKeyEvent to false - m_sendKeyEvent = true; -@@ -1569,6 +1571,23 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) - [self handleKeyEvent:nsevent eventType:int(QEvent::KeyRelease)]; - } - -+// Patch: Enable Ctrl+Tab and Ctrl+Shift+Tab / Ctrl+Backtab handle in-app. -+- (BOOL)performKeyEquivalent:(NSEvent *)nsevent -+{ -+ NSString *chars = [nsevent charactersIgnoringModifiers]; -+ -+ if ([nsevent type] == NSKeyDown && [chars length] > 0) { -+ QChar ch = [chars characterAtIndex:0]; -+ Qt::Key qtKey = qt_mac_cocoaKey2QtKey(ch); -+ 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]; -+} -+ - - (void)cancelOperation:(id)sender - { - Q_UNUSED(sender); -diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp -index 94bb71e..16ab51e 100644 ---- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp -+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp -@@ -716,12 +716,20 @@ public: - void setSelectedFiles(const QList &); - QString selectedFile() const; - -+ // Patch: Adding select-by-url for Windows file dialog. -+ void setSelectedRemoteContent(const QByteArray &); -+ QByteArray selectedRemoteContent() const; -+ - private: - class Data : public QSharedData { - public: - QUrl directory; - QString selectedNameFilter; - QList selectedFiles; -+ -+ // Patch: Adding select-by-url for Windows file dialog. -+ QByteArray selectedRemoteContent; -+ - QMutex mutex; - }; - QExplicitlySharedDataPointer m_data; -@@ -775,6 +783,21 @@ inline void QWindowsFileDialogSharedData::setSelectedFiles(const QList &ur - m_data->selectedFiles = urls; - } - -+// Patch: Adding select-by-url for Windows file dialog. -+inline QByteArray QWindowsFileDialogSharedData::selectedRemoteContent() const -+{ -+ m_data->mutex.lock(); -+ const QByteArray result = m_data->selectedRemoteContent; -+ m_data->mutex.unlock(); -+ return result; -+} -+ -+inline void QWindowsFileDialogSharedData::setSelectedRemoteContent(const QByteArray &c) -+{ -+ QMutexLocker(&m_data->mutex); -+ m_data->selectedRemoteContent = c; -+} -+ - inline void QWindowsFileDialogSharedData::fromOptions(const QSharedPointer &o) - { - QMutexLocker locker(&m_data->mutex); -@@ -899,6 +922,9 @@ public: - // example by appended default suffixes, etc. - virtual QList dialogResult() const = 0; - -+ // Patch: Adding select-by-url for Windows file dialog. -+ virtual QByteArray dialogRemoteContent() const { return QByteArray(); } -+ - inline void onFolderChange(IShellItem *); - inline void onSelectionChange(); - inline void onTypeChange(); -@@ -1338,7 +1364,14 @@ void QWindowsNativeFileDialogBase::selectFile(const QString &fileName) const - // 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()); -+ // Patch: Fix handle of full 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());; -+ } - } - - // Return the index of the selected filter, accounting for QFileDialog -@@ -1408,6 +1441,10 @@ bool QWindowsNativeFileDialogBase::onFileOk() - { - // Store selected files as GetResults() returns invalid data after the dialog closes. - m_data.setSelectedFiles(dialogResult()); -+ -+ // Patch: Adding select-by-url for Windows file dialog. -+ m_data.setSelectedRemoteContent(dialogRemoteContent()); -+ - return true; - } - -@@ -1542,6 +1579,9 @@ public: - QList selectedFiles() const Q_DECL_OVERRIDE; - QList dialogResult() const Q_DECL_OVERRIDE; - -+ // Patch: Adding select-by-url for Windows file dialog. -+ QByteArray dialogRemoteContent() const Q_DECL_OVERRIDE; -+ - private: - inline IFileOpenDialog *openFileDialog() const - { return static_cast(fileDialog()); } -@@ -1556,6 +1596,62 @@ QList QWindowsNativeOpenFileDialog::dialogResult() const - return result; - } - -+// Patch: Adding select-by-url for Windows file dialog. -+QByteArray QWindowsNativeOpenFileDialog::dialogRemoteContent() const -+{ -+ QByteArray result; -+ IShellItemArray *items = 0; -+ if (FAILED(openFileDialog()->GetResults(&items)) || !items) -+ return result; -+ DWORD itemCount = 0; -+ if (FAILED(items->GetCount(&itemCount)) || !itemCount) -+ return result; -+ for (DWORD i = 0; i < itemCount; ++i) -+ { -+ IShellItem *item = 0; -+ if (SUCCEEDED(items->GetItemAt(i, &item))) { -+ SFGAOF attributes = 0; -+ // Check whether it has a file system representation? -+ if (FAILED(item->GetAttributes(SFGAO_FILESYSTEM, &attributes)) || (attributes & SFGAO_FILESYSTEM)) -+ { -+ LPWSTR name = 0; -+ if (SUCCEEDED(item->GetDisplayName(SIGDN_FILESYSPATH, &name))) -+ { -+ CoTaskMemFree(name); -+ continue; -+ } -+ } -+ if (FAILED(item->GetAttributes(SFGAO_STREAM, &attributes)) || !(attributes & SFGAO_STREAM)) -+ continue; -+ -+ IBindCtx *bind = 0; -+ if (FAILED(CreateBindCtx(0, &bind))) -+ continue; -+ -+ IStream *stream = 0; -+ if (FAILED(item->BindToHandler(bind, BHID_Stream, IID_IStream, reinterpret_cast(&stream)))) -+ continue; -+ -+ STATSTG stat = { 0 }; -+ if (FAILED(stream->Stat(&stat, STATFLAG_NONAME)) || !stat.cbSize.QuadPart) -+ continue; -+ -+ quint64 fullSize = stat.cbSize.QuadPart; -+ if (fullSize <= 64 * 1024 * 1024) -+ { -+ result.resize(fullSize); -+ ULONG read = 0; -+ HRESULT r = stream->Read(result.data(), fullSize, &read); -+ if (r == S_FALSE || r == S_OK) -+ return result; -+ -+ result.clear(); -+ } -+ } -+ } -+ return result; -+} -+ - QList QWindowsNativeOpenFileDialog::selectedFiles() const - { - QList result; -@@ -1614,6 +1710,10 @@ public: - virtual QUrl directory() const Q_DECL_OVERRIDE; - virtual void selectFile(const QUrl &filename) Q_DECL_OVERRIDE; - virtual QList selectedFiles() const Q_DECL_OVERRIDE; -+ -+ // Patch: Adding select-by-url for Windows file dialog. -+ virtual QByteArray selectedRemoteContent() const Q_DECL_OVERRIDE; -+ - virtual void setFilter() Q_DECL_OVERRIDE; - virtual void selectNameFilter(const QString &filter) Q_DECL_OVERRIDE; - virtual QString selectedNameFilter() const Q_DECL_OVERRIDE; -@@ -1707,6 +1807,12 @@ QList QWindowsFileDialogHelper::selectedFiles() const - return m_data.selectedFiles(); - } - -+// Patch: Adding select-by-url for Windows file dialog. -+QByteArray QWindowsFileDialogHelper::selectedRemoteContent() const -+{ -+ return m_data.selectedRemoteContent(); -+} -+ - void QWindowsFileDialogHelper::setFilter() - { - qCDebug(lcQpaDialogs) << __FUNCTION__; -@@ -1996,6 +2102,10 @@ public: - QUrl directory() const Q_DECL_OVERRIDE; - void selectFile(const QUrl &url) Q_DECL_OVERRIDE; - QList selectedFiles() const Q_DECL_OVERRIDE; -+ -+ // Patch: Adding select-by-url for Windows file dialog. -+ QByteArray selectedRemoteContent() const Q_DECL_OVERRIDE; -+ - void setFilter() Q_DECL_OVERRIDE {} - void selectNameFilter(const QString &) Q_DECL_OVERRIDE; - QString selectedNameFilter() const Q_DECL_OVERRIDE; -@@ -2039,6 +2149,12 @@ QList QWindowsXpFileDialogHelper::selectedFiles() const - return m_data.selectedFiles(); - } - -+// Patch: Adding select-by-url for Windows file dialog. -+QByteArray QWindowsXpFileDialogHelper::selectedRemoteContent() const -+{ -+ return m_data.selectedRemoteContent(); -+} -+ - void QWindowsXpFileDialogHelper::selectNameFilter(const QString &f) - { - m_data.setSelectedNameFilter(f); // Dialog cannot be updated at run-time. -diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp -index 1e58b9b..1741c21 100644 ---- a/src/plugins/platforms/windows/qwindowskeymapper.cpp -+++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp -@@ -1268,6 +1268,10 @@ QList QWindowsKeyMapper::possibleKeys(const QKeyEvent *e) const - if (nativeVirtualKey > 255) - return result; - -+ // Patch: This must not happen, but there are crash reports on the next line. -+ if (e->nativeVirtualKey() > 0xFF) -+ return result; -+ - const KeyboardLayoutItem &kbItem = keyLayout[nativeVirtualKey]; - if (!kbItem.exists) - return result; -diff --git a/src/plugins/platforms/windows/qwindowsservices.cpp b/src/plugins/platforms/windows/qwindowsservices.cpp -index 1d23a9d..640cd42 100644 ---- a/src/plugins/platforms/windows/qwindowsservices.cpp -+++ b/src/plugins/platforms/windows/qwindowsservices.cpp -@@ -127,6 +127,10 @@ static inline bool launchMail(const QUrl &url) - command.prepend(doubleQuote); - } - } -+ -+ // Patch: Fix mail launch if no param is expected in this command. -+ if (command.indexOf(QStringLiteral("%1")) < 0) return false; -+ - // Pass the url as the parameter. Should use QProcess::startDetached(), - // but that cannot handle a Windows command line [yet]. - command.replace(QStringLiteral("%1"), url.toString(QUrl::FullyEncoded)); -diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp -index b38d7c2..34f19c4 100644 ---- a/src/plugins/platforms/windows/qwindowswindow.cpp -+++ b/src/plugins/platforms/windows/qwindowswindow.cpp -@@ -1020,7 +1020,8 @@ 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)) -- tw->updateTransientParent(); -+ // Patch: Fix possibility of add / remove taskbar icon of the window. -+ tw->clearTransientParent(); - QWindowsContext *context = QWindowsContext::instance(); - if (context->windowUnderMouse() == window()) - context->clearWindowUnderMouse(); -@@ -1235,6 +1236,21 @@ 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(); -+ // Patch: Fix possibility of add / remove taskbar icon of the window. -+ if (newTransientParent && newTransientParent != oldTransientParent) -+ SetWindowLongPtr(m_data.hwnd, GWL_HWNDPARENT, (LONG_PTR)newTransientParent); -+#endif // !Q_OS_WINCE -+} -+ -+// Patch: Fix possibility of add / remove taskbar icon of the window. -+void QWindowsWindow::clearTransientParent() const -+{ -+#ifndef Q_OS_WINCE -+ if (window()->type() == Qt::Popup) -+ return; // QTBUG-34503, // a popup stays on top, no parent, see also WindowCreationData::fromWindow(). -+ // Update transient parent. -+ const HWND oldTransientParent = transientParentHwnd(m_data.hwnd); -+ HWND newTransientParent = 0; - if (newTransientParent != oldTransientParent) - SetWindowLongPtr(m_data.hwnd, GWL_HWNDPARENT, (LONG_PTR)newTransientParent); - #endif // !Q_OS_WINCE -@@ -1448,10 +1464,14 @@ void QWindowsWindow::handleResized(int wParam) - handleGeometryChange(); - break; - case SIZE_RESTORED: -- if (isFullScreen_sys()) -- handleWindowStateChange(Qt::WindowFullScreen); -- else if (m_windowState != Qt::WindowNoState && !testFlag(MaximizeToFullScreen)) -+ // Patch: When resolution is changed for a frameless fullscreen widget -+ // handleWindowStateChange call prevents correct geometry get in handleGeometryChange(). -+ if (isFullScreen_sys()) { -+ if (m_windowState != Qt::WindowFullScreen) -+ handleWindowStateChange(Qt::WindowFullScreen); -+ } else if (m_windowState != Qt::WindowNoState && !testFlag(MaximizeToFullScreen)) { - handleWindowStateChange(Qt::WindowNoState); -+ } - handleGeometryChange(); - break; - } -diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h -index 6fffa1e..cb1c9c1 100644 ---- a/src/plugins/platforms/windows/qwindowswindow.h -+++ b/src/plugins/platforms/windows/qwindowswindow.h -@@ -265,6 +265,10 @@ private: - inline void setWindowState_sys(Qt::WindowState newState); - inline void setParent_sys(const QPlatformWindow *parent); - inline void updateTransientParent() const; -+ -+ // Patch: Fix possibility of add / remove taskbar icon of the window. -+ inline void clearTransientParent() const; -+ - void destroyWindow(); - inline bool isDropSiteEnabled() const { return m_dropTarget != 0; } - void setDropSiteEnabled(bool enabled); -diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp -index 09e7ecf..c0f15a4 100644 ---- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp -+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp -@@ -79,7 +79,10 @@ static int resourceType(const QByteArray &key) - QByteArrayLiteral("rootwindow"), - QByteArrayLiteral("subpixeltype"), QByteArrayLiteral("antialiasingenabled"), - QByteArrayLiteral("nofonthinting"), -- QByteArrayLiteral("atspibus") -+ QByteArrayLiteral("atspibus"), -+ -+ // Patch: Backport compositing manager check from Qt 5.7 -+ QByteArrayLiteral("compositingenabled") - }; - const QByteArray *end = names + sizeof(names) / sizeof(names[0]); - const QByteArray *result = std::find(names, end, key); -@@ -252,6 +255,13 @@ void *QXcbNativeInterface::nativeResourceForScreen(const QByteArray &resourceStr - case RootWindow: - result = reinterpret_cast(xcbScreen->root()); - break; -+ -+ // Patch: Backport compositing manager check from Qt 5.7 -+ case CompositingEnabled: -+ if (QXcbVirtualDesktop *vd = xcbScreen->virtualDesktop()) -+ result = vd->compositingActive() ? this : Q_NULLPTR; -+ break; -+ - default: - break; - } -diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h -index f88b710..6f818a5 100644 ---- a/src/plugins/platforms/xcb/qxcbnativeinterface.h -+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h -@@ -68,7 +68,10 @@ public: - ScreenSubpixelType, - ScreenAntialiasingEnabled, - NoFontHinting, -- AtspiBus -+ AtspiBus, -+ -+ // Patch: Backport compositing manager check from Qt 5.7 -+ CompositingEnabled - }; - - QXcbNativeInterface(); -diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp -index bc2de89..aa8f8df 100644 ---- a/src/widgets/dialogs/qfiledialog.cpp -+++ b/src/widgets/dialogs/qfiledialog.cpp -@@ -1200,6 +1200,15 @@ QList QFileDialogPrivate::userSelectedFiles() const - return files; - } - -+// Patch: Adding select-by-url for Windows file dialog. -+QByteArray QFileDialogPrivate::userSelectedRemoteContent() const -+{ -+ if (nativeDialogInUse) -+ return selectedRemoteContent_sys(); -+ -+ return QByteArray(); -+} -+ - QStringList QFileDialogPrivate::addDefaultSuffixToFiles(const QStringList &filesToFix) const - { - QStringList files; -@@ -1267,6 +1276,14 @@ QStringList QFileDialog::selectedFiles() const - return files; - } - -+// Patch: Adding select-by-url for Windows file dialog. -+QByteArray QFileDialog::selectedRemoteContent() const -+{ -+ Q_D(const QFileDialog); -+ -+ return d->userSelectedRemoteContent(); -+} -+ - /*! - 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/src/widgets/dialogs/qfiledialog.h b/src/widgets/dialogs/qfiledialog.h -index ffe49a2..42dc563 100644 ---- a/src/widgets/dialogs/qfiledialog.h -+++ b/src/widgets/dialogs/qfiledialog.h -@@ -108,6 +108,9 @@ public: - void selectFile(const QString &filename); - QStringList selectedFiles() const; - -+ // Patch: Adding select-by-url for Windows file dialog. -+ QByteArray selectedRemoteContent() const; -+ - void selectUrl(const QUrl &url); - QList selectedUrls() const; - -diff --git a/src/widgets/dialogs/qfiledialog_p.h b/src/widgets/dialogs/qfiledialog_p.h -index f610e46..547a646 100644 ---- a/src/widgets/dialogs/qfiledialog_p.h -+++ b/src/widgets/dialogs/qfiledialog_p.h -@@ -123,6 +123,10 @@ public: - static QString initialSelection(const QUrl &path); - QStringList typedFiles() const; - QList userSelectedFiles() const; -+ -+ // Patch: Adding select-by-url for Windows file dialog. -+ QByteArray userSelectedRemoteContent() const; -+ - QStringList addDefaultSuffixToFiles(const QStringList &filesToFix) const; - QList addDefaultSuffixToUrls(const QList &urlsToFix) const; - bool removeDirectory(const QString &path); -@@ -256,6 +260,10 @@ public: - QUrl directory_sys() const; - void selectFile_sys(const QUrl &filename); - QList selectedFiles_sys() const; -+ -+ // Patch: Adding select-by-url for Windows file dialog. -+ QByteArray selectedRemoteContent_sys() const; -+ - void setFilter_sys(); - void selectNameFilter_sys(const QString &filter); - QString selectedNameFilter_sys() const; -@@ -393,6 +401,14 @@ inline QList QFileDialogPrivate::selectedFiles_sys() const - return QList(); - } - -+// Patch: Adding select-by-url for Windows file dialog. -+inline QByteArray QFileDialogPrivate::selectedRemoteContent_sys() const -+{ -+ if (QPlatformFileDialogHelper *helper = platformFileDialogHelper()) -+ return helper->selectedRemoteContent(); -+ return QByteArray(); -+} -+ - inline void QFileDialogPrivate::setFilter_sys() - { - if (QPlatformFileDialogHelper *helper = platformFileDialogHelper()) -diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp -index b1d80d7..42e32fd 100644 ---- a/src/widgets/kernel/qwidget.cpp -+++ b/src/widgets/kernel/qwidget.cpp -@@ -5138,6 +5138,17 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset, - return; // Fully transparent. - - Q_D(QWidget); -+ -+ // Patch: save and restore dirtyOpaqueChildren field. -+ // -+ // Just like in QWidget::grab() this field should be restored -+ // after the d->render() call, because it will be set to 1 and -+ // opaqueChildren field will be filled with empty region in -+ // case the widget is hidden (because all the opaque children -+ // will be skipped in isVisible() check). -+ // -+ const bool oldDirtyOpaqueChildren = d->dirtyOpaqueChildren; -+ - const bool inRenderWithPainter = d->extra && d->extra->inRenderWithPainter; - const QRegion toBePainted = !inRenderWithPainter ? d->prepareToRender(sourceRegion, renderFlags) - : sourceRegion; -@@ -5159,6 +5170,10 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset, - if (!inRenderWithPainter && (opacity < 1.0 || (target->devType() == QInternal::Printer))) { - d->render_helper(painter, targetOffset, toBePainted, renderFlags); - d->extra->inRenderWithPainter = inRenderWithPainter; -+ -+ // Patch: save and restore dirtyOpaqueChildren field. -+ d->dirtyOpaqueChildren = oldDirtyOpaqueChildren; -+ - return; - } - -@@ -5190,6 +5205,9 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset, - d->setSharedPainter(oldPainter); - - d->extra->inRenderWithPainter = inRenderWithPainter; -+ -+ // Patch: save and restore dirtyOpaqueChildren field. -+ d->dirtyOpaqueChildren = oldDirtyOpaqueChildren; - } - - static void sendResizeEvents(QWidget *target) -@@ -8769,7 +8787,8 @@ bool QWidget::event(QEvent *event) - case QEvent::KeyPress: { - QKeyEvent *k = (QKeyEvent *)event; - bool res = false; -- if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) { //### Add MetaModifier? -+ // Patch: Enable Ctrl+Tab and Ctrl+Shift+Tab / Ctrl+Backtab handle in-app. -+ 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/src/widgets/util/qsystemtrayicon.cpp b/src/widgets/util/qsystemtrayicon.cpp -index 704142f..7c4340e 100644 ---- a/src/widgets/util/qsystemtrayicon.cpp -+++ b/src/widgets/util/qsystemtrayicon.cpp -@@ -709,6 +709,10 @@ void QSystemTrayIconPrivate::updateMenu_sys_qpa() - if (menu) { - addPlatformMenu(menu); - qpa_sys->updateMenu(menu->platformMenu()); -+ -+ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). -+ } else { -+ qpa_sys->updateMenu(nullptr); - } - } - -diff --git a/src/widgets/widgets/qabstractscrollarea.cpp b/src/widgets/widgets/qabstractscrollarea.cpp -index 2e2a042..472e377 100644 ---- a/src/widgets/widgets/qabstractscrollarea.cpp -+++ b/src/widgets/widgets/qabstractscrollarea.cpp -@@ -640,15 +640,22 @@ scrolling range. - QSize QAbstractScrollArea::maximumViewportSize() const - { - Q_D(const QAbstractScrollArea); -- int hsbExt = d->hbar->sizeHint().height(); -- int vsbExt = d->vbar->sizeHint().width(); -+ // Patch: Count the sizeHint of the bar only if it is displayed. -+ //int hsbExt = d->hbar->sizeHint().height(); -+ //int vsbExt = d->vbar->sizeHint().width(); - - int f = 2 * d->frameWidth; - QSize max = size() - QSize(f + d->left + d->right, f + d->top + d->bottom); -- if (d->vbarpolicy == Qt::ScrollBarAlwaysOn) -+ -+ // Patch: Count the sizeHint of the bar only if it is displayed. -+ if (d->vbarpolicy == Qt::ScrollBarAlwaysOn) { -+ int vsbExt = d->vbar->sizeHint().width(); - max.rwidth() -= vsbExt; -- if (d->hbarpolicy == Qt::ScrollBarAlwaysOn) -+ } -+ if (d->hbarpolicy == Qt::ScrollBarAlwaysOn) { -+ int hsbExt = d->hbar->sizeHint().height(); - max.rheight() -= hsbExt; -+ } - return max; - } - -diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp -index daf9f00..57499dc 100644 ---- a/src/widgets/widgets/qwidgetlinecontrol.cpp -+++ b/src/widgets/widgets/qwidgetlinecontrol.cpp -@@ -40,6 +40,11 @@ - #include - #include - #include -+ -+// Patch: Enable Ctrl+key and Ctrl+Shift+key in all locales except German. -+// See https://github.com/telegramdesktop/tdesktop/pull/1185. -+#include -+ - #ifndef QT_NO_ACCESSIBILITY - #include "qaccessible.h" - #endif -@@ -1882,11 +1887,21 @@ void QWidgetLineControl::processKeyEvent(QKeyEvent* event) - } - - // QTBUG-35734: ignore Ctrl/Ctrl+Shift; accept only AltGr (Alt+Ctrl) on German keyboards -- if (unknown && !isReadOnly() -- && event->modifiers() != Qt::ControlModifier -- && event->modifiers() != (Qt::ControlModifier | Qt::ShiftModifier)) { -+ -+ // Patch: Enable Ctrl+key and Ctrl+Shift+key in all locales except German. -+ // See https://github.com/telegramdesktop/tdesktop/pull/1185. -+ bool skipCtrlAndCtrlShift = false; -+ if (QGuiApplication::inputMethod()->locale().language() == QLocale::German) { -+ if (event->modifiers() == Qt::ControlModifier -+ || event->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { -+ skipCtrlAndCtrlShift = true; -+ } -+ } -+ if (unknown && !isReadOnly() && !skipCtrlAndCtrlShift) { - QString t = event->text(); -- if (!t.isEmpty() && t.at(0).isPrint()) { -+ -+ // Patch: Enable ZWJ and ZWNJ characters to be in text input. -+ 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/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp -index deca002..8a2023f 100644 ---- a/src/widgets/widgets/qwidgettextcontrol.cpp -+++ b/src/widgets/widgets/qwidgettextcontrol.cpp -@@ -71,6 +71,11 @@ - #include - #include - #include -+ -+// Patch: Enable Ctrl+key and Ctrl+Shift+key in all locales except German. -+// See https://github.com/telegramdesktop/tdesktop/pull/1185. -+#include -+ - #include - #include - #include -@@ -1343,13 +1348,24 @@ void QWidgetTextControlPrivate::keyPressEvent(QKeyEvent *e) - process: - { - // QTBUG-35734: ignore Ctrl/Ctrl+Shift; accept only AltGr (Alt+Ctrl) on German keyboards -- if (e->modifiers() == Qt::ControlModifier -- || e->modifiers() == (Qt::ShiftModifier | Qt::ControlModifier)) { -+ -+ // Patch: Enable Ctrl+key and Ctrl+Shift+key in all locales except German. -+ // See https://github.com/telegramdesktop/tdesktop/pull/1185. -+ bool skipCtrlAndCtrlShift = false; -+ if (QGuiApplication::inputMethod()->locale().language() == QLocale::German) { -+ if (e->modifiers() == Qt::ControlModifier -+ || e->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { -+ skipCtrlAndCtrlShift = true; -+ } -+ } -+ if (skipCtrlAndCtrlShift) { - e->ignore(); - return; - } - QString text = e->text(); -- if (!text.isEmpty() && (text.at(0).isPrint() || text.at(0) == QLatin1Char('\t'))) { -+ -+ // Patch: Enable ZWJ and ZWNJ characters to be in text input. -+ 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/Telegram/Resources/art/favicon.ico b/Telegram/Resources/art/favicon.ico index 5c23320d6..4bf1d3057 100644 Binary files a/Telegram/Resources/art/favicon.ico and b/Telegram/Resources/art/favicon.ico differ diff --git a/Telegram/Resources/art/icon128.png b/Telegram/Resources/art/icon128.png index 0a2c3b969..af477568c 100644 Binary files a/Telegram/Resources/art/icon128.png and b/Telegram/Resources/art/icon128.png differ diff --git a/Telegram/Resources/art/icon128@2x.png b/Telegram/Resources/art/icon128@2x.png index 4a7bbb4e4..96d9e0440 100644 Binary files a/Telegram/Resources/art/icon128@2x.png and b/Telegram/Resources/art/icon128@2x.png differ diff --git a/Telegram/Resources/art/icon16.png b/Telegram/Resources/art/icon16.png index a3553a4bc..325119785 100644 Binary files a/Telegram/Resources/art/icon16.png and b/Telegram/Resources/art/icon16.png differ diff --git a/Telegram/Resources/art/icon16@2x.png b/Telegram/Resources/art/icon16@2x.png index 32b6a5686..fa187b1d5 100644 Binary files a/Telegram/Resources/art/icon16@2x.png and b/Telegram/Resources/art/icon16@2x.png differ diff --git a/Telegram/Resources/art/icon256.ico b/Telegram/Resources/art/icon256.ico index 3a53b3b51..72a1d5195 100644 Binary files a/Telegram/Resources/art/icon256.ico and b/Telegram/Resources/art/icon256.ico differ diff --git a/Telegram/Resources/art/icon256.png b/Telegram/Resources/art/icon256.png index 2e818f129..96d9e0440 100644 Binary files a/Telegram/Resources/art/icon256.png and b/Telegram/Resources/art/icon256.png differ diff --git a/Telegram/Resources/art/icon256@2x.png b/Telegram/Resources/art/icon256@2x.png index dc2da2b33..c7bfc97e6 100644 Binary files a/Telegram/Resources/art/icon256@2x.png and b/Telegram/Resources/art/icon256@2x.png differ diff --git a/Telegram/Resources/art/icon32.png b/Telegram/Resources/art/icon32.png index 231c1e335..fa187b1d5 100644 Binary files a/Telegram/Resources/art/icon32.png and b/Telegram/Resources/art/icon32.png differ diff --git a/Telegram/Resources/art/icon32@2x.png b/Telegram/Resources/art/icon32@2x.png index c4e635afe..765ec721d 100644 Binary files a/Telegram/Resources/art/icon32@2x.png and b/Telegram/Resources/art/icon32@2x.png differ diff --git a/Telegram/Resources/art/icon48.png b/Telegram/Resources/art/icon48.png index ff2b2c759..4eafc1bd2 100644 Binary files a/Telegram/Resources/art/icon48.png and b/Telegram/Resources/art/icon48.png differ diff --git a/Telegram/Resources/art/icon48@2x.png b/Telegram/Resources/art/icon48@2x.png index c2d9bb58c..8eacb7910 100644 Binary files a/Telegram/Resources/art/icon48@2x.png and b/Telegram/Resources/art/icon48@2x.png differ diff --git a/Telegram/Resources/art/icon512.png b/Telegram/Resources/art/icon512.png index 7dc492002..c7bfc97e6 100644 Binary files a/Telegram/Resources/art/icon512.png and b/Telegram/Resources/art/icon512.png differ diff --git a/Telegram/Resources/art/icon512@2x.png b/Telegram/Resources/art/icon512@2x.png deleted file mode 100644 index 59ed2b9ab..000000000 Binary files a/Telegram/Resources/art/icon512@2x.png and /dev/null differ diff --git a/Telegram/Resources/art/icon64.png b/Telegram/Resources/art/icon64.png index b4111e8db..765ec721d 100644 Binary files a/Telegram/Resources/art/icon64.png and b/Telegram/Resources/art/icon64.png differ diff --git a/Telegram/Resources/art/icon64@2x.png b/Telegram/Resources/art/icon64@2x.png index 0a2c3b969..af477568c 100644 Binary files a/Telegram/Resources/art/icon64@2x.png and b/Telegram/Resources/art/icon64@2x.png differ diff --git a/Telegram/Resources/art/icon_green.png b/Telegram/Resources/art/icon_green.png deleted file mode 100644 index d84881e26..000000000 Binary files a/Telegram/Resources/art/icon_green.png and /dev/null differ diff --git a/Telegram/Resources/art/iconbig_green.png b/Telegram/Resources/art/iconbig_green.png deleted file mode 100644 index 382a9c962..000000000 Binary files a/Telegram/Resources/art/iconbig_green.png and /dev/null differ diff --git a/Telegram/Resources/art/logo_256.png b/Telegram/Resources/art/logo_256.png index 2e818f129..96d9e0440 100644 Binary files a/Telegram/Resources/art/logo_256.png and b/Telegram/Resources/art/logo_256.png differ diff --git a/Telegram/Resources/art/logo_256_no_margin.png b/Telegram/Resources/art/logo_256_no_margin.png index 1a94181b9..eef78bd3e 100644 Binary files a/Telegram/Resources/art/logo_256_no_margin.png and b/Telegram/Resources/art/logo_256_no_margin.png differ diff --git a/Telegram/Resources/basic.style b/Telegram/Resources/basic.style index a11084570..c0b64502b 100644 --- a/Telegram/Resources/basic.style +++ b/Telegram/Resources/basic.style @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// using "colors.palette"; TextPalette { diff --git a/Telegram/Resources/etc/qt_linux.conf b/Telegram/Resources/etc/qt_linux.conf deleted file mode 100644 index 6d80862b5..000000000 --- a/Telegram/Resources/etc/qt_linux.conf +++ /dev/null @@ -1,2 +0,0 @@ -[Paths] -Libraries=:/gui/art diff --git a/Telegram/Resources/langs/de.lproj/Localizable.strings b/Telegram/Resources/langs/de.lproj/Localizable.strings index affee91bc..d40139780 100644 --- a/Telegram/Resources/langs/de.lproj/Localizable.strings +++ b/Telegram/Resources/langs/de.lproj/Localizable.strings @@ -1,17 +1,22 @@ -/* -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 -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// diff --git a/Telegram/Resources/langs/download.sh b/Telegram/Resources/langs/download.sh deleted file mode 100755 index 92f1ef1db..000000000 --- a/Telegram/Resources/langs/download.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env bash -set -e -FullExecPath=$PWD -pushd `dirname $0` > /dev/null -FullScriptPath=`pwd` -popd > /dev/null - -if [ ! -d "$FullScriptPath/../../../../TelegramPrivate" ]; then - echo "" - echo "This script is for building the production version of Telegram Desktop." - echo "" - echo "For building custom versions please visit the build instructions page at:" - echo "https://github.com/telegramdesktop/tdesktop/#build-instructions" - exit -fi - -Error () { - cd $FullExecPath - echo "$1" - exit 1 -} - -cd $FullScriptPath/../../../../ -while IFS='' read -r line || [[ -n "$line" ]]; do - tx pull -f -l $line --minimum-perc=100 -done < tdesktop/Telegram/Resources/langs/list -cd translations/telegram-desktop.langstrings/ -for file in *.strings; do - iconv -f "UTF-16LE" -t "UTF-8" "$file" > "../../tdesktop/Telegram/Resources/langs/lang_$file.tmp" - awk '{ if (NR==1) sub(/^\xef\xbb\xbf/,""); sub(/ /,""); print }' "../../tdesktop/Telegram/Resources/langs/lang_$file.tmp" > "../../tdesktop/Telegram/Resources/langs/lang_$file" - rm "../../tdesktop/Telegram/Resources/langs/lang_$file.tmp" -done - -cd $FullExecPath diff --git a/Telegram/Resources/langs/en.lproj/Localizable.strings b/Telegram/Resources/langs/en.lproj/Localizable.strings index affee91bc..d40139780 100644 --- a/Telegram/Resources/langs/en.lproj/Localizable.strings +++ b/Telegram/Resources/langs/en.lproj/Localizable.strings @@ -1,17 +1,22 @@ -/* -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 -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// diff --git a/Telegram/Resources/langs/es.lproj/Localizable.strings b/Telegram/Resources/langs/es.lproj/Localizable.strings index affee91bc..d40139780 100644 --- a/Telegram/Resources/langs/es.lproj/Localizable.strings +++ b/Telegram/Resources/langs/es.lproj/Localizable.strings @@ -1,17 +1,22 @@ -/* -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 -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// diff --git a/Telegram/Resources/langs/it.lproj/Localizable.strings b/Telegram/Resources/langs/it.lproj/Localizable.strings index affee91bc..d40139780 100644 --- a/Telegram/Resources/langs/it.lproj/Localizable.strings +++ b/Telegram/Resources/langs/it.lproj/Localizable.strings @@ -1,17 +1,22 @@ -/* -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 -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// diff --git a/Telegram/Resources/langs/ko.lproj/Localizable.strings b/Telegram/Resources/langs/ko.lproj/Localizable.strings index affee91bc..d40139780 100644 --- a/Telegram/Resources/langs/ko.lproj/Localizable.strings +++ b/Telegram/Resources/langs/ko.lproj/Localizable.strings @@ -1,17 +1,22 @@ -/* -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 -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index c5e569340..ab6751259 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1,23 +1,31 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// +"appname" = "Kepka"; +"lng_url_about" = "https://github.com/procxx/kepka"; +"lng_url_changelog" = "https://github.com/procxx/kepka/releases"; + +// basic lang info + "lng_language_name" = "English"; "lng_switch_to_this" = "Switch to English"; @@ -31,10 +39,10 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org "lng_disable_notifications_from_tray" = "Disable notifications"; "lng_enable_notifications_from_tray" = "Enable notifications"; -"lng_open_from_tray" = "Open Telegram"; +"lng_open_from_tray" = "Open {appname}"; "lng_minimize_to_tray" = "Minimize to tray"; -"lng_quit_from_tray" = "Quit Telegram"; -"lng_tray_icon_text" = "Telegram is still running here,\nyou can change this from settings page.\nIf this icon disappears from tray menu,\nyou can drag it here from hidden icons."; +"lng_quit_from_tray" = "Quit {appname}"; +"lng_tray_icon_text" = "{appname} is still running here,\nyou can change this from settings page.\nIf this icon disappears from tray menu,\nyou can drag it here from hidden icons."; "lng_month1" = "January"; "lng_month2" = "February"; @@ -157,7 +165,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org "lng_pinned_unpin" = "Unpin"; "lng_pinned_notify" = "Notify all members"; -"lng_intro_about" = "Welcome to the official Telegram Desktop app.\nIt's fast and secure."; +"lng_intro_about" = "Welcome to the {appname}, unofficial Telegram app.\nIt's fast and secure."; "lng_start_msgs" = "START MESSAGING"; "lng_intro_next" = "NEXT"; @@ -307,6 +315,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org "lng_settings_section_chat_settings" = "Chat Settings"; "lng_settings_replace_emojis" = "Replace emoji"; +"lng_settings_message_formatting" = "Enable typographic replacements (<< into «, -- into –, etc.)"; "lng_settings_view_emojis" = "View list"; "lng_settings_send_enter" = "Send by Enter"; "lng_settings_send_ctrlenter" = "Send by Ctrl+Enter"; @@ -1135,8 +1144,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org "lng_box_leave" = "Leave"; "lng_about_version" = "version {version}"; -"lng_about_text_1" = "Official free messaging app based on [a href=\"https://core.telegram.org/api\"]Telegram API[/a]\nfor speed and security."; -"lng_about_text_2" = "This software is licensed under [a href=\"https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\"]GNU GPL[/a] version 3.\nSource code is available on [a href=\"https://github.com/telegramdesktop/tdesktop\"]GitHub[/a]."; +"lng_about_text_1" = "Unofficial free messaging app based on [a href=\"https://core.telegram.org/api\"]Telegram API[/a]\nfor speed and security."; +"lng_about_text_2" = "This software is licensed under [a href=\"https://github.com/procxx/kepka/blob/dev/LICENSE\"]GNU GPL[/a] version 3.\nSource code is available on [a href=\"https://github.com/procxx/kepka\"]GitHub[/a]."; "lng_about_text_3" = "Visit {faq_open}Telegram FAQ{faq_close} for more info."; "lng_about_done" = "Done"; diff --git a/Telegram/Resources/langs/lang_de.strings b/Telegram/Resources/langs/lang_de.strings index 6ca21d887..3269d13a8 100644 --- a/Telegram/Resources/langs/lang_de.strings +++ b/Telegram/Resources/langs/lang_de.strings @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// "lng_language_name" = "Deutsch"; "lng_switch_to_this" = "Auf Deutsch zurücksetzen"; diff --git a/Telegram/Resources/langs/lang_es.strings b/Telegram/Resources/langs/lang_es.strings index 034620f27..816320c4b 100644 --- a/Telegram/Resources/langs/lang_es.strings +++ b/Telegram/Resources/langs/lang_es.strings @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// "lng_language_name" = "Español"; "lng_switch_to_this" = "Cambiar a español"; diff --git a/Telegram/Resources/langs/lang_it.strings b/Telegram/Resources/langs/lang_it.strings index 3f966fded..bc08097db 100644 --- a/Telegram/Resources/langs/lang_it.strings +++ b/Telegram/Resources/langs/lang_it.strings @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// "lng_language_name" = "Italiano"; "lng_switch_to_this" = "Passa all'Italiano"; diff --git a/Telegram/Resources/langs/lang_ko.strings b/Telegram/Resources/langs/lang_ko.strings index 172ee2cbc..ecb12835e 100644 --- a/Telegram/Resources/langs/lang_ko.strings +++ b/Telegram/Resources/langs/lang_ko.strings @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// "lng_language_name" = "영어"; "lng_switch_to_this" = "영어로 변경"; diff --git a/Telegram/Resources/langs/lang_nl.strings b/Telegram/Resources/langs/lang_nl.strings index 093a3eacf..c702457ab 100644 --- a/Telegram/Resources/langs/lang_nl.strings +++ b/Telegram/Resources/langs/lang_nl.strings @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// "lng_language_name" = "Nederlands"; "lng_switch_to_this" = "Overschakelen naar Nederlands"; diff --git a/Telegram/Resources/langs/lang_pt_BR.strings b/Telegram/Resources/langs/lang_pt_BR.strings index 6660a1abc..e574f329f 100644 --- a/Telegram/Resources/langs/lang_pt_BR.strings +++ b/Telegram/Resources/langs/lang_pt_BR.strings @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// "lng_language_name" = "Português (Brasil)"; "lng_switch_to_this" = "Trocar para Português (Brasil)"; diff --git a/Telegram/Resources/langs/nl.lproj/Localizable.strings b/Telegram/Resources/langs/nl.lproj/Localizable.strings index affee91bc..d40139780 100644 --- a/Telegram/Resources/langs/nl.lproj/Localizable.strings +++ b/Telegram/Resources/langs/nl.lproj/Localizable.strings @@ -1,17 +1,22 @@ -/* -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 -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// diff --git a/Telegram/Resources/langs/pt-BR.lproj/Localizable.strings b/Telegram/Resources/langs/pt-BR.lproj/Localizable.strings index affee91bc..d40139780 100644 --- a/Telegram/Resources/langs/pt-BR.lproj/Localizable.strings +++ b/Telegram/Resources/langs/pt-BR.lproj/Localizable.strings @@ -1,17 +1,22 @@ -/* -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 -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// diff --git a/Telegram/Resources/langs/upload.sh b/Telegram/Resources/langs/upload.sh deleted file mode 100755 index e20706990..000000000 --- a/Telegram/Resources/langs/upload.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash -set -e -FullExecPath=$PWD -pushd `dirname $0` > /dev/null -FullScriptPath=`pwd` -popd > /dev/null - -if [ ! -d "$FullScriptPath/../../../../TelegramPrivate" ]; then - echo "" - echo "This script is for building the production version of Telegram Desktop." - echo "" - echo "For building custom versions please visit the build instructions page at:" - echo "https://github.com/telegramdesktop/tdesktop/#build-instructions" - exit -fi - -Error () { - cd $FullExecPath - echo "$1" - exit 1 -} - -cd $FullScriptPath/../../../../ -while IFS='' read -r line || [[ -n "$line" ]]; do - tx pull -f -l $line -done < tdesktop/Telegram/Resources/langs/list -tx push -s - -cd $FullExecPath diff --git a/Telegram/Resources/qrc/qmime/freedesktop.org.xml b/Telegram/Resources/qrc/qmime/freedesktop.org.xml deleted file mode 100644 index 1f4742875..000000000 --- a/Telegram/Resources/qrc/qmime/freedesktop.org.xml +++ /dev/null @@ -1,34056 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -]> - - - ATK inset - شكل ATK - Ustaŭka ATK - Сбор — ATK - inset ATK - Vložka ATK - ATK-indsættelse - ATK-Inset - ATK inset - inserción ATK - ATK sartzapena - ATK-osio - ATK innskot - encart ATK - intlis ATK - conxunto ATK - תוספת ATK - ATK betét - Inset ATK - Inset ATK - ATK インセット - ATK беті - ATK inset - ATK inset - ATK ielaidums - ATK-innsats - ATK-invoegsel - ATK-innskot - Wstawka ATK - Conjunto de entrada do ATK - Inset ATK - вкладка ATK - Vložka ATK - Vložka ATK - Inset ATK - ATK-inlägg - вкладка ATK - Bộ dát ATK - ATK 嵌入对象 - ATK - Andrew Toolkit - - - - - electronic book document - مستند كتاب إلكتروني - elektronnaja kniha - Документ — електронна книга - document de llibre electrònic - Dokument elektronické knihy - elektronisk bogdokument - Elektronisches Buch - έγγραφο ηλεκτρονικού βιβλίου - electronic book document - documento de libro electrónico - liburu elektronikoaren dokumentua - elektroninen kirja - elektroniskbóka skjal - document livre électronique - leabhar leictreonach - documento de libro electrónico - מסמך מסוג ספר אלקטרוני - dokument elektroničke knjige - elektronikus könyvdokumentum - dokumen buku elektronik - Documento libro elettronico - 電子ブックドキュメント - электронды кітабы - 전자책 문서 - elektroninės knygos dokumentas - elektroniskās grāmatas dokuments - elektronisch boek - elektronisk bok-dokument - Dokument książki elektronicznej - Documento de livro eletrônico - document carte electronică - электронная книга - Dokument elektronickej knihy - dokument elektronske knjige - Dokument libri elektronik - elektroniskt bokdokument - elektronik kitap belgesi - документ електронної книги - tài liệu cuốn sách điện tử - 电子书文档 - 電子書文件 - - - - - - - - - - - - - - Adobe Illustrator document - مستند أدوبي المصور - Dakument Adobe Illustrator - Документ — Adobe Illustrator - document d'Adobe Illustrator - Dokument Adobe Illustrator - Adobe Illustrator-dokument - Adobe-Illustrator-Dokument - έγγραφο Adobe Illustrator - Adobe Illustrator document - dokumento de Adobe Illustrator - documento de Adobe Illustrator - Adobe Illustrator dokumentua - Adobe Illustrator -asiakirja - Adobe Illustrator skjal - document Adobe Illustrator - cáipéis Adobe Illustrator - documento de Adobe Ilustrator - מסמך Adobe Ill - Adobe Illustrator dokument - Adobe Illustrator-dokumentum - Dokumen Adobe Illustrator - Documento Adobe Illustrator - Adobe Illustrator ドキュメント - Adobe Illustrator-ის დოკუმენტი - Adobe Illustrator құжаты - 어도비 일러스트레이터 문서 - Adobe Illustrator dokumentas - Adobe Illustrator dokuments - Dokumen Adobe Illustrator - Adobe Illustrator-dokument - Adobe Illustrator-document - Adobe Illustrator-dokument - Dokument Adobe Illustrator - documento Adobe Illustrator - Documento do Adobe Illustrator - Document Adobe Illustrator - документ Adobe Illustrator - Dokument Adobe Illustrator - Dokument Adobe Illustrator - Dokument Adobe Illustrator - Адоуби Илустратор документ - Adobe Illustrator-dokument - документ Adobe Illustrator - Tài liệu Adobe Illustrator - Adobe Illustrator 文档 - Adobe Illustrator 文件 - - - - - Macintosh BinHex-encoded file - ملف Macintosh BinHex مشفر - Macintosh BinHex-kodlanmış fayl - Fajł Macintosh, BinHex-zakadavany - Файл — кодиран във формат BinHex за Macintosh - fitxer codificat BinHex de Macintosh - Soubor kódovaný pomocí Macintosh BinHex - Ffeil BinHex-amgodwyd Macintosh - Macintosh BinHex-kodet fil - Macintosh-Datei (BinHex-kodiert) - αρχείο Macintosh κωδικοποίησης BinHex - Macintosh BinHex-encoded file - dosiero kodigita laŭ Macintosh BinHex - archivo Macintosh codificado con BinHex - Macintosh BinHex-ekin kodetutako fitxategia - Macintosh BinHex -koodattu tiedosto - Macintosh BinHex-bronglað fíla - fichier codé Macintosh BinHex - comhad ionchódaithe le Macintosh BinHex - ficheiro de Macintosh codificado con BinHex - קובץ מסוג Macintosh BinHex-encoded - Macintosh BinHex-kodirana datoteka - Macintosh BinHex kódolású fájl - Berkas tersandi Macintosh BinHex - File Macintosh codificato BinHex - Macintosh BinHex エンコードファイル - Macintosh BinHex кодталған файлы - 매킨토시 BinHex 인코딩된 압축 파일 - Macintosh BinHex-encoded failas - Macintosh BinHex-kodēts datne - Fail terenkod-BinHex Macintosh - Macintosh BinHe-kodet arkiv - Macintosh BinHex-gecodeerd bestand - Macintosh BinHex-koda fil - Zakodowany w BinHex plik Macintosh - ficheiro codificado em BinHex de Macintosh - Arquivo do Macintosh codificado com BinHex - Fișier codat Macintosh BinHex - файл (закодированный Macintosh BinHex) - Súbor kódovaný pomocou Macintosh BinHex - Kodirana datoteka Macintosh (BinHex) - File Macintosh i kodifikuar BinHex - Мекинтош BinHex-encoded датотека - Macintosh BinHex-kodad fil - файл закодований Macintosh BinHex - Tập tin đã mã hoá BinHex của Macintosh - Macintosh BinHex 编码的文件 - Macintosh BinHex 編碼檔 - - - - - - - Mathematica Notebook - مذكرة رياضيات - Natatnik Mathematica - Тетрадка — Mathematica - llibreta de notes de Mathematica - Sešit Mathematica - Mathematica Notebook - Mathematica-Dokument - σημειωματάριο Mathematica - Mathematica Notebook - notebook de Mathematica - Mathematica Notebook - Mathematica-muistilehtiö - Mathematica skriviblokkur - carnet de notes Mathematica - leabhar nótaí Mathematica - notebook de Mathematica - מחברת מתמטיקה - Mathematica notesz - Mathematica Notebook - Notebook Mathematica - Mathematica ノートブック - Mathematica Notebook - Mathematica 노트북 - Mathematica užrašinė - Mathematica bloknots - Mathematica notisblokk - Mathematica-notitieboek - Mathematica-notatbok - Notatnik Mathematica - Caderno do Mathematica - Carnețel Mathematica - Mathematica Notebook - Zošit Mathematica - Datoteka dokumenta Mathematica - Notebook matematike - Mathematica Notebook-dokument - математичний записник - Cuốn vở Mathematica - Mathematica 记事 - Mathematica Notebook - - - - - - - - - - - - MathML document - مستند MathML - MathML sənədi - Dakument MathML - Документ — MathML - document de MathML - Dokument MathML - Dogfen MathML - MathML-dokument - MathML-Dokument - έγγραφο MathML - MathML document - MathML-dokumento - documento MathML - MathML dokumentua - MathML-asiakirja - MathML skjal - document MathML - cáipéis MathML - documento de MathML - מסמך MathML - MathML dokument - MathML-dokumentum - Dokumen MathML - Documento MathML - MathML ドキュメント - MathML-ის დოკუმენტი - MathML құжаты - MathML 문서 - MathML dokumentas - MathML dokuments - Dokumen MathML - MathML-dokument - MathML-document - MathML-dokument - Dokument MathML - documento MathML - Documento do MathML - Document MathML - документ MathML - Dokument MathML - Dokument MathML - Dokument MathML - MathML документ - MathML-dokument - MathML belgesi - документ MathML - Tài liệu MathML - MathML 文档 - MathML 文件 - MathML - Mathematical Markup Language - - - - - - - mailbox file - ملف صندوق البريد - fajł paštovaj skryni - Файл — Mailbox - fitxer mailbox - Soubor mailbox - postkassefil - Mailbox-Datei - αρχείο mailbox - mailbox file - archivo de buzón de correo - mailbox fitxategia - mailbox-tiedosto - postkassafíla - fichier boîte aux lettres - comhad bhosca poist - ficheiro de caixa de correo - קובץ תיבת-דואר - datoteka poštanskog sandučića - mailbox fájl - berkas kotak surat - File mailbox - メールボックスファイル - пошта жәшігінің файлы - 메일함 파일 - pašto dėžutės failas - pastkastītes datne - postboksfil - mailbox-bestand - mailbox-fil - Plik poczty (Mailbox) - Arquivo de caixa de correio - fișier căsuță poștală - файл почтового ящика - Súbor mailbox - datoteka poštnega predala - File mailbox - brevlådefil - файл поштової скриньки - tập tin hộp thư - mailbox 文件 - 郵箱檔 - - - - - - - - - Metalink file - ملف ميتالنك - Изтегляне — Metalink - fitxer Metalink - Soubor metalink - Metahenvisningsfil - Metalink-Datei - αρχείο Metalink - Metalink file - Metalink-dosiero - archivo de metaenlace - Metaestekaren fitxategia - Metalink-tiedosto - Metalink fíla - fichier metalink - comhad Metalink - ficheiro Metalink - קובץ Metalink - Metalink fájl - Berkas Metalink - File Metalink - Metalink ファイル - Metalink файлы - Metalink 파일 - Metalink failas - Metalink datne - Metalink bestand - Plik Metalink - Arquivo Metalink - Fișier Metalink - файл Metalink - Súbor Metalink - Datoteka povezave Metalink - Metalink-fil - Metalink dosyası - файл метапосилання - 元链接文件 - Metalink 檔案 - - - - - - - - - Metalink file - ملف ميتالنك - Изтегляне — Metalink - fitxer Metalink - Soubor metalink - Metahenvisningsfil - Metalink-Datei - αρχείο Metalink - Metalink file - Metalink-dosiero - archivo de metaenlace - Metaestekaren fitxategia - Metalink-tiedosto - Metalink fíla - fichier metalink - comhad Metalink - ficheiro Metalink - קובץ Metalink - Metalink fájl - Berkas Metalink - File Metalink - Metalink ファイル - Metalink файлы - Metalink 파일 - Metalink failas - Metalink datne - Metalink bestand - Plik Metalink - Arquivo Metalink - Fișier Metalink - файл Metalink - Súbor Metalink - Datoteka povezave Metalink - Metalink-fil - Metalink dosyası - файл метапосилання - 元链接文件 - Metalink 檔案 - - - - - - - - - unknown - مجهول - nieviadomy - Неизвестен тип - desconegut - Neznámý - ukendt - Unbekannt - άγνωστο - unknown - nekonate - desconocido - ezezaguna - tuntematon - ókent - inconnu - anaithnid - descoñecido - לא ידוע - nepoznato - ismeretlen - tak diketahui - Sconosciuto - 不明 - უცნობი - белгісіз - 알 수 없음 - nežinoma - nezināms - Entah - ukjent - onbekend - ukjend - Nieznany typ - desconhecido - Desconhecido - necunoscut - неизвестно - Neznámy - neznano - Nuk njihet - непознато - okänd - невідомо - không rõ - 未知 - 不明 - - - - ODA document - مستند ODA - ODA sənədi - Dakument ODA - Документ — ODA - document ODA - Dokument ODA - Dogfen ODA - ODA-dokument - ODA-Dokument - έγγραφο ODA - ODA document - ODA-dokumento - documento ODA - ODA dokumentua - ODA-asiakirja - ODA skjal - document ODA - cáipéis ODA - documento ODA - מסמך ODA - ODA dokument - ODA-dokumentum - Dokumen ODA - Documento ODA - ODA ドキュメント - ODA დოკუმენტი - ODA құжаты - ODA 문서 - ODA dokumentas - ODA dokuments - Dokumen ODA - ODA-dokument - ODA-document - ODA-dokument - Dokument ODA - documento ODA - Documento ODA - Document ODA - документ ODA - Dokument ODA - Dokument ODA - Dokument ODA - ODA документ - ODA-dokument - ODA belgesi - документ ODA - Tài liệu ODA - ODA 文档 - ODA 文件 - ODA - Office Document Architecture - - - - - WWF document - Документ — WWF - document WWF - Dokument WWF - WWF-dokument - WWF-Dokument - έγγραφο WWF - WWF document - WWF-dokumento - Documento de WWF - WWF-asiakirja - document WWF - documento de WWF - מסמך WWF - WWF dokument - WWF dokumentum - Dokumen WWF - Documento WWF - WWF 文書 - WWF დოკუმენტი - WWF құжаты - WWF 문서 - WWF dokuments - WWF document - Dokument WWF - Documento WWF - документ WWF - Dokument WWF - WWF-dokument - документ WWF - WWF - WWF 文件 - - - - - - - PDF document - مستند PDF - Dakument PDF - Документ — PDF - document PDF - Dokument PDF - Dogfen PDF - PDF-dokument - PDF-Dokument - έγγραφο PDF - PDF document - PDF-dokumento - documento PDF - PDF dokumentua - PDF-asiakirja - PDF skjal - document PDF - cáipéis PDF - documento PDF - מסמך PDF - PDF-dokumentum - Dokumen PDF - Documento PDF - PDF ドキュメント - PDF құжаты - PDF 문서 - PDF dokumentas - PDF dokuments - Dokumen PDF - PDF-dokument - PDF-document - PDF-dokument - Dokument PDF - documento PDF - Documento PDF - Document PDF - документ PDF - Dokument PDF - Dokument PDF - Dokument PDF - PDF документ - PDF-dokument - PDF belgesi - документ PDF - Tài liệu PDF - PDF 文档 - PDF 文件 - PDF - Portable Document Format - - - - - - - - - - - XSPF playlist - قائمة تشغيل XSPF - Śpis piesień XSPF - Списък за изпълнение — XSPF - llista de reproducció XSPF - Seznam skladeb XSPF - XSPF-afspilningsliste - XSPF-Wiedergabeliste - λίστα αναπαραγωγής XSPF - XSPF playlist - XSPF-ludlisto - lista de reproducción XSPF - XSPF erreprodukzio-zerrenda - XSPF-soittolista - XSPF avspælingarlisti - liste de lecture XSPF - seinmliosta XSPF - lista de reprodución XSPF - רשימת השמעה XSPF - XSPF popis za reprodukciju - XSPF-lejátszólista - Senarai pular XSPF - Scaletta XSPF - XSPF 再生リスト - XSPF ойнау тізімі - XSPF 재생 목록 - XSPF grojaraštis - XSPF repertuārs - XSPF-spilleliste - XSPF-afspeellijst - XSPF-speleliste - Lista odtwarzania XSPF - Lista de reprodução XSPF - Listă XSPF - список воспроизведения XSPF - Zoznam skladieb XSPF - Seznam predvajanja XSPF - Listë titujsh XSPF - XSPF-spellista - список програвання XSPF - Danh mục nhạc XSPF - XSPF 播放列表 - XSPF 播放清單 - XSPF - XML Shareable Playlist Format - - - - - - - - - - - - Microsoft Windows theme pack - حزمة سمات Microsoft Works - Пакет с тема — Microsoft Windows - paquet de temes Windows de Microsoft - Balík motivů Microsoft Windows - Microsoft Windows-temapakke - Themenpaket für Microsoft Windows - θεματικό πάρκο Microsoft Windows - Microsoft Windows theme pack - paquete de tema para Microsoft Windows - Microsoft Windows-en gaiaren paketea - Microsoft Windows -teemapaketti - Microsoft Windows tema pakki - paquet de thèmes Microsoft Windows - paca téamaí Microsoft Windows - paquete de tema de Microsoft Windows - חבילת ערכות נושא של Microsoft Windows - Microsoft Windows paket tema - Microsoft Windows témacsomag - Pak tema Microsoft Windows - Pacchetto temi Microsoft Windows - Microsoft Windows テーマパック - Microsoft Windows-ის თემის შეკვრა - Microsoft Windows тема дестесі - 마이크로소프트 Windows 테마 패키지 - Microsoft Windows temų paketas - Microsoft Windows motīvu paka - Microsoft Windows thema pack - Pakiet motywu Microsoft Windows - Pacote de temas do Microsoft Windows - Pachet de teme Microsoft Windows - пакет темы Microsoft Windows - Balík tém Microsoft Windows - Datoteka teme Microsoft Windows - Microsoft Windows-temapaket - пакунок з темою Microsoft Windows - Microsoft Windows 主题包 - 微軟視窗佈景主題包 - - - - - - AmazonMP3 download file - - - - GSM 06.10 audio - GSM 06.10 سمعي - Аудио — GSM 06.10 - àudio GSM 06.10 - Zvuk GSM 06.10 - GSM 06.10-lyd - GSM-06.10-Audio - ήχος GSM 06.10 - GSM 06.10 audio - sonido GSM 06.10 - GSM 06.10 audioa - GSM 06.10 -ääni - GSM 06.10 ljóður - audio GSM 06.10 - fuaim GSM 06.10 - son de GSM 06.10 - שמע GSM 06.10 - GSM 06.10 audio - GSM 06.10 hang - Audio GSM 06.10 - Audio GSM 06.10 - GSM 06.10 オーディオ - GSM 06.10 აუდიო - GSM 06.10 аудиосы - GSM 06.10 오디오 - GSM 06.10 garso įrašas - GSM 06.10 audio - GSM 06.10 audio - Plik dźwiękowy GSM 06.10 - Áudio GSM 06.10 - GSM 06.10 audio - аудио GSM 06.10 - Zvuk GSM 06.10 - Zvočna datoteka GSM 06.10 - GSM 06.10-ljud - звук GSM 06.10 - Âm thanh GSM 06.10 - GSM 06.10 音频 - GSM 06.10 音訊 - GSM - Global System for Mobile communications - - - - iRiver Playlist - قائمة تشغيل iRiver - Śpis piesień iRiver - Списък за изпълнение — iRiver - llista de reproducció iRiver - Seznam skladeb iRiver - iRiver-afspilningsliste - iRiver-Wiedergabeliste - λίστα αναπαραγωγής iRiver - iRiver Playlist - iRiver-ludlisto - lista de reproducción de iRiver - iRiver erreprodukzio-zerrenda - iRiver-soittolista - iRiver avspælingarlisti - liste de lecture iRiver - seinmliosta iRiver - lista de reprodución de iRiver - רשימת השמעה של iRiver - iRiver popis za reprodukciju - iRiver lejátszólista - iRiver Playlist - Scaletta iRiver - iRiver 再生リスト - iRiver ойнау тізімі - iRiver 재생 목록 - iRiver grojaraštis - iRiver repertuārs - iRiver-spilleliste - iRiver-afspeellijst - iRiver speleliste - Lista odtwarzania iRiver - Lista de reprodução do iRiver - Listă iRiver - список воспроизведения iRiver - Zoznam skladieb iRiver - Seznam predvajanja iRiver - Listë titujsh iRiver - iRiver-spellista - список програвання iRiver - danh mục nhạc iRiver - iRiver 播放列表 - iRiver 播放清單 - - - - - - - PGP/MIME-encrypted message header - ترويسة رسالة PGP/MIME-مشفرة - Zahałovak paviedamleńnia, zašyfravany ŭ PGP/MIME - Заглавна част на шифрирано съобщение — PGP/MIME - capçalera de missatge xifrat amb PGP/MIME - Záhlaví zprávy zašifrované pomocí PGP/MIME - PGP-/MIME-krypteret meddelelseshoved - PGP/MIME-verschlüsselter Nachrichtenkopf - κεφαλίδα μηνύματος κρυπτογραφημένου κατά PGP/MIME - PGP/MIME-encrypted message header - PGP/MIME-ĉifrita ĉapo de mesaĝo - cabecera de mensaje cifrado PGP/MIME - PGP/MIME enkriptatutako mezu-goiburua - PGP/MIME-salattu viestiotsikko - PGP/MIME-encrypted boð tekshøvd - en-tête de message codé PGP/MIME - ceanntásc teachtaireachta ionchódaithe le PGP/MIME - cabeceira de mensaxe cifrado PGP/MIME - כותר של קובץ מוצפן מסוג PGP/MIME - PGP/MIME titkosított üzenetfejléc - Tajuk pesan terenkripsi PGP/MIME - Intestazione messaggio PGP/MIME-encrypted - PGP/MIME 暗号化メッセージヘッダー - PGP/MIME-шифрленген мәлімдеме тақырыптамасы - PGP/MIME으로 암호화된 메시지 헤더 - PGP/MIME užšifruota žinutės antraštė - PGP/MIME-šifrēta ziņas galvene - Pengepala mesej terenkripsi PGP/MIME - PGP/MIME-kryptert meldingshode - PGP/MIME-versleutelde berichtkopregels - PGP/MIME-kryptert meldingshovud - Nagłówek listu zaszyfrowanego PGP/MIME - cabeçalho de mensagem cifrada com PGP/MIME - Cabeçalho de mensagem criptografada PGP/MIME - Antet de mesaj encriptat PGP/MIME - заголовок сообщения, зашифрованный PGP/MIME - Hlavičke správy zašifrovaná pomocou PGP/MIME - Datoteka glave šifriranega sporočila PGP/MIME - Header mesazhi të kriptuar PGP/MIME - ПГП/МИМЕ шифровано заглавље поруке - PGP/MIME-krypterat meddelandehuvud - заголовок шифрованого PGP/MIME повідомлення - Phần đầu thông điệp đã mật mã bằng PGP/MIME - PGP/MIME 加密的信件头 - PGP/MIME 加密訊息標頭 - - - - - - - - - - - PGP keys - مفاتيح PGP - PGP açarları - Klučy PGP - Ключове — PGP - claus PGP - Klíče PGP - Allweddi PGP - PGP-nøgler - PGP-Schlüssel - κλειδιά PGP - PGP keys - PGP-ŝlosiloj - claves PGP - PGP giltzak - PGP-avainrengas - PGP lyklar - clés PGP - eochracha PGP - Chaves PGP - מפתח PGP - PGP-kulcs - Kunci PGP - Chiavi PGP - PGP 鍵 - PGP кілттері - PGP 키 - PGP raktai - PGP atslēgas - Kekunci PGP - PGP-nøkler - PGP-sleutels - PGP-nøkler - Klucze PGP - chaves PGP - Chaves PGP - Chei PGP - ключи PGP - Kľúče PGP - Datoteka ključa PGP - Kyçe PGP - PGP кључ - PGP-nycklar - PGP anahtarları - ключі PGP - Khoá PGP - PGP 密钥 - PGP 鑰匙 - PGP - Pretty Good Privacy - - - - - - - - - - - - - - - - - - detached OpenPGP signature - إمضاء OpenPGP مفصول - adłučany podpis OpenPGP - Отделен подпис — OpenPGP - signatura OpenPGP separada - Oddělený podpis OpenPGP - frigjort OpenPGP-signatur - Isolierte OpenPGP-Signatur - αποκομμένη υπογραφή OpenPGP - detached OpenPGP signature - dekroĉa OpenPGP-subskribo - firma OpenPGP separada - desuzturtako OpenPGP sinadura - erillinen OpenPGP-allekirjoitus - skild OpenPGP undirskrift - signature OpenPGP détachée - síniú OpenPGP scartha - sinatura de OpenPGP independente - חתימת OpenPGP מנותקת - odvojen OpenPGP potpis - leválasztott OpenPGP-aláírás - tanda tangan OpenPGP yang terlepas - Firma staccata OpenPGP - 分離 OpenPGP 署名 - бөлінген OpenPGP қолтаңбасы - 분리된 OpenPGP 서명 - neprisegtas OpenPGP parašas - atvienots OpenPGP paraksts - Tandatangan OpenPGP terlerai - frakoblet OpenPGP-signatur - losse OpenPGP-ondertekening - fråkopla OpenPGP-signatur - Oddzielony podpis OpenPGP - assinatura OpenPGP solta - Assinatura OpenPGP destacada - semnătură OpenPGP detașată - отсоединённая подпись OpenPGP - Oddelený podpis OpenPGP - odpet podpis OpenPGP - Firmë e shkëputur OpenPGP - одвојени ОпенПГП потпис - frikopplad OpenPGP-signatur - відокремлений OpenPGP підпис - chữ ký OpenPGP tách rời - 分离的 OpenPGP 签名 - 分離的 OpenPGP 簽章 - - - - - - - - - - - - - PKCS#7 Message or Certificate - PKCS - Public-Key Cryptography Standards - - - - - - detached S/MIME signature - إمضاء S/MIME مفصول - adłučany podpis S/MIME - Отделен подпис — S/MIME - signatura S/MIME separada - Oddělený podpis S/MIME - frigjort S/MIME-signatur - Isolierte S/MIME-Signatur - αποκομμένη υπογραφή S/MIME - detached S/MIME signature - dekroĉa S/MIME-subskribo - firma S/MIME separada - desuzturtako S/MIME sinadura - erillinen S/MIME-allekirjoitus - skild S/MIME undirskrift - signature S/MIME détachée - síniú S/MIME scartha - sinatura S/MIME independente - חתימת S/MIME מנותקת - odvojen S/MIME potpis - leválasztott S/MIME-aláírás - tanda tangan S/MIME yang terlepas - Firma staccata S/MIME - 分離 S/MIME 署名 - бөлінген S/MIME қолтаңбасы - 분리된 S/MIME 서명 - neprisegtas S/MIME parašas - atvienots S/MIME paraksts - Tandatangan S/MIME terlerai - frakoblet S/MIME-signatur - losse S/MIME-ondertekening - fråkopla S/MIME-signatur - Oddzielony podpis S/MIME - assinatura S/MIME solta - Assinatura S/MIME destacada - semnătură S/MIME detașată - отсоединённая подпись S/MIME - Oddelený podpis S/MIME - odpet podpis S/MIME - Firmë e shkëputur S/MIME - одвојени S/MIME потпис - frikopplad S/MIME-signatur - відокремлений S/MIME підпис - chữ ký S/MIME tách rời - 分离的 S/MIME 签名 - 分離的 S/MIME 簽章 - S/MIME - Secure/Multipurpose Internet Mail Extensions - - - - - - PKCS#8 private key - رزمة الشهادة PKCS#8 - Ключ, частен — PKCS#8 - clau privada PKCS#8 - Soukromý klíč PKCS#8 - PKCS#8-privat nøgle - PKCS#8 Geheimer Schlüssel - ιδιωτικό κλειδί PKCS#8 - PKCS#8 private key - clave privada PCKS#8 - PKCS#8 yksityinen avain - PKCS#8 privatur lykil - clé privée PKCS#8 - eochair phríobháideach PKCS#8 - Chave privada PKCS#8 - מפתח פרטי של PKCS#8 - PKCS#8 személyes kulcs - Kunci privat PKCS#8 - Chiave privata PKCS#8 - PKCS#8 秘密鍵 - PKCS#8 меншік кілті - PKCS#8 개인 키 - PKCS#8 asmeninis raktas - PKCS#8 privātā atslēga - PKCS#8 private sleutel - Klucz prywatny PKCS#8 - Chave privada PKCS#8 - Cheie privată PKCS#8 - личный ключ PKCS#8 - Súkromný kľúč PKCS#8 - Datoteka osebnega ključa PKCS#8 - Privat PKCS#8-nyckel - закритий ключ PKCS#8 - PKCS#8 私钥 - PKCS#8 私人金鑰 - PKCS - Public-Key Cryptography Standards - - - - PKCS#10 certification request - طلب شهادة PKCS#10 - Zapyt sertyfikacyi PKCS#10 - Заявка за сертификат — PKCS#10 - sol·licitud de certificació PKCS#10 - Požadavek na certifikát PKCS#10 - PKCS#10-certifikatanmodning - PKCS#10-Zertifikatanfrage - αίτηση πιστοποίησης PKCS#10 - PKCS#10 certification request - petición de certificados PKCS#10 - PKCS#10 ziurtagirien eskaera - PKCS#10-varmennepyyntö - PKCS#10 váttanarumbøn - requête de certification PKCS#10 - iarratas dheimhniúchán PKCS#10 - Solicitude de certificado PKCS#10 - בקשה מוסמכת PLCS#10 - PKCS#10-tanúsítványkérés - Permintaan sertifikasi PKCS#10 - Richiesta certificazione PKCS#10 - PKCS#10 証明書署名要求 - PKCS#10 сертификацияға сұранымы - PKCS#10 인증서 요청 - PKCS#10 liudijimų užklausa - PKCS#10 sertifikācijas pieprasījums - PKCS#10-sertifikatforespørsel - PKCS#10-certificatieverzoek - PKCS#10-sertifiseringsførespurnad - Żądanie certyfikatu PKCS#10 - Pedido de certificação PKCS#12 - Cerere de certificat PKCS#10 - запрос сертификации PKCS#10 - Požiadavka na certifikát PKCS#10 - Datoteka potrdila PKCS#10 - Kërkesë çertifikimi PKCS#10 - PKCS#10-certifikatbegäran - комплект сертифікатів PKCS#10 - Yêu cầu chứng nhận PKCS#10 - PKCS#10 认证请求 - PKCS#10 憑證請求 - PKCS - Public-Key Cryptography Standards - - - - - X.509 certificate - شهادة X.509 - Сертификат — X.509 - certificat X.509 - Certifikát X.509 - X.509-certifikat - X.509-Zertifikat - πιστοποιητικό X.509 - X.509 certificate - certificado X.509 - X.509 ziurtagiria - X.509-varmenne - X.509 prógv - certificat X.509 - teastas X.509 - Certificado X.509 - אישור X.509 - X.509 certifikat - X.509 tanúsítvány - Sertifikat X.509 - Certificato X.509 - X.509 証明書 - X.509 сертификаты - X.509 인증서 - X.509 liudijimas - X.509 sertifikāts - X.509 certificaat - Certyfikat X.509 - Certificado X.509 - Certificat X.509 - сертификат X.509 - Certifikát X.509 - Datoteka potrdila X.509 - X.509-certifikat - сертифікат X.509 - X.509 证书 - X.509 憑證 - - - - Certificate revocation list - قائمة إبطال الشهادات - Списък с отхвърлени сертификати - llista de revocació de certificats - Seznam odvolaných certifikátů - Certifikattilbagekaldelsesliste - Liste widerrufener Zertifikate - κατάλογος ανάκλησης πιστοποιητικού - Certificate revocation list - lista de revocación de certificados - Ziurtagiri-errebokatzeen zerrenda - Varmenteiden sulkulista - Prógv afturtøkulisti - liste de révocation de certificat - liosta teastas cúlghairmthe - lista de certificados de revogación - רשימת אישורים מבוטלים - popis povučenih certifikata - Tanúsítvány-visszavonási lista - Daftar pencabutan sertificat (CRL) - Elenco certificati di revoca - 証明書失効リスト - Сертификатты қайта шақыру тізімі - 인증서 철회 목록 - Panaikintų liudijimų sąrašas - Sertifikātu atsaukšanu saraksts - Certificaat revocation lijst - Lista unieważnień certyfikatów - Lista de revogação de certificado - Listă de revocare a certificatelor - Список аннулирования сертификатов - Zoznam zrušených certifikátov - Datoteka seznama preklica potrdil - Spärrlista för certifikat - список відкликання сертифікатів - 证书吊销列表 - 憑證撤銷清單 - - - - PkiPath certification path - مسار شهادة PkiPath - Сертификационна верига — PkiPath - ruta de certificació PkiPath - Cesta k certifikátu PkiPath - PkiPath-certifikationssti - PkiPath-Zertifikatspfad - διαδρομή πιστοποιητικού PkiPath - PkiPath certification path - ruta de certificación PkiPath - PkiPath ziurtagirien bide-izena - PkiPath-varmennepolku - PkiPath váttanleið - chemin de certification PkiPath - conair dheimhniúcháin PkiPath - Ruta de certificación PkiPath - נתיב מאושר של PkiPath - PkiPath tanúsítványútvonal - Alamat sertifikasi PkiPath - Percorso certificazione PkiPath - PkiPath 証明書パス - PkiPath сертификаттау жолы - PkiPath 인증서 요청 - PkiPath liudijimų maršrutas - PkiPath sertifikāta ceļš - PkiPath-certificatiepad - Ścieżka certyfikacji PkiPath - Pedido de certificação PkiPath - Cale certificare PkiPath - путь сертификации PkiPath - Cesta k certifikátu PkiPath - Datoteka poti potrdila PkiPath - PkiPath-certifikatsekvens - шлях сертифікації PkiPath - Đường dẫn cấp chứng nhận PkiPath - PkiPath 证书目录 - PkiPath 憑證路徑 - - - - PS document - مستند PS - Dakument PS - Документ — PS - document PS - Dokument PS - PS-dokument - PS-Dokument - έγγραφο PS - PS document - PS-dokumento - documento PS - PS dokumentua - PS-asiakirja - PS skjal - document PS - cáipéis PS - documento PS - מסמך PS - PS dokumentum - Dokumen PS - Documento PS - PS ドキュメント - PS құжаты - PS 문서 - PS dokumentas - PS dokuments - PS-dokument - PS-document - PS-dokument - Dokument PS - Documento PS - Document PS - документ PS - Dokument PS - Dokument PS - Dokument PS - PS-dokument - PS belgesi - документ PS - Tài liệu PS - PS 文档 - Ps 文件 - PS - PostScript - - - - - - - - - - Plucker document - مستند Plucker - Dakument Plucker - Документ — Plucker - document Plucker - Dokument Plucker - Pluckerdokument - Plucker-Dokument - έγγραφο Plucker - Plucker document - Plucker-dokumento - documento de Plucker - Plucker dokumentua - Plucker-asiakirja - Plucker skjal - document Plucker - cáipéis Plucker - documento de Plucker - מסמך של Plucker - Plucker dokumentum - Dokumen Plucker - Documento Plucker - Plucker ドキュメント - Plucker құжаты - Plucker 문서 - Plucker dokumentas - Plucker dokuments - Plucker-dokument - Plucker-document - Plucker-dokument - Dokument Plucker - Documento do Plucker - Document Plucker - документ Plucker - Dokument Plucker - Dokument Plucker - Dokument Plucker - Plucker-dokument - Plucker belgesi - документ Plucker - Tài liệu Plucker - Plucker 文档 - Plucker 文件 - - - - - - - RELAX NG XML schema - مخطط RELAX NG XML - Схема за XML — RELAX NG - esquema XML RELAX NG - Schéma RELAX NG XML - RELAX NG XML-skema - RELAX NG XML-Schema - σχήμα RELAX NG XML - RELAX NG XML schema - Esquema XML RELAX NG - RELAX NG XML-skeema - schéma XML RELAX NG - scéimre XML RELAX NG - Esquema XML RELAX NG - סכנת RELAX NG XML - RELAX NG XML shema - RELAX NG XML-séma - Skema XML RELAX NG - Schema XML RELAX NG - RELAX NG XML スキーマ - RELAX NG XML сұлбасы - RELAX NG XML 스키마 - RELAX NG XML schema - RELAX NG XML shēma - RELAX NG XML schema - Schemat XML RELAX NG - Esquema XML de RELAX NG - Schemă RELAX NG XML - XML-схема RELAX NG - XML schéma RELAX NG - Datoteka shema RELAX NG XML - RELAX NG XML-schema - XML-схема RELAX NG - RELAX NG XML 模式 - RELAX NG XML schema - RELAX NG - REgular LAnguage for XML Next Generation - - - - - - - RTF document - مستند RTF - Dakument RTF - Документ — RTF - document RTF - Dokument RTF - RTF-dokument - RTF-Dokument - έγγραφο RTF - RTF document - RTF-dokumento - documento RTF - RTF dokumentua - RTF-asiakirja - RTF skjal - document RTF - cáipéis RTF - documento RTF - מסמך RTF - RTF dokument - RTF dokumentum - Dokumen RTF - Documento RTF - RTF ドキュメント - RTF құжаты - RTF 문서 - RTF dokumentas - RTF dokuments - RTF-dokument - RTF-document - TRF-dokument - Dokument RTF - Documento RTF - Document RTF - документ RTF - Dokument RTF - Dokument RTF - Dokument RTF - RTF-dokument - документ RTF - Tài liệu RTF - RTF 文档 - RTF 文件 - RTF - Rich Text Format - - - - - - - - - - Sieve mail filter script - سكربت مرشح بريد Sieve - Skrypt filtravańnia pošty Sieve - Скрипт-филтър за пресяване на поща - script de filtre de correu Sieve - Skript poštovního filtru Sieve - Sieve e-post-filterprogram - Sieve-E-Mail-Filterskript - σενάριο φιλτραρίσματος αλληλογραφίας Sieve - Sieve mail filter script - script de filtro de correo Sieve - Sieve posta-iragazki script-a - Sieve-postinsuodatuskomentotiedosto - script de filtrage de courriel Sieve - script scagaire phost Sieve - Script de filtro de correo Sieve - תסריט סינון דואר של Sieve - Sieve levélszűrő parancsfájl - Skrip filter surat Sieve - Script filtro posta Sieve - Sieve メールフィルタスクリプト - Sieve пошталық фильтр сценарийі - Sieve 메일 필터 스크립트 - Sieve pašto filtro scenarijus - Sieve pasta filtra skripts - Sieve e-postfilter skript - Sieve mailfilter-script - Sieve e-postfilterskript - Skrypt filtra poczty Sieve - Script de filtro de mensagens do Sieve - Script filtrare email Sieve - сценарий почтового фильтра Sieve - Skript poštového filtra Sieve - Skriptna datoteka Sieve poštnega filtra - Script filtrim poste Sieve - Sieve-epostfilterskript - скрипт поштового фільтру Sieve - Văn lệnh lọc thư Sieve - Sieve 邮件过滤脚本 - Sieve 郵件過濾指令稿 - - - - - - SMIL document - مستند SMIL - Dakument SMIL - Документ — SMIL - document SMIL - Dokument SMIL - SMIL-dokument - SMIL-Dokument - έγγραφο SMIL - SMIL document - SMIL-dokumento - documento SMIL - SMIL dokumentua - SMIL-asiakirja - SMIL skjal - document SMIL - cáipéis SMIL - documento SMIL - מסמך SMIL - SMIL dokument - SMIL dokumentum - Dokumen SMIL - Documento SMIL - SMIL ドキュメント - SMIL құжаты - SMIL 문서 - SMIL dokumentas - SMIL dokuments - SMIL-dokument - SMIL-document - SMIL-dokument - Dokument SMIL - Documento SMIL - Document SMIL - документ SMIL - Dokument SMIL - Dokument SMIL - Dokument SMIL - SMIL-dokument - SMIL belgesi - документ SMIL - Tài liệu SMIL - SMIL 文档 - SMIL 文件 - SMIL - Synchronized Multimedia Integration Language - - - - - - - - - - - - - - - - WPL playlist - قائمة تشغيل WPL - Списък за изпълнение — WPL - llista de reproducció WPL - Seznam skladeb WPL - WPL-afspilningsliste - WPL-Wiedergabeliste - λίστα αναπαραγωγής WPL - WPL playlist - WPL-ludlisto - lista de reproducción WPL - WPL erreprodukzio-zerrenda - WPL-soittolista - WPL avspælingarlisti - liste de lecture WPL - seinmliosta WPL - lista de reprodución WPL - רשימת השמעה WPL - WPL popis za reprodukciju - WPL-lejátszólista - Senarai putar WPL - Scaletta WPL - WPL 再生リスト - WPL ойнау тізімі - WPL 재생 목록 - WPL grojaraštis - WPL repertuārs - WPL-afspeellijst - Lista odtwarzania WPL - Lista de reprodução do WPL - Listă redare WPL - список воспроизведения WPL - Zoznam skladieb WPL - Seznam predvajanja WPL - WPL-spellista - список відтворення WPL - Danh mục nhạc WPL - WPL 播放列表 - WPL 播放清單 - WPL - Windows Media Player Playlist - - - - - - - - SQLite2 database - قاعدة بيانات SQLite2 - Baza źviestak SQLite2 - База от данни — SQLite2 - base de dades SQLite2 - Databáze SQLite2 - SQLite2-database - SQLite2-Datenbank - βάση δεδομένων SQLite2 - SQLite2 database - SQLite2-datumbazo - base de datos SQLite2 - SQLite2 datu-basea - SQLite2-tietokanta - SQLite2 dátustovnur - base de données SQLite2 - bunachar sonraí SQLite2 - base de datos SQLite2 - בסיס מידע של SQLite2 - SQLite2 baza podataka - SQLite2 adatbázis - Basis data SQLite2 - Database SQLite2 - SQLite2 データベース - SQLite2 дерекқоры - SQLite2 데이터베이스 - SQLite2 duomenų bazė - SQLite2 datubāze - SQLite2-database - SQLite2-gegevensbank - SQLite2-database - Baza danych SQLite2 - Banco de dados do SQLite2 - Bază de date SQLite2 - база данных SQLite2 - Databáza SQLite2 - Podatkovna zbirka SQLite2 - Bazë me të dhëna SQLite2 - SQLite2-databas - SQLite2 veritabanı - База даних SQLite2 - Cơ sở dữ liệu SQLite2 - SQLite2 数据库 - SQLite2 資料庫 - - - - - - SQLite3 database - قاعدة بيانات SQLite3 - Baza źviestak SQLite3 - База от данни — SQLite3 - base de dades SQLite3 - Databáze SQLite3 - SQLite3-database - SQLite3-Datenbank - βάση δεδομένων SQLite3 - SQLite3 database - SQLite3-datumbazo - base de datos SQLite3 - SQLite3 datu-basea - SQLite3-tietokanta - SQLite3 dátustovnur - base de données SQLite3 - bunachar sonraí SQLite3 - base de datos SQLite3 - בסיס מידע של SQLite3 - SQLite3 baza podataka - SQLite3 adatbázis - Basis data SQLite3 - Database SQLite3 - SQLite3 データベース - SQLite3 дерекқоры - SQLite3 데이터베이스 - SQLite3 duomenų bazė - SQLite3 datubāze - SQLite3-database - SQLite3-gegevensbank - SQLite3-database - Baza danych SQLite3 - Banco de dados do SQLite3 - Bază de date SQLite3 - база данных SQLite3 - Databáza SQLite3 - Podatkovna zbirka SQLite3 - Bazë me të dhëna SQLite3 - SQLite3-databas - SQLite3 veritabanı - база даних SQLite3 - Cơ sở dữ liệu SQLite3 - SQLite3 数据库 - SQLite3 資料庫 - - - - - - GEDCOM family history - تاريخ عائلة GEDCOM - Siamiejnaja historyja GEDCOM - Родословно дърво — GEDCOM - història familiar GEDCOM - Rodokmen GEDCOM - GEDCOM-familiehistorie - GEDCOM-Stammbaum - οικογενειακό ιστορικό GEDCOM - GEDCOM family history - historia familiar GEDCOM - GEDCOM famili historia - GEDCOM-sukuhistoria - GEDCOM familjusøga - généalogie GEDCOM - stair theaghlach GEDCOM - historial de familia GEDCOM - היסטוריה משפחתית של GEDCOM - GEDCOM obiteljska povijest - GEDCOM családtörténet - Sejarah keluarga GEDCOM - Cronologia famiglia GEDCOM - GEDCOM 家系図データ - GEDCOM ოჯახის ისტორია - GEDCOM отбасы тарихы - GEDCOM 가족 내력 - GEDCOM šeimos istorija - GEDCOM ģimenes vēsture - GEDCOM-familiehistorikk - GEDCOM-stamboom - GEDCOM-familehistorie - Plik historii rodziny GEDCOM - Histórico familiar do GEDCOM - Tablou genealogic GEDCOM - история семьи GEDCOM - Rodokmeň GEDCOM - Datoteka družinske zgodovine GEDCOM - Kronollogji familje GEDCOM - GEDCOM-släktträd - історія родини GEDCOM - Lịch sử gia đình GEDCOM - GEDCOM 家谱 - GEDCOM 家族史 - GEDCOM - GEnealogical Data COMmunication - - - - - - - - - - Flash video - Flash مرئي - Videa Flash - Видео — Flash - vídeo de Flash - Video Flash - Flashvideo - Flash-Video - βίντεο Flash - Flash video - Flash-video - vídeo Flash - Flash bideoa - Flash-video - Flash video - vidéo Flash - físeán Flash - vídeo Flash - וידאו של פלאש - Flash video - Flash videó - Video Flash - Video Flash - Flash 動画 - Flash-ის ვიდეო - Flash видеосы - Flash 비디오 - Flash vaizdo įrašas - Flash video - Flash-film - Flash-video - Flash-video - Plik wideo Flash - Vídeo Flash - Video Flash - видео Flash - Video Flash - Video datoteka Flash - Video Flash - Flash-video - відеокліп Flash - Ảnh động Flash - Flash 影片 - Flash 視訊 - - - - - - - - - - - JavaFX video - Видео — JavaFX - vídeo JavaFX - Video JavaFX - JavaFX-video - JavaFX-Video - βίντεο JavaFX - JavaFX video - JavaFX-video - vídeo JavaFX - JavaFX-video - JavaFX video - vidéo JavaFX - físeán JavaFX - vídeo JavaFX - וידאו JavaFX - JavaFX video - JavaFX videó - Video JavaFX - Video JavaFX - JavaFX 動画 - JavaFX аудиосы - JavaFX 비디오 - JavaFX video - JavaFX video - Plik wideo JavaFX - Vídeo JavaFX - Video JavaFX - видео JavaFX - Video JavaFX - Video JavaFX - JavaFX-video - відеокліп JavaFX - JavaFX 视频 - JavaFX 視訊 - - - - - - - - - - SGF record - تسجيلة SGF - Zapisanaja hulnia SGF - Запис — SGF - registre SGF - Záznam SGF - SGF-optagelse - SGF-Aufzeichnung - εγγραφή SGF - SGF record - grabación SGF - SGF erregistroa - SGF-nauhoitus - SGF met - partie SGF - taifead SGF - Grabación SGF - הקלטת SGF - SGF zapis - SGF pontszám - Catatan SGF - Registrazione SGF - SGF レコード - SGF жазбасы - SGF 기록파일 - SGF įrašas - SGF ieraksts - SGF-oppføring - SGF-record - SGF-logg - Zapis gry SGF - Gravação SGF - Înregistrare SGF - запись SGF - Záznam SGF - Datoteka shranjene igre SGF - Regjistrim SGF - SGF-protokoll - SGF kaydı - запис SGF - Mục ghi SGF - SGF 记录 - SGF 紀錄 - SGF - Smart Game Format - - - - - - - - - - XLIFF translation file - ملف ترجمة XLIFF - Fajł pierakładu XLIFF - Превод — XLIFF - fitxer traducció XLIFF - Soubor překladu XLIFF - XLIFF-oversættelsesfil - XLIFF-Übersetzung - αρχείο προς μετάφραση XLIFF - XLIFF translation file - archivo de traducción XLIFF - XLIFF itzulpen-fitxategia - XLIFF-käännöstiedosto - XLIFF týðingarfíla - fichier de traduction XLIFF - comhad aistrithe XLIFF - ficheiro de tradución XLIFF - קובץ תרגום CLIFF - XLIFF datoteka prijevoda - XLIFF fordítási fájl - Berkas terjemahan XLIFF - File traduzione XLIFF - XLIFF 翻訳ファイル - XLIFF аударма файлы - XLIFF 번역 파일 - XLIFF vertimo failas - XLIFF tulkošanas datne - XLIFF-oversettelsesfil - XLIFF-vertalingsbestand - XLIFF-omsetjingsfil - Plik tłumaczenia XLIFF - Arquivo de tradução XLIFF - Fișier de traducere XLIFF - файл перевода XLIFF - Súbor prekladu XLIFF - Datoteka prevoda XLIFF - File përkthimesh XLIFF - XLIFF-översättningsfil - файл перекладу XLIFF - Tập tin dịch XLIFF - XLIFF 消息翻译文件 - XLIFF 翻譯檔 - XLIFF - XML Localization Interchange File Format - - - - - - - - - - - YAML document - مستند YAML - Документ — YAML - document YAML - Dokument YAML - YAML-dokument - YAML-Dokument - έγγραφο YAML - YAML document - YAML-dokumento - documento YAML - YAML-asiakirja - YAML skjal - document YAML - cáipéis YAML - documento YAML - מסמך YAML - YAML-dokumentum - Dokumen YAML - Documento YAML - YAML ドキュメント - YAML құжаты - YAML 문서 - YAML dokumentas - YAML dokuments - YAML document - Dokument YAML - Documento YAML - Document YAML - документ YAML - Dokument YAML - Dokument YAML - YAML-dokument - YAML belgesi - документ YAML - YAML 文档 - YAML 文件 - YAML - YAML Ain't Markup Language - - - - - - - - - - - - Corel Draw drawing - تصميم Corel Draw - Corel Draw çəkimi - Rysunak Corel Draw - Чертеж — Corel Draw - dibuix de Corel Draw - Kresba Corel Draw - Darlun Corel Draw - Corel Draw-tegning - Corel-Draw-Zeichnung - σχέδιο Corel Draw - Corel Draw drawing - grafikaĵo de Corel Draw - dibujo de Corel Draw - Corel Draw-eko marrazkia - Corel Draw -piirros - Corel Draw tekning - dessin Corel Draw - líníocht Corel Draw - debuxo de Corel Draw - ציור של Corel Draw - Corel Draw crtež - Corel Draw-rajz - Gambar Corel Draw - Disegno Corel Draw - Corel Draw ドロー - Corel Draw-ის ნახაზი - Corel Draw суреті - 코렐 드로우 드로잉 - Corel Draw piešinys - Corel Draw zīmējums - Lukisan Corel Draw - Corel Draw-tegning - Corel Draw-tekening - Corel Draw-teikning - Rysunek Corel Draw - desenho Corel Draw - Desenho do Corel Draw - Desen Corel Draw - изображение Corel Draw - Kresba Corel Draw - Datoteka risbe Corel Draw - Vizatim Corel Draw - Corel Draw цртеж - Corel Draw-teckning - малюнок Corel Draw - Bản vẽ Corel Draw - Corel Draw 图形 - Corel Draw 繪圖 - - - - - - - - - - - - - - - HPGL file - ملف HPGL - Fajł HPGL - Файл — HPGL - fitxer HPGL - Soubor HPGL - HPGL-fil - HPGL-Datei - αρχείο HPGL - HPGL file - HPGL-dosiero - archivo HPGL - HPGL fitxategia - HPGL-tiedosto - HPGL fíla - fichier HPGL - comhad HPGL - ficheiro HPGL - קובץ HGPL - HPGL datoteka - HPGL fájl - Berkas HPGL - File HPGL - HPGL ファイル - HPGL файлы - HPGL 파일 - HPGL failas - HPGL datne - HPGL-fil - HPGL-bestand - HPGL-fil - Plik HPGL - Arquivo HPGL - Fișier HPGL - файл HPGL - Súbor HPGL - Datoteka HPGL - File HPGL - HPGL-fil - файл HPGL - Tập tin HPGL - HPGL 文件 - HPGL 檔案 - HPGL - HP Graphics Language - - - - - PCL file - ملف PCL - Fajł PCL - Файл — PCL - fitxer PCL - Soubor PCL - PCL-fil - PCL-Datei - αρχείο PCL - PCL file - PCL-dosiero - archivo PCL - PCL fitxategia - PCL-tiedosto - PCL fíla - fichier PCL - comhad PCL - ficheiro PCL - קובץ PCL - PCL fájl - Berkas PCL - File PCL - PCL ファイル - PCL файлы - PCL 파일 - PCL failas - PCL datne - PCL-fil - PCL-bestand - PCL-fil - Plik PCL - Arquivo PCL - Fișier PCL - файл PCL - Súbor PCL - Datoteka PCL - File PCL - PCL-fil - PCL dosyası - файл PCL - Tập tin PCL - PCL 文件 - PCL 檔 - PCL - HP Printer Control Language - - - - - Lotus 1-2-3 spreadsheet - جدول Lotus 1-2-3 - Lotus 1-2-3 hesab cədvəli - Raźlikovy arkuš Lotus 1-2-3 - Таблица — Lotus 1-2-3 - full de càlcul de Lotus 1-2-3 - Sešit Lotus 1-2-3 - Taenlen Lotus 1-2-3 - Lotus 1-2-3-regneark - Lotus-1-2-3-Tabelle - λογιστικό φύλλο Lotus 1-2-3 - Lotus 1-2-3 spreadsheet - Kalkultabelo de Lotus 1-2-3 - hoja de cálculo de Lotus 1-2-3 - Lotus 1-2-3 kalkulu-orria - Lotus 1-2-3 -taulukko - Lotus 1-2-3 rokniark - feuille de calcul Lotus 1-2-3 - scarbhileog Lotus 1-2-3 - folla de cálculo de Lotus 1-2-3 - גליון נתונים של Lotus 1-2-3 - Lotus 1-2-3 proračunska tablica - Lotus 1-2-3-munkafüzet - Lembar sebar Lotus 1-2-3 - Foglio di calcolo Lotus 1-2-3 - Lotus 1-2-3 スプレッドシート - Lotus 1-2-3 электрондық кестесі - Lotus 1-2-3 스프레드시트 - Lotus 1-2-3 skaičialentė - Lotus 1-2-3 izklājlapa - Hamparan Lotus 1-2-3 - Lotus 1-2-3 regneark - Lotus 1-2-3-rekenblad - Lotus 1-2-3 rekneark - Arkusz Lotus 1-2-3 - folha de cálculo Lotus 1-2-3 - Planilha do Lotus 1-2-3 - Foaie de calcul Lotus 1-2-3 - электронная таблица Lotus 1-2-3 - Zošit Lotus 1-2-3 - Preglednica Lotus 1-2-3 - Fletë llogaritjesh Lotus 1-2-3 - Lotus 1-2-3 табеларни прорачун - Lotus 1-2-3-kalkylblad - ел. таблиця Lotus 1-2-3 - Bảng tính Lotus 1-2-3 - Lotus 1-2-3 工作簿 - Lotus 1-2-3 試算表 - - - - - - - - - - - - - - - - - Lotus Word Pro - - - - - - - - JET database - قاعدة بيانات JET - Baza źviestak JET - База от данни — JET - base de dades JET - Databáze JET - JET-database - JET-Datenbank - βάση δεδομένων JET - JET database - JET-datumbazo - base de datos JET - JET datu-basea - JET-tietokanta - JET dátustovnur - base de données JET - bunachar sonraí JET - base de datos JET - מסד נתונים JET - JET baza podataka - JET adatbázis - Basis data JET - Database JET - JET データベース - JET дерекқоры - JET 데이터베이스 - JET duomenų bazė - JET datubāze - JET-database - JET-gegevensbank - JET-database - Baza Danych JET - Banco de dados JET - Bază de date JET - база данных JET - Databáza JET - Podatkovna zbirka JET - Bazë me të dhëna JET - JET-databas - JET veritabanı - База даних JET - Cơ sở dữ liệu JET - JET 数据库 - JET 資料庫 - JET - Joint Engine Technology - - - - - - - - - - - - - - - Microsoft Cabinet archive - أرشيف Microsoft Cabinet - Архив — Microsoft Cabinet - arxiu Cabinet de Microsoft - Archiv Microsoft Cabinet - Microsoft Cabinet-arkiv - Microsoft-Cabinet-Archiv - συμπιεσμένο αρχείο Microsoft Cabinet - Microsoft Cabinet archive - archivador Microsoft Cabinet - Microsoft Cabinet artxiboa - Microsoft Cabinet -arkisto - Microsoft Cabinet skjalasavn - archive Cab Microsoft - cartlann Microsoft Cabinet - arquivo de Microsoft Cabinet - ארכיון CAB (מיקרוסופט) - Microsoft Cabinet arhiva - Microsoft Cabinet archívum - Arsip Microsoft Cabinet - Archivio Microsoft Cabinet - Microsoft Cabinet アーカイブ - Microsoft-ის Cabinet არქივი - Microsoft Cabinet архиві - 마이크로소프트 캐비닛 묶음 - Microsoft Cabinet archyvas - Microsoft kabineta arhīvs - Microsoft Cabinet-archief - Archiwum Microsoft Cabinet - Pacote do Microsoft Cabinet - Arhivă Microsoft Cabinet - архив Microsoft Cabinet - Archív Microsoft Cabinet - Datoteka arhiva Microsoft Cabinet - Microsoft Cabinet-arkiv - Microsoft Cabinet arşivi - архів Cabinet Microsoft - Kho lưu Cabinet Microsoft - Microsoft CAB 归档文件 - 微軟 Cabinet 封存檔 - - - - - - - - - Excel spreadsheet - جدول Excel - Raźlikovy akruš Excel - Таблица — Excel - full de càlcul d'Excel - Sešit Excel - Excelregneark - Excel-Tabelle - φύλλο εργασίας Excel - Excel spreadsheet - Excel-kalkultabelo - hoja de cálculo de Excel - Excel kalkulu-orria - Excel-taulukko - Excel rokniark - feuille de calcul Excel - scarbhileog Excel - folla de cálculo de Excel - גליון נתונים של אקסל - Excel proračunska tablica - Excel táblázat - Lembar sebar Excel - Foglio di calcolo Excel - Excel スプレッドシート - Excel-ის ცხრილი - Excel электрондық кестесі - 엑셀 스프레드시트 - Excel skaičialentė - Excel izklājlapa - Excel regneark - Excel-rekenblad - Excel-rekneark - Arkusz Excel - Planilha do Excel - Foaie de calcul Excel - электронная таблица Excel - Zošit Excel - Razpredelnica Microsoft Excel - Fletë llogaritje Excel - Excel-kalkylblad - ел. таблиця Excel - Bảng tính Excel - Microsoft Excel 工作簿 - Excel 試算表 - - - - - - - - - - - - - - - - - - Excel add-in - Приставка — Excel - complement d'Excel - Doplněk aplikace Excel - Excel-tilføjelse - Excel Add-in - πρόσθετο Excel - Excel add-in - Complemento de Excel - Excel-lisäosa - complément Excel - complemento de Excel - תוסף של Excel - Excel priključak - Excel bővítmény - Add-in Excel - Add-in Excel - Excel アドイン - Excel-ის დამატება - Excel қосымшасы - 엑셀 추가 기능 - Excel pievienojumprogramma - Excel add-in - Dodatek Excel - Suplemento do Excel - дополнение Excel - Vstavek Excel - додаток Excel - Excel 附加组件 - Excel 增益集 - - - - - - Excel 2007 binary spreadsheet - Таблица — Excel 2007, двоична - full de càlcul binari d'Excel 2007 - Binární formát sešitu Excel 2007 - Binært Excel 2007-regneark - Excel 2007-Tabelle (binär) - Excel 2007 binary spreadsheet - Hoja de cálculo de Excel 2007 - feuille de calcul binaire Excel 2007 - ficheiro binario de folla de cálculo Excel 2007 - גיליון נתונים בינרי של Excel 2007 - Excel 2007 binarna proračunska tablica - Excel 2007 bináris táblázat - Lembar kerja biner Excel 2007 - Foglio di calcolo binario Excel 2007 - Excel 2007 バイナリスプレッドシート - Excel 2007-ის ბინარული ცხრილი - Excel 2007 бинарды кестесі - 엑셀 2007 바이너리 스프레드시트 - Excel 2007 binārā izklājlapa - Excel 2007 binary spreadsheet - Binarny arkusz Excel 2007 - Planilha binária do Excel 2007 - двоичная электронная таблица Excel 2007 - Binarna preglednica Excel 2007 - бінарна електронна таблиця Excel 2007 - Excel 2007 二进制工作表 - Excel 2007 二進位試算表 - - - - - - Excel macro-enabled spreadsheet - Таблица — Excel, с макроси - full de càlcul amb macros d'Excel - Sešit Excel s podporou maker - Makro-aktiveret Excel-regneark - Excel-Tabelle mit aktivierten Makros - φύλο εργασίας Excel με ενεργοποιημένες μακροεντολές - Excel macro-enabled spreadsheet - Hoja de cálculo con macros activados de Excel - feuille de calcul Excel avec macros - folla de cálculo de Excel con macros activadas - גיליון נתונים עם תכונות מקרו פעילות של Excel - Excel proračunska tablica s omogućenim makro naredbama - Excel makrókat tartalmazó táblázat - Lembar kerja Excel dengan makro - Foglio di calcolo Excel con macro abilitate - Excel マクロ有効スプレッドシート - Excel-ის მაკროსიანი ცხრილი - макростары іске қосылған Excel кестесі - 엑셀 매크로 사용 스프레드시트 - Excel izklājlapa ar makrosiem - Excel macro-enabled spreadsheet - Arkusz z włączonymi makrami Excel - Planilha do Excel com macro ativada - электронная таблица Excel с включёнными макросами - Preglednica Excel z omogočenimi makri - електронна таблиця Excel з увімкненими макросами - Excel 启用宏的工作表 - Excel 巨集啟用試算表 - - - - - - Excel macro-enabled spreadsheet template - Шаблон за таблици — Excel, с макроси - plantilla de full de càlcul amb macros d'Excel - Šablona sešitu Excel s podporou maker - Makro-aktiveret Excel-regnearksskabelon - Excel-Tabellenvorlage mit aktivierten Makros - πρότυπο φύλλο εργασίας Excel με ενεργοποιημένες μακροεντολές - Excel macro-enabled spreadsheet template - Plantilla de hoja de cálculo con macros activados de Excel - modèle de feuille de calcul Excel avec macros - modelo de folla de cálculo de Excel con macros activadas - תבנית של גיליון נתונים עם תכונות מקרו פעילות של Excel - Excel predložak proračunske tablice s omogućenim makro naredbama - Excel makrókat tartalmazó táblázatsablon - Templat lembar kerja Excel dengan makro - Modello foglio di calcolo Excel con macro abilitate - Excel マクロ有効スプレッドシートテンプレート - Excel-ის მაკროსიანი ცხრილის შაბლონი - макростары іске қосылған Excel кестесінің үлгісі - 엑셀 매크로 사용 스프레드시트 서식 - Excel izklājlapas ar makrosiem veidne - Excel macro-enabled spreadsheet sjabloon - Szablon arkusza z włączonymi makrami Excel - Módulo de planilha do Excel com macro ativada - шаблон электронной таблицы Excel с включёнными макросами - Predloga preglednice Excel z omogočenimi makri - шаблон електронної таблиці Excel з увімкненими макросами - Excel 启用宏的工作表模板 - Excel 巨集啟用試算表範本 - - - - - - PowerPoint presentation - عرض تقديمي PowerPoint - Prezentacyja PowerPoint - Презентация — PowerPoint - presentació de PowerPoint - Prezentace PowerPoint - PowerPoint-præsentation - PowerPoint-Präsentation - παρουσίαση PowerPoint - PowerPoint presentation - PowerPoint-prezentaĵo - presentación de PowerPoint - PowerPoint aurkezpena - PowerPoint-esitys - PowerPoint framløga - présentation PowerPoint - láithreoireacht PowerPoint - presentación de PowerPoint - מצגת PowerPoint - PowerPoint prezentacija - PowerPoint prezentáció - Presentasi PowerPoint - Presentazione PowerPoint - PowerPoint プレゼンテーション - PowerPoint презентациясы - 파워포인트 프리젠테이션 - PowerPoint pateiktis - PowerPoint prezentācija - PowerPoint-presentasjon - PowerPoint-presentatie - PowerPoint-presentasjon - Prezentacja PowerPoint - Apresentação do PowerPoint - Prezentare PowerPoint - презентация PowerPoint - Prezentácia PowerPoint - Predstavitev Microsoft PowerPoint - Prezantim PowerPoint - PowerPoint-presentation - презентація PowerPoint - Trình diễn PowerPoint - Microsoft PowerPoint 演示文稿 - PowerPoint 簡報 - - - - - - - - - - - PowerPoint add-in - Приставка — PowerPoint - complement de - Doplněk PowerPoint - PowerPoint-tilføjelse - PowerPoint Add-in - πρόσθετο PowerPoint - PowerPoint add-in - Complemento de PowerPoint - PowerPoint-lisäosa - complément PowerPoint - complemento de PowerPoint - תוסף של PowerPoint - PowerPoint priključak - PowerPoint bővítmény - Add-in PowerPoint - Add-in PowerPoint - PowerPoint アドイン - PowerPoint-ის დამატება - PowerPoint қосымшасы - 파워포인트 추가 기능 - PowerPoint pievienojumprogramma - PowerPoint add-in - Dodatek PowerPoint - Suplemento do PowerPoint - дополнение PowerPoint - Vstavek PowerPoint - додаток PowerPoint - PowerPoint 附加组件 - PowerPoint 增益集 - - - - - PowerPoint macro-enabled presentation - Презентация — PowerPoint, с макроси - presentació amb macros - Prezentace PowerPoint s podporou maker - Makro-aktiveret PowerPoint-præsentation - PowerPoint-Präsentation mit aktivierten Makros - παρουσίαση PowerPoint με ενεργοποιημένες μακροεντολές - PowerPoint macro-enabled presentation - Presentación con macros activadas de PowerPoint - présentation PowerPoint avec macros - presentación con macros activadas de PowerPoint - מצגת של PowerPoint בעלת תכונות מקרו פעילות - PowerPoint prezentacija s omogućenim makro naredbama - PowerPoint makrókat tartalmazó bemutató - Presentasi PowerPoint dengan makro - Presentazione PowerPoint con macro abilitate - PowerPoint マクロ有効プレゼンテーション - PowerPoint-ის მაკროსიანი პრეზენტაცია - макростары іске қосылған PowerPoint презентациясы - 파워포인트 매크로 사용 프리젠테이션 - PowerPoint prezentācija ar makrosiem - PowerPoint macro-enabled presentatie - Prezentacja z włączonymi makrami PowerPoint - Apresentação do PowerPoint com macro ativada - презентация PowerPoint с включёнными макросами - Predstavitev PowerPoint z omogočenimi makri - презентація PowerPoint з увімкненими макросами - PowerPoint 启用宏的演示文稿 - PowerPoint 巨集啟用簡報 - - - - - - PowerPoint macro-enabled slide - Кадър — PowerPoint, с макроси - dispositiva amb macros - Snímek PowerPoint s podporou maker - Makro-aktiveret PowerPoint-slide - PowerPoint-Folie mit aktivierten Makros - σλάιντ PowerPoint με ενεργοποιημένες μακροεντολές - PowerPoint macro-enabled slide - Diapositiva con macros activadas de PowerPoint - diapositive PowerPoint avec macros - Diapositiva con macros activadas de Powerpoint - שקופית של PowerPoint בעלת תכונות מקרו פעילות - PowerPoint slajd s omogućenim makro naredbama - PowerPoint makrókat tartalmazó dia - Slide PowerPoint dengan makro - Diapositiva PowerPoint con macro abilitate - PowerPoint マクロ有効スライド - PowerPoint-ის მაკროსიანი სლაიდი - макростары іске қосылған PowerPoint слайды - 파워포인트 매크로 사용 슬라이드 - PowerPoint slaids ar makrosiem - PowerPoint macro-enabled dia - Slajd z włączonymi makrami PowerPoint - Slide do PowerPoint com macro ativada - слайд PowerPoint с включёнными макросами - Prosojnica PowerPoint z omogočenimi makri - слайд PowerPoint з увімкненими макросами - PowerPoint 启用宏的幻灯片 - PowerPoint 巨集啟用投影片 - - - - - - PowerPoint macro-enabled presentation - Презентация — PowerPoint, с макроси - presentació amb macros - Prezentace PowerPoint s podporou maker - Makro-aktiveret PowerPoint-præsentation - PowerPoint-Präsentation mit aktivierten Makros - παρουσίαση PowerPoint με ενεργοποιημένες μακροεντολές - PowerPoint macro-enabled presentation - Presentación con macros activadas de PowerPoint - présentation PowerPoint avec macros - presentación con macros activadas de PowerPoint - מצגת של PowerPoint בעלת תכונות מקרו פעילות - PowerPoint prezentacija s omogućenim makro naredbama - PowerPoint makrókat tartalmazó bemutató - Presentasi PowerPoint dengan makro - Presentazione PowerPoint con macro abilitate - PowerPoint マクロ有効プレゼンテーション - PowerPoint-ის მაკროსიანი პრეზენტაცია - макростары іске қосылған PowerPoint презентациясы - 파워포인트 매크로 사용 프리젠테이션 - PowerPoint prezentācija ar makrosiem - PowerPoint macro-enabled presentatie - Prezentacja z włączonymi makrami PowerPoint - Apresentação do PowerPoint com macro ativada - презентация PowerPoint с включёнными макросами - Predstavitev PowerPoint z omogočenimi makri - презентація PowerPoint з увімкненими макросами - PowerPoint 启用宏的演示文稿 - PowerPoint 巨集啟用簡報 - - - - - - PowerPoint macro-enabled presentation template - Шаблон за презентации — PowerPoint, с макроси - plantilla de presentació amb macros - Šablona prezentace PowerPoint s podporou maker - Makro-aktiveret PowerPoint-præsentationsskabelon - PowerPoint-Präsentationsvorlage mit aktivierten Makros - πρότυπη παρουσίαση PowerPoint με ενεργοποιημένες μακροεντολές - PowerPoint macro-enabled presentation template - Plantilla de presentación con macros activadas de PowerPoint - modèle de présentation PowerPoint avec macros - modelo de presentación con macros activadas de PowerPoint - תבנית של מצגת של PowerPoint בעלת תכונות מקרו פעילות - PowerPoint predložak prezentacije s omogućenim makro naredbama - PowerPoint makrókat tartalmazó bemutatósablon - Templat presentasi PowerPoint dengan makro - Modello presentazione PowerPoint con macro abilitate - PowerPoint マクロ有効プレゼンテーションテンプレート - PowerPoint-ის მაკროსიანი პრეზენტაციის შაბლონი - макростары іске қосылған PowerPoint презентациясының үлгісі - 파워포인트 매크로 사용 프리젠테이션 서식 - PowerPoint prezentācijas ar makrosiem veidne - PowerPoint macro-enabled presentatie-sjabloon - Szablon prezentacji z włączonymi makrami PowerPoint - Modelo de apresentação do PowerPoint com macro ativada - шаблон презентации PowerPoint с включёнными макросами - Predloga predstavitve PowerPoint z omogočenimi makri - шаблон презентації PowerPoint з увімкненими макросами - PowerPoint 启用宏的演示文稿模板 - PowerPoint 巨集啟用簡報範本 - - - - - - Word macro-enabled document - Документ — Word, с макроси - document amb macros de Word - Dokument Word s podporou maker - Makro-aktiveret Word-dokument - Word-Dokument mit aktivierten Makros - έγγραφο Word με ενεργοποιημένες μακροεντολές - Word macro-enabled document - Documento con macros activadas de Word - document Word avec macros - documento con macros activadas de Word - מסמך של Word בעל תכונות מקרו פעילות - Word dokument s omogućenim makro naredbama - Word makrókat tartalmazó dokumentum - Dokumen Word dengan makro - Documento Word con macro abilitate - Word マクロ有効文書 - Word-ის მაკროსიანი დოკუმენტი - макростары іске қосылған Word құжаты - 워드 매크로 사용 문서 - Word dokuments ar makrosiem - Word macro-enabled document - Dokument z włączonymi makrami Word - Documento do Word com macro ativada - документ Word с включёнными макросами - Dokument Word z omogočenimi makri - документ Word з увімкненими макросами - Word 启用宏的文档 - Word 巨集啟用文件 - - - - - - Word macro-enabled document template - Шаблон за документи — Word, с макроси - plantilla de document amb macros de Word - Šablona dokumentu Word s podporou maker - Makro-aktiveret Word-dokumentskabelon - Word-Dokumentvorlage mit aktivierten Makros - πρότυπο έγγραφο Word με ενεργοποιημένες μακροεντολές - Word macro-enabled document template - Plantilla de documento con macros activadas de Word - modèle de document Word avec macros - Plantilla de documento con macros activadas de Word - תבנית של מסמך של Word בעל תכונות מקרו פעילות - Word predložak dokumenta s omogućenim makro naredbama - Word makrókat tartalmazó dokumentumsablon - Templat dokumen Word dengan makro - Modello documento Word con macro abilitate - Word マクロ有効文書テンプレート - Word-ის მაკროსიანი დოკუმენტის შაბლონი - макростары іске қосылған Word құжатының үлгісі - 워드 매크로 사용 문서 서식 - Word dokumenta ar makrosiem veidne - Word macro-enabled document sjabloon - Szablon dokumentu z włączonymi makrami Word - Modelo de documento do Word com macro ativada - шаблон документа Word с включёнными макросами - Predloga dokumenta Word z omogočenimi makri - шаблон документа Word з увімкненими макросами - Word 启用宏的文档模板 - Word 巨集啟用文件範本 - - - - - - XPS document - مستند XPS - Dakument XPS - Документ — XPS - document XPS - Dokument XPS - XPS-dokument - XPS-Dokument - έγγραφο XPS - XPS document - XPS-dokumento - documento XPS - XPS dokumentua - XPS-asiakirja - XPS skjal - document XPS - cáipéis XPS - documento XPS - מסמך XPS - XPS dokument - XPS dokumentum - Dokumen XPS - Documento XPS - XPS ドキュメント - XPS құжаты - XPS 문서 - XPS dokumentas - XPS dokuments - XPS-dokument - XPS-document - XPS-dokument - Dokument XPS - Documento XPS - Document XPS - документ XPS - Dokument XPS - Dokument XPS - Dokument XPS - XPS-dokument - документ XPS - Tài liệu XPS - XPS 文档 - XPS 文件 - XPS - Open XML Paper Specification - - - - - - - - Microsoft Works document - مستند Microsoft Works - Dakument Microsoft Works - Документ — Microsoft Works - document Works de Microsoft - Dokument Microsoft Works - Microsoft Works-dokument - Microsoft-Works-Dokument - έγγραφο Microsoft Works - Microsoft Works document - documento de Microsoft Works - Microsoft Works dokumentua - Microsoft Works -asiakirja - Microsoft Works skjal - document Microsoft Works - cáipéis Microsoft Works - documento de Microsoft Works - מסמך Microsoft Works - Microsoft Works dokument - Microsoft Works dokumentum - Dokumen Microsoft Works - Documento Microsoft Works - Microsoft Works ドキュメント - Microsoft Works-ის დოკუმენტი - Microsoft Works құжаты - 마이크로소프트 Works 문서 - Microsoft Works dokumentas - Microsoft Works dokuments - Microsoft Works-dokument - Microsoft Works-document - Microsoft Works-dokument - Dokument Microsoft Works - Documento do Microsoft Works - Document Microsoft Works - документ Microsoft Works - Dokument Microsoft Works - Dokument Microsoft Works - Dokument Microsoft Works - Microsoft Works-dokument - Microsoft Works belgesi - документ Microsoft Works - Tài liệu Microsoft Works - Microsoft Works 文档 - 微軟 Works 文件 - - - - - - - - - - Microsoft Visio document - Документ — Microsoft Visio - document Visio de Microsoft - Microsoft Visio-dokument - Microsoft Visio-Dokument - έγγραφο Microsoft Visio - Microsoft Visio document - documento de Microsoft Visio - Microsoft Visio -asiakirja - document Microsoft Visio - Documento de Microsoft Visio - מסמך - Microsoft Visio dokument - Microsoft Visio dokumentum - Dokumen Microsoft Visio - Documento Microsoft Visio - Microsoft Visio ドキュメント - Microsoft Visio-ის დოკუმენტი - Microsoft Visio құжаты - 마이크로소프트 Visio 문서 - Microsoft Visio dokuments - Microsoft Visio document - Dokument Microsoft Visio - Documento do Microsoft Visio - документ Microsoft Visio - Dokument Microsoft Visio - документ Microsoft Visio - Microsoft Visio 文档 - Microsoft Visio文件 - - - - - - - - - Word document - مستند Word - Dakument Word - Документ — Word - document de Word - Dokument Word - Worddokument - Word-Dokument - έγγραφο Word - Word document - Word-dokumento - documento de Word - Word dokumentua - Word-asiakirja - Word skjal - document Word - cáipéis Word - documento de Word - מסמך Word - Word dokument - Word dokumentum - Dokumen Word - Documento Word - Word ドキュメント - Word құжаты - 워드 문서 - Word dokumentas - Word dokuments - Word-dokument - Word-document - Word-dokument - Dokument Word - Documento do Word - Document Word - документ Word - Dokument Word - Dokument Word - Dokument Word - Word-dokument - документ Word - Tài liệu Word - Microsoft Word 文档 - Word 文件 - - - - - - - - - - - - - - - - - - - - Word template - قالب Word - Šablon Word - Шаблон за документи — Word - plantilla de Word - Šablona Word - Wordskabelon - Word-Vorlage - πρότυπο έγγραφο Word - Word template - Word-ŝablono - plantilla de Word - Word txantiloia - Word-malli - Word formur - modèle Word - teimpléad Word - Plantilla de Word - תבנית Word - Word predložak - Word sablon - Templat Word - Modello Word - Word テンプレート - Word үлгісі - 워드 서식 - Word šablonas - Word veidne - Word-mal - Word-sjabloon - Word-mal - Szablon Word - Modelo do Word - Șablon Word - шаблон Word - Šablóna Word - Predloga dokumenta Microsoft Word - Model Word - Word-mall - шаблон Word - Mẫu Word - Word 模板 - Word 範本 - - - - - - GML document - GML - Geography Markup Language - - - - - - GNUnet search file - ملف بحث GNUnet - fajł pošuku GNUnet - Указател за търсене — GNUnet - fitxer de cerca GNUnet - Vyhledávací soubor GNUnet - GNunet-søgefil - GNUnet-Suchdatei - αρχείο αναζήτησης GNUnet - GNUnet search file - archivo de búsqueda GNUnet - GNUnet bilaketako fitxategia - GNUnet-hakutiedosto - GNUnet leitifíla - fichier de recherche GNUnet - comhad cuardaigh GNUnet - ficheiro de busca de GNUnet - קובץ חיפוש של GNUnet - GNUnet datoteka pretrage - GNUnet keresési fájl - Berkas telusur GNUnet - File ricerca GNUnet - GNUnet 検索ファイル - GNUnet ძებნის ფაილი - GNUnet іздеу файлы - GNUnet 검색 파일 - GNUnet paieškos failas - GNUnet meklēšanas datne - GNUnet søkefil - GNUnet-zoekbestand - GNUnet-søkjefil - Plik wyszukiwania GNUnet - Arquivo de pesquisa do GNUnet - Fișier căutare GNUnet - файл поиска GNUnet - Vyhľadávací súbor GNUnet - Iskalna datoteka GNUnet - File kërkimi GNUnet - GNUnet-sökfil - файл пошуку GNUnet - Tập tin tìm kiếm GNUnet - GNUnet 搜索文件 - GNUnet 搜尋檔案 - - - - - - - TNEF message - رسالة TNEF - List TNEF - Съобщение — TNEF - missatge TNEF - Zpráva TNEF - TNEF-meddelelse - TNEF-Nachricht - μήνυμα TNEF - TNEF message - mensaje TNEF - TNEF mezua - TNEF-viesti - TNEF boð - message TNEF - teachtaireacht TNEF - mensaxe TNEF - הודעת TNEF - TNEF poruka - TNEF üzenet - Pesan TNEF - Messaggio TNEF - TNEF メッセージ - TNEF мәлімдемесі - TNEF 메시지 - TNEF žinutė - TNEF ziņojums - TNEF-melding - TNEF-bericht - TNEF-melding - Wiadomość TNEF - Mensagem TNEF - Mesaj TNEF - сообщение TNEF - Správa TNEF - Datoteka sporočila TNEF - Mesazh TNEF - TNEF-meddelande - повідомлення TNEF - Thông điệp TNEF - TNEF 信件 - TNEF 訊息 - TNEF - Transport Neutral Encapsulation Format - - - - - - - - - - StarCalc spreadsheet - جدول StarCalc - StarCalc hesab cədvəli - Raźlikovy arkuš StarCalc - Таблица — StarCalc - full de càlcul de StarCalc - Sešit StarCalc - Taenlen StarCalc - StarCalc-regneark - StarCalc-Tabelle - λογιστικό φύλλο StarCalc - StarCalc spreadsheet - StarCalc-kalkultabelo - hoja de cálculo de StarCalc - StarCalc kalkulu-orria - StarCalc-taulukko - StarCalc rokniark - feuille de calcul StarCalc - scarbhileog StarCalc - folla de cálculo de StarCalc - גליון נתונים של StarCalc - StarCalc proračunska tablica - StarCalc-munkafüzet - Lembar sebar StarCalc - Foglio di calcolo StarCalc - StarCalc スプレッドシート - StarCalc электрондық кестесі - StarCalc 스프레드시트 - StarCalc skaičialentė - StarCalc izklājlapa - Hamparan StarCalc - StarCalc-regneark - StarCalc-rekenblad - StarCalc-rekneark - Arkusz StarCalc - folha de cálculo do StarCalc - Planilha do StarCalc - Foaie de calcul StarCalc - электронная таблица StarCalc - Zošit StarCalc - Preglednica StarCalc - Fletë llogaritjesh StarCalc - StarCalc табеларни прорачун - StarCalc-kalkylblad - ел. таблиця StarCalc - Bảng tính StarCalc - STarCalc 工作簿 - StarCalc 試算表 - - - - - StarChart chart - مخطط StarChart - StarChart cədvəli - Dyjahrama StarChart - Диаграма — StarChart - diagrama de StarChart - Graf StarChart - Siart StarChart - StarChart-diagram - StarChart-Diagramm - γράφημα StarChart - StarChart chart - StarChart-diagramo - gráfica de StarChart - StarChart diagrama - StarChart-kaavio - StarChart strikumynd - graphique StarChart - cairt StarChart - gráfica de StarChart - טבלה של StarChart - StarChart grafikon - StarChart-grafikon - Bagan StarChart - Grafico StarChart - StarChart チャート - StarChart диаграммасы - StarCalc 표 - StarChart diagrama - StarChart diagramma - Carta StarChart - StarChart graf - StarChart-kaart - StarChart-graf - Wykres StarChart - gráfico do StarChart - Gráfico do StarChart - Diagramă StarChart - диаграмма StarChart - Graf StarChart - Datoteka grafikona StarChart - Grafik StarChart - StarChart графикон - StarChart-diagram - діаграма StarChart - Đồ thị StarChart - STarChart 图表 - StarChart 圖表 - - - - - StarDraw drawing - تصميم StarDraw - StarDraw çəkimi - Rysunak StarDraw - Чертеж — StarDraw - dibuix de StarDraw - Kresba StarDraw - Darlun StarDraw - StarDraw-tegning - StarDraw-Zeichnung - σχέδιο StarDraw - StarDraw drawing - StarDraw-grafikaĵo - dibujo de StarDraw - StarDraw marrazkia - StarDraw-piirros - StarDraw tekning - dessin StarDraw - líníocht StarDraw - debuxo de StarDraw - ציור של StarDrawing - StarDraw crtež - StarDraw-rajz - Gambar StarDraw - Disegno StarDraw - StarDraw ドロー - StarDraw суреті - StarCalc 드로잉 - StarDraw piešinys - StarDraw zīmējums - Lukisan StarDraw - StarDraw tegning - StarDraw-tekening - StarDraw-teikning - Rysunek StarDraw - desenho do StarDraw - Desenho do StarDraw - Desen StarDraw - изображение StarDraw - Kresba StarDraw - Datoteka risbe StarDraw - Vizatim StarDraw - StarDraw drawing - StarDraw-teckning - малюнок StarDraw - Bản vẽ StarDraw - STarDraw 绘图 - StarDraw 繪圖 - - - - - StarImpress presentation - عرض تقديمي StarImpress - StarImpress təqdimatı - Prezentacyja StarImpress - Презентация — StarImpress - presentació de StarImpress - Prezentace StarImpress - Cyflwyniad StarImpress - StarImpress-præsentation - StarImpress-Präsentation - παρουσίαση StarImpress - StarImpress presentation - StarImpress-prezentaĵo - presentación de StarImpress - StarImpress aurkezpena - StarImpress-esitys - StarImpress framløga - présentation StarImpress - láithreoireacht StarImpress - presentación de StarImpress - מצגת של StarImpress - StarImpress prezentacija - StarImpress-bemutató - Presentasi StarImpress - Presentazione StarImpress - StarImpress プレゼンテーション - StarImpress презентациясы - StarImpress 프리젠테이션 - StarImpress pateiktis - StarImpress prezentācija - Persembahan StarImpress - StarImpress-presentasjon - StarImpress-presentatie - StarImpress-presentasjon - Prezentacja StarImpress - apresentação do StarImpress - Apresentação do StarImpress - Prezentare StarImpress - презентация StarImpress - Prezentácia StarImpress - Predstavitev StarImpress - Prezantim StarImpress - StarImpress презентација - StarImpress-presentation - презентація StarImpress - Trình diễn StarImpress - STarImpress 演示文稿 - StarImpress 簡報檔 - - - - - - StarMail email - بريد StarMail الإلكتروني - Email StarMail - Електронно писмо — StarMail - correu electrònic de StarMail - E-mail StarMail - StarMail-e-brev - StarMail-E-Mail - ηλ. μήνυμα StarMail - StarMail email - StarMail-retpoŝto - correo electrónico de StarMail - StarMail helb.el. - StarMail-sähköposti - StarMail t-postur - courriel StarMail - ríomhphost StarMail - Correo electrónico de StarMail - דוא"ל של StarMail - StarMail e-pošta - StarMail e-mail - Email StarMail - Email StarMail - StarMail メール - StarMail электрондық хаты - StarMail 전자우편 - StarMail el. laiškas - StarMail epasts - Emel StarMail - StarMail-melding - StarMail-e-mail - StarMail-fil - E-Mail StarMail - e-mail do StarMail - E-mail do StarMail - Email StarEmail - электронное письмо StarMail - E-mail StarMail - Datoteka pošte StarMail - Mesazh StarMail - StarMail пошта - StarMail-e-post - поштове повідомлення StarMail - Thư điện tử StarMail - STarMail 电子邮件 - StarMail 郵件 - - - - StarMath formula - صيغة StarMath - Formuła StarMath - Формула — StarMath - fórmula de StarMath - Vzorec StarMath - StarMath-formel - StarMath-Formel - μαθηματικός τύπος StarMath - StarMath formula - StarMath-formulo - fórmula de StarMath - StarMath formula - StarMath-kaava - StarMath frymil - formule StarMath - foirmle StarMath - fórmula de StarMath - נוסחה של StarMath - StarMath formula - StarMath-képlet - Formula StarMath - Formula StarMath - StarMath 計算式 - StarMath формуласы - StarMath 수식 - StarMath formulė - StarMath formula - Formula StarMath - StarMath-formel - StarMath-formule - StarMath-formel - Formuła StarMath - fórmula do StarMath - Fórmula do StarMath - Formulă StarMath - формула StarMath - Vzorec StarMath - Datoteka formule StarMath - Formulë StarMath - StarMath формула - StarMath-formel - формула StarMath - Công thức StarMath - STarMath 公式 - StarMath 公式 - - - - - StarWriter document - مستند StarWriter - StarWriter sənədi - Dakument StarWriter - Документ — StarWriter - document de StarWriter - Dokument StarWriter - Dogfen StarWriter - StarWriter-dokument - StarWriter-Dokument - έγγραφο StarWriter - StarWriter document - StarWriter-dokumento - documento de StarWriter - StarWriter dokumentua - StarWriter-asiakirja - StarWriter skjal - document StarWriter - cáipéis StarWriter - documento de StarWriter - מסמך של StarWriter - StarWriter dokument - StarWriter-dokumentum - Dokumen StarWriter - Documento StrarWriter - StarWriter ドキュメント - StarWriter құжаты - StarWriter 문서 - StarWriter dokumentas - StarWriter dokuments - Dokumen StarWriter - StarWriter-dokument - StarWriter-document - StarWriter document - Dokument StarWriter - documento do StarWriter - Documento do StarWriter - Document StarWriter - документ StarWriter - Dokument StarWriter - Dokument StarWriter - Dokument StarWriter - StarWriter документ - StarWriter-dokument - StarWriter belgesi - документ StarWriter - Tài liệu StarWriter - STarWriter 文档 - StarWriter 文件 - - - - - - - - - - OpenOffice Calc spreadsheet - جدول Calc المكتب المفتوح - Raźlikovy arkuš OpenOffice Calc - Таблица — OpenOffice Calc - full de càlcul d'OpenOffice Calc - Sešit OpenOffice Calc - OpenOffice Calc-regneark - OpenOffice-Calc-Tabelle - φύλλο εργασίας OpenOffice Calc - OpenOffice Calc spreadsheet - hoja de cálculo de OpenOffice Calc - OpenOffice.org Calc kalkulu-orria - OpenOffice Calc -taulukko - OpenOffice Calc rokniark - feuille de calcul OpenOffice Calc - scarbhileog OpenOffice Calc - folla de cálculo de OpenOffice Calc - גליון נתונים של OpenOffice Calc - OpenOffice Calc táblázat - Lembar sebar OpenOffice Calc - Foglio di calcolo OpenOffice Calc - OpenOffice Calc スプレッドシート - OpenOffice Calc-ის ცხრილი - OpenOffice Calc электрондық кестесі - OpenOffice Calc 스프레드시트 - OpenOffice Calc skaičialentė - OpenOffice Calc izklājlapa - OpenOffice Calc-regneark - OpenOffice.org Calc-rekenblad - OpenOffice Calc-rekneark - Arkusz kalkulacyjny OpenOffice.org Calc - Planilha do OpenOffice Calc - Foaie de calcul OpenOffice Calc - электронная таблица OpenOffice Calc - Zošit OpenOffice Calc - Razpredelnica OpenOffice.org Calc - Fletë llogaritjesh OpenOffice Calc - OpenOffice Calc-kalkylblad - ел. таблиця OpenOffice Calc - Bảng tính Calc của OpenOffice.org - OpenOffice.org Calc 工作簿 - OpenOffice Calc 試算表 - - - - - - - - - - - - - OpenOffice Calc template - قالب Calc المكتب المفتوح - Šablon OpenOffice Calc - Шаблон за таблици — OpenOffice Calc - plantilla d'OpenOffice Calc - Šablona OpenOffice Calc - OpenOffice Calc-skabelon - OpenOffice-Calc-Vorlage - πρότυπο OpenOffice Calc - OpenOffice Calc template - plantilla de OpenOffice Calc - OpenOffice Calc txantiloia - OpenOffice Calc -malli - OpenOffice Calc formur - modèle OpenOffice Calc - teimpléad OpenOffice Calc - modelo de OpenOffice Calc - תבנית של OpenOffice Calc - OpenOffice Calc sablon - Templat OpenOffice Calc - Modello OpenOffice Calc - OpenOffice Calc テンプレート - OpenOffice Calc-ის შაბლონი - OpenOffice Calc үлгісі - OpenOffice Calc 스프레드시트 문서 서식 - OpenOffice Calc šablonas - OpenOffice Calc veidne - OpenOffice Calc-mal - OpenOffice.org Calc-sjabloon - OpenOffice Calc-mal - Szablon arkusza OpenOffice.org Calc - Modelo do OpenOffice Calc - Șablon OpenOffice Calc - шаблон OpenOffice Calc - Šablóna OpenOffice Calc - Predloga OpenOffice.org Calc - Model OpenOffice Calc - OpenOffice Calc-mall - шаблон ел.таблиці OpenOffice Calc - Mẫu bảng tính Calc của OpenOffice.org - OpenOffice.org Calc 工作簿模板 - OpenOffice Calc 範本 - - - - - - - - - - - - - OpenOffice Draw drawing - تصميم Draw المكتب المفتوح - Rysunak OpenOffice Draw - Чертеж — OpenOffice Draw - dibuix d'OpenOffice Draw - Kresba OpenOffice Draw - OpenOffice Draw-tegning - OpenOffice-Draw-Zeichnung - σχέδιο OpenOffice Draw - OpenOffice Draw drawing - dibujo de OpenOffice Draw - OpenOffice.org Draw marrazkia - OpenOffice Draw -piirros - OpenOffice Draw tekning - dessin OpenOffice Draw - líníocht OpenOffice Draw - debuxo de OpenOffice Draw - ציור של OpenOffice Draw - OpenOffice Draw rajz - Gambar OpenOffice Draw - Disegno OpenOffice Draw - OpenOffice Draw ドロー - OpenOffice Draw-ის ნახაზი - OpenOffice Draw суреті - OpenOffice Draw 그림 - OpenOffice Draw piešinys - OpenOffice Draw zīmējums - OpenOffice Draw-tegning - OpenOffice.org Draw-tekening - OpenOffice Draw-teikning - Rysunek OpenOffice.org Draw - Desenho do OpenOffice Draw - Desen OpenOffice Draw - изображение OpenOffice Draw - Kresba OpenOffice Draw - Datoteka risbe OpenOffice.org Draw - Vizatim OpenOffice Draw - OpenOffice Draw-teckning - малюнок OpenOffice Draw - Bản vẽ Draw của OpenOffice.org - OpenOffice.org Draw 绘图 - OpenOffice Draw 繪圖 - - - - - - - - - - - - - OpenOffice Draw template - قالب Draw المكتب المفتوح - Šablon OpenOffice Draw - Шаблон за чертежи — OpenOffice Draw - plantilla d'OpenOffice Draw - Šablona OpenOffice Draw - OpenOffice Draw-skabelon - OpenOffice-Draw-Vorlage - πρότυπο OpenOffice Draw - OpenOffice Draw template - plantilla de OpenOffice.org Draw - OpenOffice Draw txantiloia - OpenOffice Draw -malli - OpenOffice Draw formur - modèle OpenOffice Draw - teimpléad OpenOffice Draw - modelo de OpenOffice Draw - תבנית של OpenOffice Draw - OpenOffice Draw sablon - Templat OpenOffice Draw - Modello OpenOffice Draw - OpenOffice Draw テンプレート - OpenOffice Draw-ის შაბლონი - OpenOffice Draw үлгісі - OpenOffice Draw 그림 문서 서식 - OpenOffice Draw šablonas - OpenOffice Draw veidne - OpenOffice Draw-mal - OpenOffice.org Draw-sjabloon - OpenOffice Draw-mal - Szablon rysunku OpenOffice.org Draw - Modelo do OpenOffice Draw - Șablon OpenOffice Draw - шаблон OpenOffice Draw - Šablóna OpenOffice Draw - Predloga OpenOffice.org Draw - Model OpenOffice Draw - OpenOffice Draw-mall - шаблон малюнку OpenOffice Draw - Mẫu bản vẽ Draw của OpenOffice.org - OpenOffice.org Draw 绘图模板 - OpenOffice Draw 範本 - - - - - - - - - - - - - OpenOffice Impress presentation - عرض تقديمي Impress المكتب المفتوح - OpenOffice Impress sənədi - Prezentacyja OpenOffice Impress - Презентация — OpenOffice Impress - presentació d'OpenOffice Impress - Prezentace OpenOffice Impress - Cyflwyniad OpenOffice (Impress) - OpenOffice Impress-præsentation - OpenOffice-Impress-Vorlage - παρουσίαση OpenOffice Impress - OpenOffice Impress presentation - presentación de OpenOffice Impress - OpenOffice.org Impress aurkezpena - OpenOffice Impress -esitys - OpenOffice Impress framløga - présentation OpenOffice Impress - láithreoireacht OpenOffice Impress - presentación de de OpenOffice Impress - מצגת של OpenOffice Impress - OpenOffice Impress bemutató - Presentasi OpenOffice Impress - Presentazione OpenOffice Impress - OpenOffice Impress プレゼンテーション - OpenOffice Impress-ის პრეზენტაცია - OpenOffice Impress презентациясы - OpenOffice Impress 프리젠테이션 - OpenOffice Impress pateiktis - OpenOffice Impress prezentācija - OpenOffice Impress-presentasjon - OpenOffice.org Impress-presentatie - OpenOffice Impress-presentasjon - Prezentacja OpenOffice.org Impress - Apresentação do OpenOffice Impress - Prezentare OpenOffice Impress - презентация OpenOffice Impress - Prezentácia OpenOffice Impress - Predstavitev OpenOffice.org Impress - Prezantim OpenOffice Impress - OpenOffice Impress-presentation - презентація OpenOffice Impress - Trình diễn Impress của OpenOffice.org - OpenOffice.org Impress 演示文稿 - OpenOffice Impress 簡報 - - - - - - - - - - - - - OpenOffice Impress template - قالب Impress المكتب المفتوح - Šablon OpenOffice Impress - Шаблон за презентации — OpenOffice Impress - plantilla d'OpenOffice Impress - Šablona OpenOffice Impress - OpenOffice Impress-skabelon - OpenOffice-Impress-Vorlage - πρότυπο OpenOffice Impress - OpenOffice Impress template - plantilla de OpenOffice Impress - OpenOffice Impress txantiloia - OpenOffice Impress -malli - OpenOffice Impress formur - modèle OpenOffice Impress - teimpléad OpenOffice Impress - modelo de OpenOffice Impress - תבנית של OpenOffice Impress - OpenOffice Impress sablon - Templat OpenOffice Impress - Modello OpenOffice Impress - OpenOffice Impress テンプレート - OpenOffice Impress-ის შაბლონი - OpenOffice Impress үлгісі - OpenOffice Impress 프리젠테이션 문서 서식 - OpenOffice Impress šablonas - OpenOffice Impress veidne - OpenOffice Impress-mal - OpenOffice.org Impress-sjabloon - OpenOffice Impress-mal - Szablon prezentacji OpenOffice.org Impress - Modelo do OpenOffice Impress - Șablon OpenOffice Impress - шаблон OpenOffice Impress - Šablóna OpenOffice Impress - Predloga OpenOffice.org Impress - Model OpenOffice Impress - OpenOffice Impress-mall - шаблон презентації OpenOffice Impress - Mẫu trình diễn Impress của OpenOffice.org - OpenOffice.org Impress 演示文稿模板 - OpenOffice Impress 範本 - - - - - - - - - - - - - OpenOffice Math formula - صيغة Math المكتب المفتوح - Formuła OpenOffice Math - Формула — OpenOffice Math - fórmula d'OpenOffice Math - Vzorec OpenOffice Math - OpenOffice Math-formel - OpenOffice-Math-Formel - μαθηματικός τύπος OpenOffice Math - OpenOffice Math formula - fórmula de OpenOffice Math - OpenOffice.org Math formula - OpenOffice Math -kaava - OpenOffice Math frymil - formule OpenOffice Math - foirmle OpenOffice Math - fórmula de OpenOffice Math - נוסחה של OpenOffice Math - OpenOffice Math képlet - Formula OpenOffice Math - Formula OpenOffice Math - OpenOffice Math 計算式 - OpenOffice Math-ის ფორმულა - OpenOffice Math формуласы - OpenOffice Math 수식 - OpenOffice Math formulė - OpenOffice Math formula - OpenOffice Math-formel - OpenOffice.org Math-formule - OpenOffice Math-formel - Formuła OpenOffice.org Math - Fórmula do OpenOffice Math - Formulă OpenOffice Math - формула OpenOffice Math - Vzorec OpenOffice Math - Dokument formule OpenOffice.org Math - Formulë OpenOffice Math - OpenOffice Math-formel - OpenOffice Math formülü - формула OpenOffice Math - Công thức Math của OpenOffice.org - OpenOffice.org Math 公式 - OpenOffice Math 公式 - - - - - - - - - - - - - OpenOffice Writer document - مستند Writer المكتب المفتوح - OpenOffice Writer sənədi - Dakument OpenOffice Writer - Документ — OpenOffice Writer - document d'OpenOffice Writer - Dokument OpenOffice Writer - Dogfen OpenOffice (Writer) - OpenOffice Writer-dokument - OpenOffice-Writer-Dokument - έγγραφο OpenOffice Writer - OpenOffice Writer document - documento de OpenOffice Writer - OpenOffice.org Writer dokumentua - OpenOffice Writer -asiakirja - OpenOffice Writer skjal - document OpenOffice Writer - cáipéis OpenOffice Writer - documento de OpenOffice Writer - מסמך של OpenOffice Writer - OpenOffice Writer dokumentum - Dokumen OpenOffice Writer - Documento OpenOffice Writer - OpenOffice Writer ドキュメント - OpenOffice Writer-ის დოკუმენტი - OpenOffice Writer құжаты - OpenOffice Writer 문서 - OpenOffice Writer dokumentas - OpenOffice Writer dokuments - OpenOffice Writer-dokument - OpenOffice.org Writer-document - OpenOffice Writer-dokument - Dokument OpenOffice.org Writer - Documento do OpenOffice Writer - Document OpenOffice Writer - документ OpenOffice Writer - Dokument OpenOffice Writer - Dokument OpenOffice.org Writer - Dokument OpenOffice Writer - OpenOffice Writer-dokument - OpenOffice Writer belgesi - документ OpenOffice Writer - Tài liệu Writer của OpenOffice.org - OpenOffice.org Writer 文档 - OpenOffice Writer 文件 - - - - - - - - - - - - - OpenOffice Writer global document - مستند المكتب المفتوح Writer العالمي - OpenOffice Writer qlobal sənədi - Hlabalny dakument OpenOffice Writer - Документ - глобален — OpenOffice Writer - document global d'OpenOffice Writer - Globální dokument OpenOffice Writer - Dogfen eang OpenOffice (Writer) - OpenOffice Writer-globalt dokument - OpenOffice-Writer-Globaldokument - παγκόσμιο έγγραφο OpenOffice Writer - OpenOffice Writer global document - documento global de OpenOffice Writer - OpenOffice.org Writer dokumentu globala - OpenOffice Writer - yleinen asiakirja - OpenOffice Writer heiltøkt skjal - document global OpenOffice Writer - cáipéis chomhchoiteann OpenOffice Writer - documento global de OpenOffice Writer - מסמך גלובלי של OpenOffice Writer - OpenOffice Writer globális dokumentum - Dokumen global OpenOffice Writer - Documento globale OpenOffice Writer - OpenOffice Writer グローバルドキュメント - OpenOffice Writer-ის გლობალური დოკუმენტი - OpenOffice Writer негізгі құжаты - OpenOffice Writer 글로벌 문서 - OpenOffice Writer bendrinis dokumentas - OpenOffice Writer globālais dokuments - Global OpenOffice Writer globalt dokument - OpenOffice.org Writer-globaal-document - OpenOffice Writer globalt dokument - Globalny dokument OpenOffice.org Writer - Documento global do OpenOffice Writer - Document global OpenOffice Writer - основной документ OpenOffice Writer - Globálny dokument OpenOffice Writer - Splošni dokument OpenOffice.org Writer - Dokument i përgjithshëm OpenOffice Writer - OpenOffice Writer-globaldokument - загальний документ OpenOffice Writer - Tài liệu toàn cục Writer của OpenOffice.org - OpenOffice.org Writer 全局文档 - OpenOffice Writer 主控文件 - - - - - - - - - - - - - OpenOffice Writer template - قالب Writer المكتب المفتوح - OpenOffice Writer şablonu - Šablon OpenOffice Writer - Шаблон за документи — OpenOffice Writer - plantilla d'OpenOffice Writer - Šablona OpenOffice Writer - Templed OpenOffice (Writer) - OpenOffice Writer-skabelon - OpenOffice-Writer-Vorlage - πρότυπο OpenOffice Writer - OpenOffice Writer template - plantilla de OpenOffice Writer - OpenOffice Writer txantiloia - OpenOffice Writer -malli - OpenOffice Writer formur - modèle OpenOffice Writer - teimpléad OpenOffice Writer - modelo de OpenOffice Writer - תסנית של OpenOffice Writer - OpenOffice Writer sablon - Templat OpenOffice Writer - Modello OpenOffice Writer - OpenOffice Writer ドキュメントテンプレート - OpenOffice Writer-ის შაბლონი - OpenOffice Writer үлгісі - OpenOffice Writer 문서 서식 - OpenOffice Writer šablonas - OpenOffice Writer veidne - Templat OpenOffice Writer - OpenOffice Writer-mal - OpenOffice.org Writer-sjabloon - OpenOffice Writer-mal - Szablon dokumentu OpenOffice.org Writer - Modelo do OpenOffice Writer - Șablon OpenOffice Writer - шаблон OpenOffice Writer - Šablóna OpenOffice Writer - Predloga OpenOffice.org Writer - Model OpenOffice Writer - OpenOffice Writer-mall - шаблон документа OpenOffice Writer - Mẫu tài liệu Writer của OpenOffice.org - OpenOffice.org Writer 文档模板 - OpenOffice Writer 範本 - - - - - - - - - - - - - ODT document - مستند ODT - Dakument ODT - Документ — ODT - document ODT - Dokument ODT - ODT-dokument - ODT-Dokument - έγγραφο ODT - ODT document - ODT-dokumento - documento ODT - ODT dokumentua - ODT-asiakirja - ODT skjal - document ODT - cáipéis ODT - documento ODT - מסמך ODT - ODT dokument - ODT-dokumentum - Dokumen ODT - Documento ODT - ODT ドキュメント - ODT დოკუმენტი - ODT құжаты - ODT 문서 - ODT dokumentas - ODT dokuments - ODT-dokument - ODT-document - ODT-dokument - Dokument ODT - Documento ODT - Document ODT - документ ODT - Dokument ODT - Dokument ODT - Dokument ODT - ODT-dokument - документ ODT - Tài liệu ODT - ODT 文档 - ODT 文件 - ODT - OpenDocument Text - - - - - - - - - - - - - ODT document (Flat XML) - مستند ODT (Flat XML) - Документ — ODT (само XML) - document ODT (XML pla) - Dokument ODT (Flat XML) - ODT-dokument (flad XML) - ODT-Dokument (Unkomprimiertes XML) - έγγραφο ODT (Flat XML) - ODT document (Flat XML) - documento ODT (XML plano) - ODT dokumentua (XML soila) - ODT skjal (Flat XML) - document ODT (XML plat) - cáipéis ODT (XML cothrom) - documento ODT (XML plano) - מסמך ODT‏ (Flat XML) - ODT-dokumentum (egyszerű XML) - Dokumen ODT (Flat XML) - Documento ODT (XML semplice) - ODT ドキュメント (Flat XML) - ODT დოკუმენტი (Flat XML) - ODT құжаты (Тек XML) - ODT 문서 (단일 XML) - ODT dokumentas (Flat XML) - ODT dokuments (plakans XML) - ODT document (Flat XML) - Dokument ODT (prosty XML) - Documento ODT (Flat XML) - Document ODT (XML simplu) - документ ODT (простой XML) - Dokument ODT (čisté XML) - Datoteka dokumenta ODT (nepovezan XML) - ODT-dokument (platt XML) - документ ODT (Flat XML) - ODT 文档(Flat XML) - ODT 文件 (Flat XML) - FODT - OpenDocument Text (Flat XML) - - - - - - ODT template - قالب ODT - Šablon ODT - Шаблон за документи — ODT - plantilla ODT - Šablona ODT - ODT-skabelon - ODT-Vorlage - πρότυπο ODT - ODT template - ODT-ŝablono - plantilla ODT - ODT txantiloia - ODT-malli - ODT formur - modèle ODT - teimpléad ODT - modelo ODT - תבנית ODT - ODT predložak - ODT-sablon - Templat ODT - Modello ODT - ODT テンプレート - ODT დოკუმენტი - ODT үлгісі - ODT 문서 서식 - ODT šablonas - ODT veidne - ODT-mal - ODT-sjabloon - ODT-mal - Szablon ODT - Modelo ODT - Șablon ODT - шаблон ODT - Šablóna ODT - Predloga dokumenta ODT - Model ODT - ODT-mall - шаблон ODT - Mẫu ODT - ODT 模板 - ODT 範本 - ODT - OpenDocument Text - - - - - - - - - - - - - OTH template - قالب OTH - Šablon OTH - Шаблон за страници — OTH - plantilla OTH - Šablona OTH - OTH-skabelon - OTH-Vorlage - πρότυπο OTH - OTH template - OTH-ŝablono - plantilla OTH - OTH txantiloia - OTH-malli - OTH formur - modèle OTH - teimpléad OTH - modelo OTH - תבנית OTH - OTH predložak - OTH-sablon - Templat OTH - Modello OTH - OTH テンプレート - OTH შაბლონი - OTH үлгісі - OTH 문서 서식 - OTH šablonas - OTH veidne - OTH-mal - OTH-sjabloon - OTH-mal - Szablon OTH - Modelo OTH - Șablon OTH - шаблон OTH - Šablóna OTH - Predloga OTH - Model OTH - OTH-mall - шаблон OTH - Mẫu ODH - OTH 模板 - OTH 範本 - OTH - OpenDocument HTML - - - - - - - - - - - - - ODM document - مستند ODM - Dakument ODM - Документ — ODM - document ODM - Dokument ODM - ODM-dokument - ODM-Dokument - έγγραφο ODM - ODM document - ODM-dokumento - documento ODM - ODM dokumentua - ODM-asiakirja - ODM skjal - document ODM - cáipéis ODM - documento ODM - מסמך ODM - ODM dokument - ODM-dokumentum - Dokumen ODM - Documento ODM - ODM ドキュメント - ODM დოკუმენტი - ODM құжаты - ODM 문서 - ODM dokumentas - ODM dokuments - ODM-dokument - ODM-document - ODM-dokument - Dokument ODM - Documento ODM - Document ODM - документ ODM - Dokument ODM - Dokument ODM - Dokument ODM - ODM-dokument - ODM belgesi - документ ODM - Tài liệu ODM - ODM 文档 - ODM 文件 - ODM - OpenDocument Master - - - - - - - - - - - - - ODG drawing - تصميم ODG - Rysunak ODG - Чертеж — ODG - dibuix ODG - Kresba ODG - ODG-tegning - ODG-Zeichnung - σχέδιο ODG - ODG drawing - ODG-desegnaĵo - dibujo ODG - ODG marrazkia - ODG-piirros - ODG tekning - dessin ODG - líníocht ODG - debuxo ODG - ציור ODG - ODG crtež - ODG-rajz - Gambar ODG - Disegno ODG - ODG ドロー - ODG-ის ნახაზი - ODG суреті - ODG 드로잉 - ODG piešinys - ODG zīmējums - ODG-tegning - ODG-tekening - ODG-teikning - Rysunek ODG - Desenho ODG - Desen ODG - изображение ODG - Kresba ODG - Datoteka risbe ODG - Vizatim ODG - ODG-teckning - малюнок ODG - Bản vẽ ODG - ODG 绘图 - ODG 繪圖 - ODG - OpenDocument Drawing - - - - - - - - - - - - - ODG drawing (Flat XML) - رسمة ODG (Flat XML) - Чертеж — ODG (само XML) - dibuix ODG (XML pla) - Kresba ODG (Flat XML) - ODG-tegning (flad XML) - ODG-Zeichnung (Unkomprimiertes XML) - ODG drawing (Flat XML) - dibujo ODG (XML plano) - ODG marrazkia (XML soila) - ODG tekning (Flat XML) - dessin ODG (XML plat) - líníocht ODG (XML cothrom) - debuxo ODB (XML plano) - ציור ODG (Flat XML( - ODG-rajz (egyszerű XML) - Gambar ODG (FLAT XML) - Disegno ODG (XML semplice) - ODG ドロー (Flat XML) - ODG-ის ნახაზი (Flat XML) - ODG сызбасы (Тек XML) - ODG 드로잉 (단일 XML) - ODG piešinys (Flat XML) - ODG zīmējums (plakans XML) - ODG-tekening (Flat XML) - Rysunek ODG (prosty XML) - Desenho ODG (Flat XML) - Desen ODG (XML simplu) - изображение ODG (простой XML) - Kresba ODG (čisté XML) - Datoteka risbe ODG (nepovezan XML) - ODG-teckning (platt XML) - малюнок ODG (Flat XML) - ODG 绘图(Flat XML) - ODG 繪圖 (Flat XML) - FODG - OpenDocument Drawing (Flat XML) - - - - - - ODG template - قالب ODG - Šablon ODG - Шаблон за чертежи — ODG - plantilla ODG - Šablona ODG - ODG-skabelon - ODG-Vorlage - πρότυπο ODG - ODG template - ODG-ŝablono - plantilla ODG - ODG txantiloia - ODG-malli - ODG formur - modèle ODG - teimpléad ODG - modelo ODG - תבנית ODG - ODG predložak - ODG-sablon - Templat ODG - Modello ODG - ODG テンプレート - ODG-ის შაბლონი - ODG үлгісі - ODG 문서 서식 - ODG šablonas - ODG veidne - ODG-mal - ODG-sjabloon - ODG-mal - Szablon ODG - Modelo ODG - Șablon ODG - шаблон ODG - Šablóna ODG - Predloga dokumenta ODG - Model ODG - ODG-mall - шаблон ODG - Mẫu ODG - ODG 模板 - ODG 範本 - ODG - OpenDocument Drawing - - - - - - - - - - - - - ODP presentation - عرض تقديمي ODP - Prezentacyja ODP - Презентация — ODP - presentació ODP - Prezentace ODP - ODP-præsentation - ODP-Präsentation - παρουσίαση ODP - ODP presentation - ODP-prezentaĵo - presentación ODP - ODP aurkezpena - ODP-esitys - ODP framløga - présentation ODP - láithreoireacht ODP - presentación ODP - מצגת ODP - ODP prezentacija - ODP-prezentáció - Presentasi ODP - Presentazione ODP - ODP プレゼンテーション - ODP პრეზენტაცია - ODP презентациясы - ODP 프리젠테이션 - ODP pateiktis - ODP prezentācija - ODP-presentasjon - ODP-presentatie - ODP-presentasjon - Prezentacja ODP - Apresentação ODP - Prezentare ODP - презентация ODP - Prezentácia ODP - Predstavitev ODP - Prezantim ODP - ODP-presentation - ODP sunumu - презентація ODP - Trình diễn ODM - ODP 演示文稿 - ODP 簡報 - ODP - OpenDocument Presentation - - - - - - - - - - - - - ODP presentation (Flat XML) - عرض ODP (Flat XML) - Презентация — ODP (само XML) - presentació ODP (XML pla) - Prezentace ODP (Flat XML) - ODP-præsentation (flad XML) - ODP-Präsentation (Unkomprimiertes XML) - παρουσίαση ODP (Flat XML) - ODP presentation (Flat XML) - presentación ODP (XML plano) - ODP aurkezpena (XML soila) - ODP framløga (Flat XML) - présentation ODP (XML plat) - láithreoireacht ODP (XML cothrom) - presentación ODP (XML plano) - מצגת ODP‏ (Flat XML) - ODP-prezentáció (egyszerű XML) - Presentasi ODP (Flat XML) - Presentazione ODP (XML semplice) - ODP プレゼンテーション (Flat XML) - ODP პრეზენტაცია (Flat XML) - ODP презентациясы (Тек XML) - ODP 프리젠테이션 (단일 XML) - ODP pateiktis (Flat XML) - ODP prezentācija (plakans XML) - ODP presentatie (Flat XML) - Prezentacja ODP (prosty XML) - Apresentação ODP (Flat XML) - Prezentare ODP (XML simplu) - презентация ODP (простой XML) - Prezentácia ODP (čisté XML) - Predstavitev ODP (nepovezan XML) - ODP-presentation (platt XML) - презентація ODP (Flat XML) - ODP 演示文稿(Flat XML) - ODP 範本 (Flat XML) - FODP - OpenDocument Presentation (Flat XML) - - - - - - ODP template - قالب ODP - Šablon ODP - Шаблон за презентации — ODP - plantilla ODP - Šablona ODP - ODP-skabelon - ODP-Vorlage - πρότυπο ODP - ODP template - ODP-ŝablono - plantilla ODP - ODP txantiloia - ODP-malli - ODP formur - modèle ODP - teimpléad ODP - modelo ODP - תבנית ODP - ODP predložak - ODP-sablon - Templat ODP - Modello ODP - ODP テンプレート - ODP შაბლონი - ODP үлгісі - ODP 문서 서식 - ODP šablonas - ODP veidne - ODP-mal - ODP-sjabloon - ODP-mal - Szablon ODP - Modelo ODP - Șablon ODP - шаблон ODP - Šablóna ODP - Predloga dokumenta ODP - Model ODP - ODP-mall - шаблон ODP - Mẫu ODP - ODP 模板 - ODP 範本 - ODP - OpenDocument Presentation - - - - - - - - - - - - - ODS spreadsheet - جدول ODS - Raźlikovy arkuš ODS - Таблица — ODS - full de càlcul ODS - Sešit ODS - ODS-regneark - ODS-Tabelle - φύλλο εργασίας ODS - ODS spreadsheet - ODS-kalkultabelo - hoja de cálculo ODS - ODS kalkulu-orria - ODS-taulukko - ODS rokniark - feuille de calcul ODS - scarbhileog ODS - folla de cálculo ODS - גליון נתונים ODS - ODS proračunska tablica - ODS-táblázat - Lembar sebar ODS - Foglio di calcolo ODS - ODS スプレッドシート - ODS ცხრილი - ODS электрондық кестесі - ODS 스프레드시트 - ODS skaičialentė - ODS izklājlapa - ODS-regneark - ODS-rekenblad - ODS-rekneark - Arkusz ODS - Planilha ODS - Foaie de calcul ODS - электронная таблица ODS - Zošit ODS - Preglednica ODS - Fletë llogaritjesh ODS - ODS-kalkylblad - ел. таблиця ODS - Bảng tính ODS - ODS 工作簿 - ODS 試算表 - ODS - OpenDocument Spreadsheet - - - - - - - - - - - - - ODS spreadsheet (Flat XML) - جدول ODS (Flat XML) - Таблица — ODS (само XML) - full de càlcul ODS (XML pla) - Sešit ODS (Flat XML) - ODS-regneark (flad XML) - ODS-Tabelle (Unkomprimiertes XML) - φύλλο εργασίας ODS (Flat XML) - ODS spreadsheet (Flat XML) - hoja de cálculo ODS (XML plano) - ODS kalkulu-orria (XML soila) - ODS rokniark (Flat XML) - feuille de calcul ODS (XML plat) - scarbhileog ODS (XML cothrom) - folla de cálculo ODS (XML plano) - גליון נתונים ODS‏ (XML פשוט) - ODS-táblázat (egyszerű XML) - Lembar sebar ODS (Flat XML) - Foglio di calcolo ODS (XML semplice) - ODS スプレッドシート (Flat XML) - ODS ცხრილი (Flat XML) - ODS электрондық кестесі (Тек XML) - ODS 스프레드시트 (단일 XML) - ODS skaičialentė (Flat XML) - ODS izklājlapa (plakans XML) - ODS spreadsheet (Flat XML) - Arkusz ODS (prosty XML) - Planilha ODS (Flat XML) - Foaie de calcul ODS (XML simplu) - электронная таблица ODS (простой XML) - Zošit ODS (čisté XML) - Preglednica ODS (nepovezan XML) - ODS-kalkylblad (platt XML) - ел. таблиця ODS (Flat XML) - ODS 工作簿(Flat XML) - ODS 試算表 (Flat XML) - FODS - OpenDocument Spreadsheet (Flat XML) - - - - - - ODS template - قالب ODS - Šablon ODS - Шаблон за таблици — ODS - plantilla ODS - Šablona ODS - ODS-skabelon - ODS-Vorlage - πρότυπο ODS - ODS template - ODS-ŝablono - plantilla ODS - ODS txantiloia - ODS-malli - ODS formur - modèle ODS - teimpléad ODS - modelo ODS - תבנית ODS - ODS predložak - ODS-sablon - Templat ODS - Modello ODS - ODS テンプレート - ODS-ის შაბლონი - ODS үлгісі - ODS 문서 서식 - ODS šablonas - ODS veidne - ODS-mal - ODS-sjabloon - ODS-mal - Szablon ODS - Modelo ODS - Șablon ODS - шаблон ODS - Šablóna ODS - Predloga dokumenta ODS - Model ODS - ODS-mall - шаблон ODS - Mẫu ODS - ODS 模板 - ODS 範本 - ODS - OpenDocument Spreadsheet - - - - - - - - - - - - - ODC chart - مخطط ODC - Dyjahrama ODC - Диаграма — ODC - diagrama ODC - Graf ODC - ODC-diagram - ODC-Diagramm - διάγραμμα ODC - ODC chart - ODC-diagramo - gráfica ODC - ODC diagrama - ODC-kaavio - ODC strikumynd - graphique ODC - cairt ODC - gráfica ODC - תו ODC - ODC grafikon - ODC-táblázat - Bagan ODC - Grafico ODC - ODC チャート - ODC диаграммасы - ODC 차트 - ODC diagrama - ODC diagramma - ODC-graf - ODC-grafiek - ODC-diagram - Wykres ODC - Gráfico ODC - Diagramă ODC - диаграмма ODC - Graf ODC - Datoteka grafikona ODC - Grafik ODC - ODC-diagram - діаграма ODC - Sơ đồ ODC - ODC 图表 - ODC 圖表 - ODC - OpenDocument Chart - - - - - - - - - - - - - ODC template - قالب ODC - Шаблон за диаграми — ODC - plantilla ODC - Šablona ODC - ODC-skabelon - ODC-Vorlage - πρότυπο ODC - ODC template - ODC-ŝablono - plantilla ODC - ODC txantiloia - ODC-malli - ODC formur - modèle ODC - teimpléad ODC - modelo ODC - תבנית ODC - ODC predložak - ODC-sablon - Templat ODC - Modello ODC - ODC テンプレート - ODC შაბლონი - ODC үлгісі - ODC 문서 서식 - ODC šablonas - ODC veidne - ODC-sjabloon - Szablon ODC - Modelo ODC - Șablon ODC - шаблон ODC - Šablóna ODC - Predloga ODC - ODC-mall - шаблон ODC - Mẫu ODC - ODC 模板 - ODC 範本 - ODC - OpenDocument Chart - - - - - - - - - - - - - ODF formula - صيغة ODF - Formuła ODF - Формула — ODF - fórmula ODF - Vzorec ODF - ODF-formel - ODF-Formel - μαθηματικός τύπος ODF - ODF formula - ODF-formulo - fórmula ODF - ODF formula - ODF-kaava - ODF frymil - formule ODF - foirmle ODF - Fórula ODF - נוסחת ODF - ODF formula - ODF-képlet - Formula ODF - Formula ODF - ODF 計算式 - ODF-ის ფორმულა - ODF формуласы - ODF 수식 - ODF formulė - ODF formula - ODF-formel - ODF-formule - ODF-formel - Formuła ODF - Fórmula ODF - Formulă ODF - формула ODF - Vzorec ODF - Dokument formule ODF - Formulë ODF - ODF-formel - формула ODF - Công thức ODF - ODF 公式 - ODF 公式 - ODF - OpenDocument Formula - - - - - - - - - - - - - ODF template - قالب ODF - Шаблон за формули — ODF - plantilla ODF - Šablona ODF - ODF-skabelon - ODF-Vorlage - πρότυπο ODF - ODF template - ODF-ŝablono - plantilla ODF - ODF txantiloia - ODF-malli - ODF formur - modèle ODF - teimpléad ODF - modelo ODF - תבנית ODF - ODF predložak - ODG-sablon - Templat ODF - Modello ODF - ODF テンプレート - ODF-ის შაბლონი - ODF үлгісі - ODF 문서 서식 - ODF šablonas - ODF veidne - ODF-sjabloon - Szablon ODF - Modelo ODF - Șablon ODF - шаблон ODF - Šablóna ODF - Predloga dokumenta ODF - ODF-mall - шаблон ODF - Mẫu ODF - ODF 模板 - ODF 範本 - ODF - OpenDocument Formula - - - - - - - - - - - - - ODB database - قاعدة بيانات ODB - Baza źviestak ODB - База от данни — ODB - base de dades ODB - Databáze ODB - ODB-database - ODB-Datenbank - Βάση δεδομένων ODB - ODB database - ODB-datumbazo - base de datos ODB - ODB datu-basea - ODB-tietokanta - ODB dátustovnur - base de données ODB - bunachar sonraí ODB - base de datos ODB - בסיס נתונים ODB - ODB baza podataka - ODB-adatbázis - Basis data ODB - Database ODB - ODB データベース - ODB-ის მონაცემთა ბაზა - ODB дерекқоры - ODB 데이터베이스 - ODB duomenų bazė - ODB datubāze - ODB-database - ODB-gegevensbank - ODB-database - Baza danych ODB - Banco de dados ODB - Bază de date ODB - база данных ODB - Databáza ODB - Podatkovna zbirka ODB - Bazë me të dhëna ODB - ODB-databas - ODB veritabanı - база даних ODB - Cơ sở dữ liệu ODB - ODB 数据库 - ODB 資料庫 - ODB - OpenDocument Database - - - - - - ODI image - صورة ODI - Vyjava ODI - Изображение — ODI - imatge ODI - Obrázek ODI - ODI-billede - ODI-Bild - εικόνα ODI - ODI image - ODI-bildo - imagen ODI - ODI irudia - ODI-kuva - ODI mynd - image ODI - íomhá ODI - imaxe ODI - תמונת ODI - ODI slika - ODI-kép - Citra ODI - Immagine ODI - ODI 画像 - ODI გამოსახულება - ODI суреті - ODI 그림 - ODI paveikslėlis - ODI attēls - ODI-bilde - ODI-afbeelding - ODI-bilete - Obraz ODI - Imagem ODI - Imagine ODI - изображение ODI - Obrázok ODI - Slikovna datoteka ODI - Figurë ODI - ODI-bild - ODI görüntüsü - зображення ODI - Ảnh ODI - ODI 图像 - ODI 影像 - ODI - OpenDocument Image - - - - - - - - - - - - - OpenOffice.org extension - امتداد OpenOffice.org - Pašyreńnie OpenOffice.org - Разширение — OpenOffice - extensió d'OpenOffice.org - Rozšíření OpenOffice.org - OpenOffice.org-udvidelse - OpenOffice.org-Erweiterung - επέκταση OpenOffice.org - OpenOffice.org extension - extensión de OpenOffice - OpenOffice.org luzapena - OpenOffice.org-laajennus - OpenOffice.org víðkan - extension OpenOffice.org - eisínteacht OpenOffice.org - Extensión de OpenOffice.org - הרחבה של OpenOffice.org - OpenOffice.org kiterjesztés - Ekstensi OpenOffice.org - Estensione OpenOffice.org - OpenOffice.org 拡張機能 - OpenOffice.org-ის გაფართოება - OpenOffice.org кеңейтуі - OpenOffice.org 확장 - OpenOffice.org plėtinys - OpenOffice.org paplašinājums - OpenOffice.org-uitbreiding - OpenOffice Writer-utviding - Rozszerzenie OpenOffice.org - Extensão do OpenOffice - Extensie OpenOffice.org - расширение OpenOffice.org - Rozšírenie OpenOffice.org - Razširitev OpenOffice.org - Shtojcë për OpenOffice.org - OpenOffice.org-tillägg - OpenOffice.org eklentisi - розширення OpenOffice.org - Phần mở rộng của OpenOffice.org - OpenOffice.org 扩展 - OpenOffice.org 擴充套件 - - - - - - Android package - Пакет — Android - paquet d'Android - Balíčky systému Android - Android-pakke - Android-Paket - πακέτο Android - Android package - Android-pakaĵo - Paquete de Android - Android-paketti - paquet Android - paquete de Android - חבילת אנדרויד - Android paket - Android csomag - Paket Android - Pacchetto Android - Android パッケージ - Android-ის პაკეტი - Android дестесі - 안드로이드 패키지 - Android pakotne - Android pakket - Pakiet Androida - Pacote do Android - пакет Android - Paket Android - Android-paket - пакунок Android - Android - Android 套件 - - - - - SIS package - حزمة SIS - Pakunak SIS - Пакет — SIS - paquet SIS - Balíček SIS - SIS-pakke - SIS-Paket - πακέτο SIS - SIS package - SIS-pakaĵo - paquete SIS - SIS paketea - SIS-paketti - SIS pakki - paquet SIS - pacáiste SIS - paquete SIS - חבילת SIS - SIS paket - SIS csomag - Paket SIS - Pacchetto SIS - SIS パッケージ - SIS дестесі - SIS 패키지 - SIS paketas - SIS pakotne - SIS-pakke - SIS-pakket - SIS-pakke - Pakiet SIS - Pacote SIS - Pachet SIS - пакет SIS - Balíček SIS - Datoteka paketa SIS - Paketë SIS - SIS-paket - SIS paketi - пакунок SIS - Gói SIS - SIS 软件包 - SIS 套件 - SIS - Symbian Installation File - - - - - - - - SISX package - حزمة SISX - Pakunak SISX - Пакет — SISX - paquet SISX - Balíček SISX - SISX-pakke - SISX-Paket - πακέτο SISX - SISX package - SISX-pakaĵo - paquete SISX - SISX paketea - SISX-paketti - SISX pakki - paquet SISX - pacáiste SISX - paquete SISX - חבילת SISX - SISX paket - SISX csomag - Paket SISX - Pacchetto SISX - SISX パッケージ - SISX дестесі - SISX 패키지 - SISX paketas - SISX pakotne - SISX-pakke - SISX-pakket - SISX-pakke - Pakiet SISX - Pacote SISX - Pachet SISX - пакет SISX - Balíček SISX - Datoteka paketa SISX - Paketë SISX - SISX-paket - SISX paketi - пакунок SISX - Gói SISX - SISX 软件包 - SISX 套件 - SIS - Symbian Installation File - - - - - - - - Network Packet Capture - Прихванати пакети по мрежата - captura de paquets de xarxa - Network Packet Capture - Netværkspakkeoptegnelse - Netzwerk-Paketmitschnitt - Σύλληψη Πακέτων Δικτύου - Network Packet Capture - Caputra de paquete de red - capture de paquet réseau - Captura de Network Packet - לכידה של מנות נתונים ברשת - Hálózati csomagelfogás - Tangkapan Paket Jaringan - Cattura pacchetti rete - ネットワークパケットキャプチャー - ქსელური პაკეტის ანაბეჭდი - ұсталған желілік пакеттер - 네트워크 패킷 캡처 - Network Packet Capture - Network Packet Capture - Przechwycenie pakietu sieciowego - Pacote de captura de rede - захваченные сетевые пакеты - Zajem omrežnih paketov - перехоплені дані мережевих пакетів - 网络包抓取 - 網路封包捕捉 - - - - - - - - - - - - WordPerfect document - مستند WordPerfect - WordPerfect sənədi - Dakument WordPerfect - Документ — WordPerfect - document de WordPerfect - Dokument WordPerfect - Dogfen WordPerfect - WordPerfect-dokument - WordPerfect-Dokument - έγγραφο WordPerfect - WordPerfect document - WordPerfect-dokumento - documento de WordPerfect - WordPerfect dokumentua - WordPerfect-asiakirja - WordPerfect skjal - document WordPerfect - cáipéis WordPerfect - documento de WordPerfect - מסמך WordPerfect - WordPerfect dokument - WordPerfect-dokumentum - Dokumen WordPerfect - Documento WordPerfect - WordPerfect ドキュメント - WordPerfect құжаты - 워드퍼펙트 문서 - WordPerfect dokumentas - WordPerfect dokuments - Dokumen WordPerfect - WordPerfect-dokument - WordPerfect-document - WordPerfect-dokument - Dokument WordPerfect - documento do WordPerfect - Documento do WordPerfect - Document WordPerfect - документ WordPerfect - Dokument WordPerfect - Dokument WordPerfect - Dokument WordPerfect - WordPerfect документ - WordPerfect-dokument - документ WordPerfect - Tài liệu WordPerfect - WordPerfect 文档 - WordPerfect 文件 - - - - - - - - - - - - - - - - SPSS Portable Data File - ملف بيانات SPSS متنقلة - Данни — SPSS, преносими - fitxer de dades portables SPSS - Soubor přenositelných dat SPSS - Portabel SPSS-datafil - SPSS portable Datendatei - φορητό αρχείο δεδομένων SPSS - SPSS Portable Data File - archivo de datos portable SPSS - SPSS datuen fitxategi eramangarria - SPSS flytifør dátufíla - fichier portable de données SPSS - comhad iniompartha sonraí SPSS - ficheiro de datos portábel SPSS - קובץ מידע נייד SPSS - SPSS prenosiva podatkovna datoteka - SPSS hordozható adatfájl - Berkas Data Portabel SPSS - File dati SPSS Portable - SPSS ポータブルデータファイル - SPSS тасымалы ақпарат файлы - SPSS 이동식 데이터 파일 - SPSS perkeliamų duomenų failas - SPSS pārvietojamu datu datne - SPSS Portable Databestand - Plik przenośnych danych SPSS - Arquivo de Dados Portáteis SPSS - Fișier portabil de date SPSS - файл переносимых данных SPSS - Súbor prenosných dát SPSS - Prenosna podatkovna datoteka SPSS - Portabel SPSS-datafil - файл даних SPSS Portable - SPSS 便携式数据文件 - SPSS 可攜式資料檔 - - - - - - - SPSS Data File - ملف بيانات SPSS - Данни — SPSS - fitxer de dades SPSS - Datový soubor SPSS - SPSS-datafil - SPSS-Datendatei - αρχείο δεδομένων SPSS - SPSS Data File - archivo de datos SPSS - SPSS datuen fitxategia - SPSS dátufíla - fichier de données SPSS - comhad sonraí SPSS - ficheiro de datos SPSS - קובץ מידע SPSS - SPSS podatkovna datoteka - SPSS adatfájl - Berkas Data SPSS - File dati SPSS - SPSS データファイル - SPSS ақпарат файлы - SPSS 데이터 파일 - SPSS duomenų failas - SPSS datu datne - SPSS Databstand - Plik danych SPSS - Arquivo de dados SPSS - Fișier date SPSS - файл данных SPSS - Dátový súbor SPSS - Podatkovna datoteka SPSS - SPSS-datafil - файл даних SPSS - SPSS 数据文件 - SPSS 資料檔 - - - - - - - - XBEL bookmarks - علامات XBEL - Zakładki XBEL - Отметки — XBEL - llista d'adreces d'interès XBEL - Záložky XBEL - XBEL-bogmærker - XBEL-Lesezeichen - σελιδοδείκτες XBEL - XBEL bookmarks - XBEL-legosignoj - marcadores XBEL - XBEL laster-markak - XBEL-kirjanmerkit - XBEL bókamerki - marque-pages XBEL - leabharmharcanna XBEL - Marcadores XBEL - סמניית XBEL - XBEL knjižne oznake - XBEL-könyvjelzők - Bookmark XBEL - Segnalibri XBEL - XBEL ブックマーク - XBEL бетбелгілері - XBEL 책갈피 - XBEL žymelės - XBEL grāmatzīmes - Tandabuku XBEL - XBEL-bokmerker - XBEL-bladwijzers - XBEL-bokmerker - Zakładki XBEL - marcadores XBEL - Marcadores do XBEL - Semne de carte XBEL - закладки XBEL - Záložky XBEL - Datoteka zaznamkov XBEL - Libërshënues XBEL - XBEL обележивачи - XBEL-bokmärken - закладки XBEL - Liên kết đã lưu XBEL - XBEL 书签 - XBEL 格式書籤 - XBEL - XML Bookmark Exchange Language - - - - - - - - - 7-zip archive - أرشيف 7-zip - Archiŭ 7-zip - Архив — 7-zip - arxiu 7-zip - Archiv 7-zip - 7-zip-arkiv - 7zip-Archiv - αρχείο 7-zip - 7-zip archive - 7z-arkivo - archivador 7-zip - 7-zip artxiboa - 7-zip-arkisto - 7-zip skjalasavn - archive 7-zip - cartlann 7-zip - arquivo 7-zip - ארכיון 7-zip - 7-zip arhiva - 7-zip archívum - Arsip 7-zip - Archivio 7-zip - 7-zip アーカイブ - 7-zip არქივი - 7-zip архиві - 7-ZIP 압축 파일 - 7-zip archyvas - 7-zip arhīvs - 7-zip-arkiv - 7-zip-archief - 7-zip-arkiv - Archiwum 7-zip - Pacote 7-zip - Arhivă 7-zip - архив 7-zip - Archív 7-zip - Datoteka arhiva 7-zip - Arkiv 7-zip - 7-zip-arkiv - 7-Zip arşivi - архів 7-zip - Kho nén 7-zip - 7-zip 归档文件 - 7-zip 封存檔 - - - - - - - - AbiWord document - مستند آبي وورد - Dakument AbiWord - Документ — AbiWord - document d'AbiWord - Dokument AbiWord - AbiWord-dokument - AbiWord-Dokument - έγγραφο AbiWord - AbiWord document - AbiWord-dokumento - documento de Abiword - AbiWord dokumentua - AbiWord-asiakirja - AbiWord skjal - document AbiWord - cáipéis AbiWord - documento de AbiWord - מסמך AbiWord - AbiWord dokument - AbiWord-dokumentum - Dokumen AbiWord - Documento AbiWord - AbiWord ドキュメント - AbiWord-ის დოკუმენტი - AbiWord құжаты - AbiWord 문서 - AbiWord dokumentas - AbiWord dokuments - Dokumen AbiWord - AbiWord-dokument - AbiWord-document - AbiWord-dokument - Dokument AbiWord - documento AbiWord - Documento do AbiWord - Document AbiWord - документ AbiWord - Dokument AbiWord - Dokument AbiWord - Dokument AbiWord - Абиворд документ - AbiWord-dokument - AbiWord belgesi - документ AbiWord - Tài liệu AbiWord - AbiWord 文档 - AbiWord 文件 - - - - - - - - - - - - - - CD image cuesheet - صفيحة صورة الـCD جديلة - Infarmacyjny arkuš vyjavy CD - Описание на изображение на CD - «cuesheet» d'imatge de CD - Rozvržení stop obrazu CD - Cd-aftrykscuesheet - CD-Abbild-Cuesheet - CD image cuesheet - cue sheet de una imagen de CD - CD irudiaren CUE orria - CD-vedos cuesheet - index de pistes de CD - bileog chiúáil íomhá CD - cue sheet dunha imaxe de CD - גליון נתונים לתמונת דיסק - CD kép cuesheet - Citra cuesheet CD - Cuesheet immagine CD - CD イメージキューシート - CD бейнесінің құрама кестесі - CD 이미지 큐시트 - CD atvaizdžio aprašas - CD attēla rindulapa - Filliste for CD-avtrykk - CD-inhoudsopgave - CD-bilete-indeksfil - Obraz cuesheet płyty CD - Índice de Imagem de CD - Imagine CD cuesheet - таблица содержания образа CD - Rozvrhnutie stôp obrazu CD - Datoteka razpredelnice odtisa CD cue - Cuesheet imazhi CD - Indexblad för cd-avbild - таблиця CUE образу CD - Tờ tín hiệu báo ảnh CD - CD 映像标记文件 - CD 映像指示表 - - - - - - Lotus AmiPro document - مستند Lotus AmiPro - Lotus AmiPro sənədi - Dakument Lotus AmiPro - Документ — Lotus AmiPro - document de Lotus AmiPro - Dokument Lotus AmiPro - Dogfen Lotus AmiPro - Lotus AmiPro-dokument - Lotus-AmiPro-Dokument - έγγραφο Lotus AmiPro - Lotus AmiPro document - dokumento de Lotus AmiPro - documento de Lotus AmiPro - Lotus AmiPro dokumentua - Lotus AmiPro -asiakirja - Lotus AmiPro skjal - document Lotus AmiPro - cáipéis Lotus AmiPro - documento de Lotus AmiPro - מסמך של Lotus AmiPro - Lotus AmiPro dokument - Lotus AmiPro-dokumentum - Dokumen Lotus AmiPro - Documento Lotus AmiPro - Lotus AmiPro ドキュメント - Lotus AmiPro құжаты - Lotus AmiPro 문서 - Lotus AmiPro dokumentas - Lotus AmiPro dokuments - Dokumen Lotus AmiPro - Lotus AmiPro-dokument - Lotus AmiPro-document - Lotus AmiPro-dokument - Dokument Lotus AmiPro - documento Lotus AmiPro - Documento do Lotus AmiPro - Document Lotus AmiPro - документ Lotus AmiPro - Dokument Lotus AmiPro - Dokument Lotus AmiPro - Dokument Lotus AmiPro - Лотус АмиПро документ - Lotus AmiPro-dokument - документ Lotus AmiPro - Tài liệu Lotus AmiPro - Lotus AmiPro 文档 - Lotus AmiPro 文件 - - - - - AportisDoc document - مستند AportisDoc - Документ — AportisDoc - document AportisDoc - Dokument AportisDoc - AportisDoc-dokument - AportisDoc-Dokument - έγγραφο AportisDoc - AportisDoc document - AportisDoc-dokumento - documento AportisDoc - AportisDoc dokumentua - AportisDoc-asiakirja - AportisDoc skjal - document AportisDoc - cáipéis AportisDoc - documento de AportiDoc - מסמך AportisDoc - AportisDoc dokument - AportisDoc-dokumentum - Dokumen AportisDoc - Documento AportisDoc - AportisDoc ドキュメント - AportisDoc-ის დოკუმენტი - AportisDoc құжаты - AportisDoc 문서 - AportisDoc dokumentas - AportisDoc dokuments - AportisDoc-document - Dokument AportisDoc - Documento do AportisDoc - Document AportisDoc - документ AportisDoc - Dokument AportisDoc - Dokument AportisDoc - AportisDoc-dokument - AportisDoc belgesi - документ AportisDoc - Tài liệu AportisDoc - AportisDoc 文档 - AportisDoc 文件 - - - - - - - - - - - Applix Spreadsheets spreadsheet - جداول بيانات Applix - Raźlikovy arkuš Applix Spreadsheets - Таблица — Applix Spreadsheets - full de càlcul d'Applix Spreadsheets - Sešit Applix Spreadsheets - Applix Spreadsheets-regneark - Applix-Spreadsheets-Tabelle - λογιστικό φύλλο Applix Spreadsheets - Applix Spreadsheets spreadsheet - sterntabelo de Applix Spreadsheets - hoja de cálculo de Applix Spreadsheets - Applix Spreadsheets kalkulu-orria - Applix Spreadsheets -taulukko - Applix Spreadsheets rokniark - feuille de calcul Applix - scarbhileog Applix Spreadsheets - folla de cálculo de Applix - גליון נתונים של Applix Spreadsheets - Applix Spreadsheets proračunska tablica - Applix Spreadsheets-munkafüzet - Lembar sebar Applix Spreadsheets - Foglio di calcolo Applix Spreadsheets - Applix Spreadsheets スプレッドシート - Applix Spreadsheets-ის ცხრილი - Applix Spreadsheets электрондық кестесі - Applix 스프레드시트 - Applix Spreadsheets skaičialentė - Applix Spreadsheets izklājlapa - Hamparan Applix Spreadsheets - Applix Spreadsheets-regneark - Applix Spreadsheets-rekenblad - Applix Spreadsheets-dokument - Arkusz Applix Spreadsheets - folha de cálculo Applix Spreadsheets - Planilha do Applix Spreadsheets - Foaie de calcul Applix - электронная таблица Applix Spreadsheets - Zošit Applix Spreadsheets - Razpredelnica Applix Spreadsheets - Fletë llogaritjesh Applix Spreadsheets - Applix табеларни документ - Applix Spreadsheets-kalkylblad - ел. таблиця Applix Spreadsheets - Bảng tính Applix Spreadsheets - Applix Spreadsheets 工作簿 - Applix Spreadsheets 試算表 - - - - - - - - - - - Applix Words document - مستند كلمات Applix - Applix Words sənədi - Dakument Applix Words - Документ — Applix Words - document d'Applix Words - Dokument Applix Words - Dogfen Applix Words - Applix Words-dokument - Applix-Words-Dokument - έγγραφο Applix Words - Applix Words document - dokumento de Applix Words - documento de Applix Words - Applix Words dokumentua - Applix Words -asiakirja - Applix Words skjal - document Applix Words - cáipéis Applix Words - documento de Applix Words - מסמך של Applix Words - Applix Words dokument - Applix Words-dokumentum - Dokumen Applix Words - Documento Applix Words - Applix Words ドキュメント - Applix Words-ის დოკუმენტი - Applix Words құжаты - Applix Words 문서 - Applix Words dokumentas - Applix Words dokuments - Dokumen Perkataan Applix - Applix Words-dokument - Applix Words-document - Applix Words dokument - Dokument Applix Words - documento Applix Words - Documento do Applix Words - Document Applix Words - документ Applix Words - Dokument Applix Words - Dokument Applix Words - Dokument Applix Words - Applix Words документ - Applix Words-dokument - документ Applix Words - Tài liệu Applix Words - Applix Words 文档 - Applix Words 文件 - - - - - - - - - - ARC archive - أرشيف ARC - Archiŭ ARC - Архив — ARC - arxiu ARC - Archiv ARC - ARC-arkiv - ARC-Archiv - αρχείο ARC - ARC archive - ARC-arkivo - archivador ARC - ARC artxiboa - ARC-arkisto - ARC skjalasavn - archive ARC - cartlann ARC - arquivo ARC - ארכיון ARC - ARC arhiva - ARC-archívum - Arsip ARC - Archivio ARC - ARC アーカイブ - ARC არქივი - ARC архиві - ARC 압축 파일 - ARC archyvas - ARC arhīvs - ARC-arkiv - ARC-archief - ARC-arkiv - Archiwum ARC - Pacote ARC - Arhivă ARC - архив ARC - Archív ARC - Datoteka arhiva ARC - Arkiv ARC - ARC-arkiv - ARC arşivi - архів ARC - Kho nén ARC - ARC 归档文件 - ARC 封存檔 - - - - - - - - - - - - AR archive - أرشيف AR - Archiŭ AR - Архив — AR - arxiu AR - Archiv AR - AR-arkiv - AR-Archiv - σρχείο AR - AR archive - AR-arkivo - archivador AR - AR artxiboa - AR-arkisto - AR skjalasavn - archive AR - cartlann AR - arquivo AR - ארכיון AR - AR arhiva - AR-archívum - Arsip AR - Archivio AR - AR アーカイブ - AR არქივი - AR архиві - AR 묶음 파일 - AR archyvas - AR arhīvs - Arkib AR - AR-arkiv - AR-archief - AR-arkiv - Archiwum AR - arquivo AR - Pacote AR - Arhivă AR - архив AR - Archív AR - Datoteka arhiva AR - Arkiv AR - АР архива - AR-arkiv - AR arşivi - архів AR - Kho nén AR - AR 归档文件 - AR 封存檔 - - - - - - - - - - ARJ archive - أرشيف ARJ - ARJ arxivi - Archiŭ ARJ - Архив — ARJ - arxiu ARJ - Archiv ARJ - Archif ARJ - ARJ-arkiv - ARJ-Archiv - αρχείο ARJ - ARJ archive - ARJ-arkivo - archivador ARJ - ARJ artxiboa - ARJ-arkisto - ARJ skjalasavn - archive ARJ - cartlann ARJ - arquivo ARJ - ארכיון ARJ - ARJ arhiva - ARJ-archívum - Arsip ARJ - Archivio ARJ - ARJ アーカイブ - ARJ არქივი - ARJ архиві - ARJ 압축 파일 - ARJ archyvas - ARJ arhīvs - Arkib ARJ - ARJ-arkiv - ARJ-archief - ARJ-arkiv - Archiwum ARJ - arquivo ARJ - Pacote ARJ - Arhivă ARJ - архив ARJ - Archív ARJ - Datoteka arhiva ARJ - Arkiv ARJ - ARJ архива - ARJ-arkiv - ARJ arşivi - архів ARJ - Kho nén ARJ - ARJ 归档文件 - ARJ 封存檔 - ARJ - Archived by Robert Jung - - - - - - - - ASP page - صفحة ASP - Staronka ASP - Страница — ASP - pàgina ASP - Stránka ASP - ASP-side - ASP-Seite - σελίδα ASP - ASP page - ASP-paĝo - página ASP - ASP orria - ASP-sivu - ASP síða - page ASP - leathanach ASP - páxina ASP - עמוד ASP - ASP stranica - ASP oldal - Halaman ASP - Pagina ASP - ASP ページ - ASP გვერდი - ASP парағы - ASP 페이지 - ASP puslapis - ASP lapa - ASP-side - ASP-pagina - ASP-side - Strona ASP - Página ASP - Pagină ASP - страница ASP - Stránka ASP - Datoteka spletne strani ASP - Faqe ASP - ASP-sida - сторінка ASP - Trang ASP - ASP 页面 - ASP 頁面 - ASP - Active Server Page - - - - - - AWK script - سكربت AWK - AWK skripti - Skrypt AWK - Скрипт — AWK - script AWK - Skript AWK - Sgript AWK - AWK-program - AWK-Skript - πρόγραμμα εντολών AWK - AWK script - AWK-skripto - script en AWK - AWK script-a - AWK-komentotiedosto - AWK boðrøð - script AWK - script AWK - script de AWK - תסריט AWK - AWK skripta - AWK-parancsfájl - Skrip AWK - Script AWK - AWK スクリプト - AWK სცენარი - AWK сценарийі - AWK 스크립트 - AWK scenarijus - AWK skripts - Skrip AWK - AWK-skript - AWK-script - WAK-skript - Skrypt AWK - 'script' AWK - Script AWK - Script AWK - сценарий AWK - Skript AWK - Skriptna datoteka AWK - Script AWK - AWK скрипта - AWK-skript - AWK betiği - скрипт AWK - Văn lệnh AWK - AWK 脚本 - AWK 指令稿 - - - - - - - - - - - - - - - - - - - BCPIO document - مستند BCPIO - BCPIO sənədi - Dakument BCPIO - Документ — BCPIO - document BCPIO - Dokument BCPIO - Dogfen BCPIO - BCPIO-dokument - BCPIO-Dokument - έγγραφο BCPIO - BCPIO document - BCPIO-dokumento - documento BCPIO - BCPIO dokumentua - BCPIO-asiakirja - BCPIO skjal - document BCPIO - cáipéis BCPIO - documento BCPIO - מסמך של BCPO - BCPIO dokument - BCPIO-dokumentum - Dokumen BCPIO - Documento BCPIO - BCPIO ドキュメント - BCPIO-ის დოკუმენტი - BCPIO құжаты - BCPIO 문서 - BCPIO dokumentas - BCPIO dokuments - Dokumen BCPIO - BCPIO-dokument - BCPIO-document - BCPIO-dokument - Dokument BCPIO - documento BCPIO - Documento BCPIO - Document BCPIO - документ BCPIO - Dokument BCPIO - Dokument BCPIO - Dokument BCPIO - BCPIO документ - BCPIO-dokument - BCPIO belgesi - документ BCPIO - Tài liệu BCPIO - BCPIO 文档 - BCPIO 文件 - BCPIO - Binary CPIO - - - - - BitTorrent seed file - ملف باذر البت تورنت - BitTorrent seed faylı - Fajł krynicy BitTorrent - Файл-източник — BitTorrent - fitxer llavor de BitTorrent - Soubor BitTorrent - Ffeil hadu BitTorrent - BitTorrent-frøfil - BitTorrent-Seed-Datei - αρχείο BitTorrent seed - BitTorrent seed file - BitTorrent-semdosiero - archivo semilla de BitTorrent - BitTorrent hazi-fitxategia - BitTorrent-siementiedosto - BitTorrent seed fíla - fichier graine BitTorrent - comhad síl BitTorrent - ficheiro de orixe BitTorrent - קובץ זריעה של BitTorrent - BitTorrent-magfájl - Berkas benih BitTorrent - File seed BitTorrent - BitTorrent シードファイル - BitTorrent көз файлы - 비트토렌트 시드 파일 - BitTorrent šaltinio failas - BitTorrent avota datne - Fail seed BitTorrent - Fil med utgangsverdi for BitTorrent - BitTorrent-bestand - Nedlastingsfil for BitTorrent - Plik ziarna BitTorrent - ficheiro de origem BitTorrent - Arquivo semente BitTorrent - Fișier sursă-completă BitTorrent - файл источника BitTorrent - Súbor BitTorrent - Datoteka sejanja BitTorrent - File bazë BitTorrent - Датотека са БитТорентовим полазиштима - BitTorrent-distributionsfil - файл поширення BitTorrent - Tải tập hạt BitTorrent - BitTorrent 种子文件 - BitTorrent 種子檔 - - - - - - - Blender scene - مشهد بلندر - Scena Blender - Сцена — Blender - escena Blender - Scéna Blender - Blenderscene - Blender-Szene - σκηνή Blender - Blender scene - Blender-sceno - escena de Blender - Blender-eko fitxategia - Blender-näkymä - Blender leikmynd - scène Blender - radharc Blender - escena de Blender - סצנת Blender - Blender scena - Blender-jelenet - Scene Blender - Scena Blender - Blender シーン - Blender-ის სცენა - Blender сахнасы - Blender 장면 - Blender scena - Blender aina - Babak Blender - Blender-scene - Blender-scène - Blender-scene - Scena programu Blender - cenário Blender - Cena do Blender - Scenă Blender - сцена Blender - Scéna Blender - Datoteka scene Blender - Skenë Blender - Блендер сцена - Blender-scen - сцена Blender - Cảnh Blender - Blender 场景 - Blender 場景 - - - - - - - - - - TeX DVI document (bzip-compressed) - مستند TeX DVI (مضغوط-bzip) - Dakument TeX DVI (bzip-skampresavany) - Документ — TeX DVI, компресиран с bzip - document TeX DVI (comprimit amb bzip) - Dokument TeX DVI (komprimovaný pomocí bzip) - TeX DVI-dokument (bzip-komprimeret) - TeX-DVI-Dokument (bzip-komprimiert) - αρχείο TeX DVI (συμπιεσμένο με bzip) - TeX DVI document (bzip-compressed) - documento DVI de TeX (comprimido con bzip) - TeX DVI dokumentua (bzip-ekin konprimitua) - TeX DVI -asiakirja (bzip-pakattu) - TeX DVI skjal (bzip-stappað) - document DVI TeX (compressé bzip) - cáipéis DVI TeX (comhbhrúite le bzip) - documento DVI de TeX (comprimido con bzip) - מסמך מסוג TeX DVI (מכווץ ע"י bzip) - TeX DVI dokument (komprimiran bzip-om) - TeX DVI dokumentum (bzip-pel tömörítve) - Dokumen TeX DVI (terkompresi bzip) - Documento TeX DVI (compresso con bzip) - Tex DVI ドキュメント (bzip 圧縮) - TeX DVI құжаты (bzip-пен сығылған) - TeX DVI 문서 (BZIP 압축) - TeX DVI dokumentas (suglaudintas su bzip) - TeX DVI dokuments (saspiests ar bzip) - TeX DVI-dokument (bzip-komprimert) - TeX DVI-document (ingepakt met bzip) - TeX DVI-dokument (pakka med bzip) - Dokument TeX DVI (kompresja bzip) - Documento DVI TeX (compactado com bzip) - Document TeX DVI (comprimat bzip) - документ TeX DVI (сжатый bzip) - Dokument TeX DVI (komprimovaný pomocou bzip) - Dokument TeX DVI (stisnjen z bzip) - Dokument Tex DVI (i kompresuar me bzip) - TeX DVI-dokument (bzip-komprimerat) - документ TeX DVI (стиснений bzip) - Tài liệu DVI TeX (đã nén bzip) - TeX DVI 文档(gzip 压缩) - TeX DVI 文件 (bzip 格式壓縮) - - - - - - Bzip archive - أرشيف Bzip - Archiŭ bzip - Архив — bzip - arxiu bzip - Archiv bzip - Bzip-arkiv - Bzip-Archiv - συμπιεσμένο αρχείο Bzip - Bzip archive - Bzip-arkivo - archivador Bzip - Bzip artxiboa - Bzip-arkisto - Bzip skjalasavn - archive bzip - cartlann Bzip - arquivo Bzip - ארכיון Bzip - Bzip arhiva - Bzip archívum - Arsip Bzip - Archivio bzip - Bzip アーカイブ - Bzip არქივი - Bzip архиві - BZIP 압축 파일 - Bzip archyvas - Bzip arhīvs - Bzip-arkiv - Bzip-archief - Bzip-arkiv - Archiwum bzip - Pacote Bzip - Arhivă Bzip - архив BZIP - Archív bzip - Datoteka arhiva Bzip - Arkiv bzip - Bzip-arkiv - Bzip arşivi - архів bzip - Kho nén bzip - bzip 归档文件 - Bzip 封存檔 - - - - - - - - - - Tar archive (bzip-compressed) - أرشيف Tar (مضغوط-bzip) - Archiŭ tar (bzip-skampresavany) - Архив — tar, компресиран с bzip - arxiu tar (comprimit amb bzip) - Archiv tar (komprimovaný pomocí bzip) - Tar-arkiv (bzip-komprimeret) - Tar-Archiv (bzip-komprimiert) - αρχείο Tar (συμπιεσμένο με bzip) - Tar archive (bzip-compressed) - archivador Tar (comprimido con bzip) - Tar artxiboa (bzip-ekin konprimitua) - Tar-arkisto (bzip-pakattu) - Tar skjalasavn (bzip-stappað) - archive tar (compressée bzip) - cartlann Tar (comhbhrúite le bzip) - arquivo Tar (comprimido con bzip) - ארכיון Tar (מכווץ ע"י bzip) - Tar arhiva (komprimirana bzip-om) - Tar archívum (bzip-pel tömörítve) - Arsip Tar (terkompresi bzip) - Archivio tar (compresso con bzip) - Tar アーカイブ (bzip 圧縮) - Tar архиві (bzip-пен сығылған) - TAR 묶음 파일 (BZIP 압축) - Tar archyvas (suglaudintas su bzip) - Tar arhīvs (saspiests ar bzip) - Tar-arkiv (bzip-komprimert) - Tar-archief (ingepakt met bzip) - Tar-arkiv (pakka med bzip) - Archiwum tar (kompresja bzip) - Pacote tar (compactado com bzip) - Arhivă Tar (comprimată bzip) - архив TAR (сжатый BZIP) - Archív tar (komprimovaný pomocou bzip) - Datoteka arhiva Tar (stisnjen z bzip) - Arkiv tar (i kompresuar me bzip) - Tar-arkiv (bzip-komprimerat) - архів tar (стиснений bzip) - Kho nén tar (đã nén bzip) - Tar 归档文件(bzip 压缩) - Tar 封存檔 (bzip 格式壓縮) - - - - - - - - - - PDF document (bzip-compressed) - مستند PDF (مضغوط-bzip) - Dakument PDF (bzip-skampresavany) - Документ — PDF, компресиран с bzip - document PDF (comprimit amb bzip) - Dokument PDF (komprimovaný pomocí bzip) - PDF-dokument (bzip-komprimeret) - PDF-Dokument (bzip-komprimiert) - έγγραφο PDF (συμπιεσμένο με bzip) - PDF document (bzip-compressed) - documento PDF (comprimido con bzip) - PostScript dokumentua (bzip-ekin konprimitua) - PDF-asiakirja (bzip-pakattu) - PDF skjal (bzip-stappað) - document PDF (compressé bzip) - cáipéis PDF (comhbhrúite le bzip) - documento PDF (comprimido en bzip) - מסמך PDF (מכווץ ע"י bzip) - PDF dokumentum (bzip-tömörítésű) - Dokumen PDF (terkompresi bzip) - Documento PDF (compresso con bzip) - PDF ドキュメント (bzip 圧縮) - PDF құжаты (bzip-пен сығылған) - PDF 문서 (BZIP 압축) - PDF dokumentas (suglaudintas su bzip) - PDF dokuments (saspiests ar bzip) - PDF-dokument (bzip-komprimert) - PDF-document (ingepakt met bzip) - PDF-dokument (pakka med bzip) - Dokument PDF (kompresja bzip) - Documento PDF (compactado com bzip) - Document PDF (comprimat bzip) - документ PDF (сжатый bzip) - Dokument PDF (komprimovaný pomocou bzip) - Dokument PDF (stisnjen z bzip) - Dokument PDF (i kompresuar me bzip) - PDF-dokument (bzip-komprimerat) - PDF belgesi (bzip ile sıkıştırılmış) - документ PDF (стиснений bzip) - Tài liệu PDF (đã nén bzip) - PDF 文档(bzip 压缩) - PDF 文件 (bzip 格式壓縮) - - - - - - PostScript document (bzip-compressed) - مستند PostScript (مضغوط-bzip) - Dakument PostScript (bzip-skampresavany) - Документ — PostScript, компресиран с bzip - document PostScript (comprimit amb bzip) - Dokument PostScript (komprimovaný pomocí bzip) - PostScript-dokument (bzip-komprimeret) - PostScript-Dokument (bzip-komprimiert) - έγγραφο PostScript (συμπιεσμένο με bzip) - PostScript document (bzip-compressed) - documento PostScript (comprimido con bzip) - PostScript dokumentua (bzip-ekin konprimitua) - PostScript-asiakirja (bzip-pakattu) - PostScript skjal (bzip-stappað) - document PostScript (compressé bzip) - cáipéis PostScript (comhbhrúite le bzip) - documento PostScript (comprimido con bzip) - מסמך PostDcript (מכווץ ע"י bzip) - PostScript dokumentum (bzip-tömörítésű) - Dokumen PostScript (terkompresi bzip) - Documento PostScript (compresso con bzip) - PostScript ドキュメント (bzip 圧縮) - PostScript құжаты (bzip-пен сығылған) - 포스트스크립트 문서 (BZIP 압축) - PostScript dokumentas (suglaudintas su bzip) - PostScript dokuments (saspiests ar bzip) - PostScript-dokument (bzip-komprimert) - PostScript-document (ingepakt met bzip) - PostScript-dokument (pakka med bzip) - Dokument Postscript (kompresja bzip) - Documento PostScript (compactado com bzip) - Document PostScript (comprimat bzip) - документ PostScript (сжатый bzip) - Dokument PostScript (komprimovaný pomocou bzip) - Dokument PostScript (stisnjen z bzip) - Dokument PostScript (i kompresuar me bzip) - Postscript-dokument (bzip-komprimerat) - документ PostScript (стиснене bzip) - Tài liệu PostScript (đã nén bzip) - PostScript 文档(bzip 压缩) - PostScript 文件 (bzip 格式壓縮) - - - - - - comic book archive - أرشيف comic book - archiŭ komiksaŭ - Архив — комикси - arxiu comic book - Archiv knihy komiksů - comic book-arkiv - Comic-Book-Archiv - συμπιεσμένο αρχείο κόμικ - comic book archive - archivador de libro de cómic - komiki artxiboa - sarjakuva-arkisto - teknisøgubóka skjalasavn - archive Comic Book - cartlann chartúin - ficheiro de libro de banda deseñada - ארכיון ספר קומי - képregényarchívum - arsip buku komik - Archivio comic book - コミックブックアーカイブ - комикстар архиві - 만화책 압축 파일 - komiksų knygos archyvas - komiksu grāmatas arhīvs - Tegneseriearkiv - stripboek-archief - teikneseriearkiv - Archiwum komiksu - Pacote de livro de revista em quadrinhos - arhivă benzi desenate - архив комиксов - Archív knihy komiksov - Datoteka arhiva stripov - Arkiv comic book - serietidningsarkiv - архів коміксів - Kho nén sách tranh chuyện vui - Comic Book 归档文件 - 漫畫書封存檔 - - - - - - comic book archive - أرشيف comic book - archiŭ komiksaŭ - Архив — комикси - arxiu comic book - Archiv knihy komiksů - comic book-arkiv - Comic-Book-Archiv - συμπιεσμένο αρχείο κόμικ - comic book archive - archivador de libro de cómic - komiki artxiboa - sarjakuva-arkisto - teknisøgubóka skjalasavn - archive Comic Book - cartlann chartúin - ficheiro de libro de banda deseñada - ארכיון ספר קומי - képregényarchívum - arsip buku komik - Archivio comic book - コミックブックアーカイブ - комикстар архиві - 만화책 압축 파일 - komiksų knygos archyvas - komiksu grāmatas arhīvs - Tegneseriearkiv - stripboek-archief - teikneseriearkiv - Archiwum komiksu - Pacote de livro de revista em quadrinhos - arhivă benzi desenate - архив комиксов - Archív knihy komiksov - Datoteka arhiva stripov - Arkiv comic book - serietidningsarkiv - архів коміксів - Kho nén sách tranh chuyện vui - Comic Book 归档文件 - 漫畫書封存檔 - - - - - - comic book archive - أرشيف comic book - archiŭ komiksaŭ - Архив — комикси - arxiu comic book - Archiv knihy komiksů - comic book-arkiv - Comic-Book-Archiv - συμπιεσμένο αρχείο κόμικ - comic book archive - archivador de libro de cómic - komiki artxiboa - sarjakuva-arkisto - teknisøgubóka skjalasavn - archive Comic Book - cartlann chartúin - ficheiro de libro de banda deseñada - ארכיון ספר קומי - képregényarchívum - arsip buku komik - Archivio comic book - コミックブックアーカイブ - комикстар архиві - 만화책 압축 파일 - komiksų knygos archyvas - komiksu grāmatas arhīvs - Tegneseriearkiv - stripboek-archief - teikneseriearkiv - Archiwum komiksu - Pacote de livro de revista em quadrinhos - arhivă benzi desenate - архив комиксов - Archív knihy komiksov - Datoteka arhiva stripov - Arkiv comic book - serietidningsarkiv - архів коміксів - Kho nén sách tranh chuyện vui - Comic Book 归档文件 - 漫畫書封存檔 - - - - - - comic book archive - أرشيف comic book - archiŭ komiksaŭ - Архив — комикси - arxiu comic book - Archiv knihy komiksů - comic book-arkiv - Comic-Book-Archiv - συμπιεσμένο αρχείο κόμικ - comic book archive - archivador de libro de cómic - komiki artxiboa - sarjakuva-arkisto - teknisøgubóka skjalasavn - archive Comic Book - cartlann chartúin - ficheiro de libro de banda deseñada - ארכיון ספר קומי - képregényarchívum - arsip buku komik - Archivio comic book - コミックブックアーカイブ - комикстар архиві - 만화책 압축 파일 - komiksų knygos archyvas - komiksu grāmatas arhīvs - Tegneseriearkiv - stripboek-archief - teikneseriearkiv - Archiwum komiksu - Pacote de livro de revista em quadrinhos - arhivă benzi desenate - архив комиксов - Archív knihy komiksov - Datoteka arhiva stripov - Arkiv comic book - serietidningsarkiv - архів коміксів - Kho nén sách tranh chuyện vui - Comic Book 归档文件 - 漫畫書封存檔 - - - - - - Lrzip archive - أرشيف Lrzip - Архив — lrzip - arxiu lrzip - Archiv Lrzip - Lrzip-arkiv - Lrzip-Archiv - συμπιεσμένο αρχείο Lrzip - Lrzip archive - Lrzip-arkivo - archivador Lrzip - Lrzip-arkisto - Lrzip skjalasavn - archive lrzip - cartlann Lrzip - arquivo Lrzip - ארכיון Lrzip - Lrzip arhiva - Lrzip archívum - Arsip Lrzip - Archivio Lrzip - Lrzip アーカイブ - Lrzip архиві - LRZIP 압축 파일 - Lrzip archyvas - Lrzip arhīvs - Lrzip archief - Archiwum lrzip - Pacote Lrzip - Arhivă Lrzip - архив LRZIP - Archív Lrzip - Datoteka arhiva Lrzip - Lrzip-arkiv - архів lrzip - Lrzip 归档文件 - Lrzip 封存檔 - - - - - - - - Tar archive (lrzip-compressed) - أرشيف Tar (مضغوط-lrzip) - Архив — tar, компресиран с lrzip - arxiu tar (comprimit amb lrzip) - Archiv tar (komprimovaný pomocí lrzip) - Tar-arkiv (lrzip-komprimeret) - Tar-Archiv (lrzip-komprimiert) - αρχείο Tar (συμπιεσμένο με lrzip) - Tar archive (lrzip-compressed) - archivador Tar (comprimido con lrzip) - Tar-arkisto (lrzip-pakattu) - Tar skjalasavn (lrzip-stappað) - archive tar (compressée lrzip) - cartlann Tar (comhbhrúite le lrzip) - arquivo Tar (comprimido con lrzip) - ארכיון Tar (מכווץ ע"י lrzip) - Tar arhiva (komprimirana lrzip-om) - Tar archívum (lrzip-pel tömörítve) - Arsip Tar (terkompresi lrzip) - Archivio tar (compresso con lrzip) - Tar アーカイブ (lrzip 圧縮) - Tar архиві (lrzip-пен сығылған) - TAR 묶음 파일 (LRZIP 압축) - Tar archyvas (suglaudintas su lrzip) - Tar arhīvs (saspiests ar lrzip) - Tar archief (lrzip-compressed) - Archiwum tar (kompresja lrzip) - Pacote tar (compactado com lrzip) - Arhivă Tar (comprimată lrzip) - архив TAR (сжатый LRZIP) - Archív tar (komprimovaný pomocou lrzip) - Datoteka arhiva Tar (stisnjen z lrzip) - Tar-arkiv (lrzip-komprimerat) - архів tar (стиснений lrzip) - Tar 归档文件 (lrzip 压缩) - Tar 封存檔 (lrzip 格式壓縮) - - - - - - - Apple disk image - Диск — Apple - imatge de disc d'Apple - Obraz disku Apple - Apple-diskaftryk - Apple-Datenträgerabbild - εικόνα δίσκου Apple - Apple disk image - imagen de disco de Apple - Apple-levytiedosto - image disque Apple - imaxe de disco de Appl - תמונת כונן Apple - Apple snimka diska - Apple lemezkép - Image disk Apple - Immagine disco Apple - Apple ディスクイメージ - Apple-ის სადისკო გამოსახულება - Apple диск бейнесі - 애플 디스크 이미지 - Apple diska attēls - Apple disk image - Obraz dysku Apple - Imagem de disco Apple - образ диска Apple Mac OS X - Obraz disku Apple - Odtis diska Apple - Apple-skivavbild - Apple disk görüntüsü - образ диска Apple - Apple 磁盘镜像 - Apple 磁碟映像 - - - - Raw disk image - - - - - Raw disk image (XZ-compressed) - - - - - - raw CD image - صورة CD خامة - suvoraja vyjava CD - Изображение — raw CD - imatge de CD en cru - Surový obraz CD - rå cd-aftryk - CD-Roh-Abbild - εικόνα περιεχομένου ψηφιακού δίσκου - raw CD image - kruda lumdiskbildo - imagen de CD en bruto - CD gordinaren irudia - raaka CD-vedos - rá CD mynd - image CD brute - amhíomhá dhlúthdhiosca - imaxe de CD en bruto - תמונת דיסק גולמית - nyers CD-lemezkép - citra CD mentah - Immagine raw CD - 生 CD イメージ - өңделмеген CD бейнесі - CD 이미지 - raw CD atvaizdis - CD jēlattēls - Imej CD mentah - rått CD-bilde - ruw CD-beeldbestand - rått CD-bilete - Surowy obraz CD - imagem em bruto de CD - Imagem bruta de CD - imagine de CD brută - образ компакт-диска - Surový obraz CD - surovi CD odtis - Imazh raw CD - сирови отисак ЦД-а - rå cd-avbild - образ raw CD - ảnh đĩa CD thô - 原始 CD 映像 - 原生 CD 映像 - - - - - - - CD Table Of Contents - جدول محتويات الـ CD - Źmieściva CD - Съдържание на CD - taula de continguts de CD - Obsah CD - Cd-indholdsfotegnelse - CD-Inhaltsverzeichnis - Πίνακας Περιεχομένων CD - CD Table Of Contents - Índice de contenidos de CD - CDaren edukien aurkibidea - CD-sisällysluettelo - CD innihaldsyvurlit - table des matières de CD - clár ábhar dlúthdhiosca - táboa de contidos de CD - תוכן עניינים של דיסק - CD sadržaj - CD tartalomjegyzék - Tabel Isi CD - Indice CD - CD Table Of Contents - CD құрама кестесі - CD 내용 목록 - CD turinys - CD satura rādītājs - Innholdsfortegnelse for CD - CD-inhoudsopgave - CD innhaldsliste - Plik zawartości płyty CD - Sumário de CD - Tabel conținut CD - таблица содержания CD - Obsah CD - Kazalo vsebine CD nosilca - Tregues CD - Cd-innehållsförteckning - зміст CD - Mục Lục của đĩa CD - CD 索引 - CD 內容目錄 - - - - - - - - - - - - - - - PGN chess game notation - تدوينة لعبة الشطرنج PGN - Zaciem ab šachmatnaj partyi PGN - Игра шах — PGN - notació de joc d'escacs PGN - Šachová notace PGN - PGN-skakspilsnotation - PGN-Schachspielnotation - σημειογραφία παιχνιδιού σκακιού PGN - PGN chess game notation - notación para juegos de ajedrez PGN - PGN xake jokoaren notazioa - PGN-šakkipelinotaatio - PGN talv teknskipan - notation de jeu d'échecs PGN - nodaireacht chluiche ficheall PGN - Notación de xogo de xadrez PGN - סימון משחק שח PGN - PGN sakkfeljegyzés - Notasi permainan catur PGN - Notazione partita a scacchi PGN - PGN チェスゲーム記録 - PGN шахмат ойыны - PGN 체스게임 기보 - PGN šachmatų žaidimo žymėjimas - PGN šaha spēles notācija - PGN sjakkspillnotasjon - PGN-schaakspelnotatie - PGN-sjakkspelnotasjon - Plik PGN notacji gry w szachy - Notação de jogo de xadrez PGN - Notație joc șah PGN - шахматная партия PGN - Šachová notácia PGN - Datoteka opomb šahovske igre PGN - Njoftim loje shahu PGN - PGN-schackpartinotation - запис гри у шахи PGN - Cách ghi lượt chơi cờ PGN - PGN 象棋游戏注记 - PGN 國際象棋棋譜 - - - - - - - - - CHM document - مستند CHM - Dakument CHM - Документ — CHM - document CHM - Dokument CHM - CHM-dokument - CHM-Dokument - έγγραφο CHM - CHM document - CHM-dokumento - documento CHM - CHM dokumentua - CHM-asiakirja - CHM skjal - document CHM - cáipéis CHM - documento CHM - מסמך CHM - CHM dokument - CHM dokumentum - Dokumen CHM - Documento CHM - CHM ドキュメント - CHM დოკუმენტი - CHM құжаты - CHM 문서 - CHM dokumentas - CHM dokuments - CHM-dokument - CHM-document - CHM-dokument - Dokument CHM - Documento CHM - Document CHM - документ CHM - Dokument CHM - Dokument CHM - Dokument CHM - CHM-dokument - документ CHM - Tài liệu CHM - CHM 文档 - CHM 文件 - CHM - Compiled Help Modules - - - - - - Java byte code - رمز بايت الـJava - Java bayt kodu - Bajtavy kod Java - Байт код за Java - codi byte de Java - Bajtový kód Java - Côd beit Java - Javabytekode - Java-Bytecode - συμβολοκώδικας Java - Java byte code - Java-bajtkodo - bytecode Java - Java byte-kodea - Java-tavukoodi - Java býtkota - code Java binaire - beartchód Java - byte code de Java - קוד Java byte - Java-bájtkód - Kode bita Java - Bytecode Java - Java バイトコード - Java байт коды - 자바 바이트코드 - Java baitinis kodas - Java bitu kods - Kod bait Java - Java-bytekode - Java-bytecode - Jave byte-kode - Kod bajtowy Java - 'byte-code' Java - Código compilado Java - Bytecode Java - байт-код Java - Bajtový kód Java - Datoteka bitne kode Java - Byte code Java - Јава бајтни ко̂д - Java-bytekod - Байт-код Java - Mã byte Java - Java 字节码 - Java 位元組碼 - - - UNIX-compressed file - ملف يونكس-مضغوط - Skampresavany UNIX-fajł - Файл — компресиран за UNIX - fitxer comprimit UNIX - Soubor komprimovaný v Unixu - UNIX-komprimeret fil - UNIX-komprimierte Datei - αρχείο συμπιεσμένο με compress - UNIX-compressed file - UNIX-kunpremita dosiero - archivo comprimido de Unix - UNIX-en konprimitutako fitxategia - UNIX-pakattu tiedosto - UNIX-stappað fíla - fichier compressé UNIX - comhad UNIX-comhbhrúite - ficheiro comprimido de UNIX - קובץ מכווץ של UNIX - UNIX-komprimirana datoteka - Tömörített UNIX-fájl - Berkas terkompresi UNIX - File compresso-UNIX - UNIX-compress ファイル - файл (UNIX-сығылған) - UNIX 압축 파일 - UNIX suglaudintas failas - UNIX saspiesta datne - Fail termampat-UNIX - UNIX-komprimert fil - UNIX-ingepakt bestand - UNIX-komprimert fil - Skompresowany plik systemu UNIX - ficheiro comprimido UNIX - Arquivo compactado do UNIX - Fișier comprimat UNIX - файл (UNIX-сжатый) - Súbor komprimovaný v Unixe - Skrčena Unix datoteka - File i kompresuar UNIX - UNIX-компресована датотека - UNIX-komprimerad fil - UNIX-sıkıştırılmış dosyası - стиснений файл UNIX - Tập tin đã nén UNIX - UNIX 压缩文件 - UNIX 格式壓縮檔 - - - - - - - - Tar archive (gzip-compressed) - أرشيف Tar (مضغوط-gzip) - Archiŭ tar (gzip-skampresavany) - Архив — tar, компресиран с gzip - arxiu tar (comprimit amb gzip) - Archiv tar (komprimovaný pomocí gzip) - Tar-arkiv (gzip-komprimeret) - Tar-Archiv (gzip-komprimiert) - αρχείο Tar (συμπιεσμένο με gzip) - Tar archive (gzip-compressed) - archivador Tar (comprimido con gzip) - Tar artxiboa (gzip-ekin konprimitua) - Tar-arkisto (gzip-pakattu) - Tar skjalasavn (gzip-stappað) - archive tar (compressée gzip) - cartlann Tar (comhbhrúite le gzip) - arquivo Tar (comprimido con gzip) - ארכיון Tar (מכווץ ע"י gzip) - Tar arhiva (komprimirana gzip-om) - Tar archívum (gzip-pel tömörítve) - Arsip Tar (terkompresi gzip) - Archivio tar (compresso con gzip) - Tar アーカイブ (gzip 圧縮) - Tar архиві (gzip-пен сығылған) - TAR 묶음 파일 (GZIP 압축) - Tar archyvas (suglaudintas su gzip) - Tar arhīvs (saspiests ar gzip) - Tar-arkiv (gzip-komprimert) - Tar-archief (ingepakt met gzip) - Tar-arkiv (pakka med gzip) - Archiwum tar (kompresja gzip) - Pacote tar (compactado com gzip) - Arhivă Tar (comprimată gzip) - архив TAR (сжатый GZIP) - Archív tar (komprimovaný pomocou gzip) - Datoteka arhiva Tar (stisnjen z gzip) - Arkiv tar (i kompresuar me gzip) - Tar-arkiv (gzip-komprimerat) - архів tar (стиснений gzip) - Kho nén tar (đã nén gzip) - Tar 归档文件(gzip 压缩) - Tar 封存檔 (gzip 格式壓縮) - - - - - - - program crash data - معلومات انهيار البرنامج - źviestki złamanaj prahramy - Данни от забиване на програма - dades de fallada de programa - Data o pádu programu - programnedbrudsdata - Daten zu Programmabsturz - δεδομένα από την κατάρρευση προγράμματος - program crash data - datumo pri kraŝo de programo - datos de cuelgue de programa - programaren kraskaduraren datuak - ohjelman kaatumistiedot - forrits sordáta - données de plantage de programme - sonraí thuairt ríomhchláir - datos de colgue do programa - מידע מקריסת תוכנה - podaci o rušenju programa - összeomlott program adatai - data program macet - Dati crash di applicazione - プログラムクラッシュデータ - апатты аяқтаудың мәліметтері - 프로그램 비정상 종료 데이터 - programos nulūžimo duomenys - programmas avārijas dati - Data program musnah - krasjdata fra program - programma-crashgegevens - data om programkrasj - Dane awarii programu - dados de estoiro de aplicação - Dados de travamento de programa - date eroare program - данные аварийного завершения - Údaje o páde programu - podatki sesutja programa - Të dhëna nga programi i bllokuar - подаци о кркљавини програма - programkraschdata - аварійні дані про програму - dữ liệu sụp đổ chương trình - 程序崩溃数据 - 程式當掉資料 - - - - - - - - - - - - - - - - - - - CPIO archive - أرشيف CPIO - CPIO arxivi - Archiŭ CPIO - Архив — CPIO - arxiu CPIO - Archiv CPIO - Archif CPIO - CPIO-arkiv - CPIO-Archiv - αρχείο CPIO - CPIO archive - CPIO-arkivo - archivador CPIO - CPIO artxiboa - CPIO-arkisto - CPIO skjalasavn - archive CPIO - cartlann CPIO - arquivo CPIO - ארכיון CPIO - CPIO arhiva - CPIO-archívum - Arsip CPIO - Archivio CPIO - CPIO アーカイブ - CPIO არქივი - CPIO архиві - CPIO 묶음 파일 - CPIO archyvas - CPIO arhīvs - Arkib CPIO - CPIO-arkiv - CPIO-archief - CPIO-arkiv - Archiwum CPIO - arquivo CPIO - Pacote CPIO - Arhivă CPIO - архив CPIO - Archív CPIO - Datoteka arhiva CPIO - Arkiv CPIO - CPIO архива - CPIO-arkiv - архів CPIO - Kho nén CPIO - CPIO 归档文件 - CPIO 封存檔 - - - - - - - - - - - CPIO archive (gzip-compressed) - أرشيف CPIO (مضغوط-gzip) - CPIO arxivi (gzip ilə sıxışdırılmış) - Archiŭ CPIO (gzip-skampresavany) - Архив — CPIO, компресиран с gzip - arxiu CPIO (comprimit amb gzip) - Archiv CPIO (komprimovaný pomocí gzip) - Archif CPIO (gywasgwyd drwy gzip) - CPIO-arkiv (gzip-komprimeret) - CPIO-Archiv (gzip-komprimiert) - αρχείο CPIO (συμπιεσμένο με gzip) - CPIO archive (gzip-compressed) - CPIO-arkivo (kunpremita per gzip) - archivador CPIO (comprimido con gzip) - CPIO artxiboa (gzip-ekin konprimitua) - CPIO-arkisto (gzip-pakattu) - CPIO skjalasavn (gzip-stappað) - archive CPIO (compressé gzip) - cartlann CPIO (comhbhrúite le gzip) - arquivo CPIO (comprimido con gzip) - ארכיון CPIO (מכווץ ע"י gzip) - CPIO arhiva (komprimirana gzip-om) - CPIO-archívum (gzip-pel tömörítve) - Arsip CPIO (terkompresi gzip) - Archivio CPIO (compresso con gzip) - CPIO (gzip 圧縮) アーカイブ - CPIO არქივი (gzip-ით შეკუმშული) - CPIO архиві (gzip-пен сығылған) - CPIO 묶음 파일 (GZIP 압축) - CPIO archyvas (suglaudintas su gzip) - CPIO arhīvs (saspiests ar gzip) - Arkib CPIO (dimampatkan-gzip) - CPIO-arkiv (gzip-komprimert) - CPIO-archief (ingepakt met gzip) - CPIO-arkiv (gzip-pakka) - Archiwum CPIO (kompresja gzip) - arquivo CPIO (comprimido com gzip) - Pacote CPIO (compactado com gzip) - Arhivă CPIO (compresie gzip) - архив CPIO (сжатый GZIP) - Archív CPIO (komprimovaný pomocou gzip) - Datoteka arhiva CPIO (skrčena z gzip) - Arkiv CPIO (kompresuar me gzip) - CPIO архива (компресована gzip-ом) - CPIO-arkiv (gzip-komprimerat) - архів CPIO (стиснений gzip) - Kho nén CPIO (đã nén gzip) - CPIO 归档文件(gzip 压缩) - CPIO 封存檔 (gzip 格式壓縮) - - - - - - C shell script - سكربت شِل سي - C qabıq skripti - Skrypt abałonki C - Скрипт — обвивка C - script en C - Skript shellu C - Sgript plisgyn C - C-skalprogram - C-Shell-Skript - πρόγραμμα εντολών φλοιού C - C shell script - skripto de C-ŝelo - script en C shell - C shell script-a - Csh-komentotiedosto - C skel boðrøð - script C shell - script bhlaosc C - script de C shell - תסריט מעטפת C - C skripta - C héj-parancsfájl - Skrip shell C - Script C shell - C シェルスクリプト - C shell сценарийі - C 셸 스크립트 - C shell scenarijus - C čaulas skripts - Skrip shell C - C-skallskript - C-shellscript - C-skalskript - Skrypt powłoki C - 'script' de consola C - Script de shell C - Script C shell - сценарий C shell - Skript shellu C - Skriptna datoteka lupine C - Script shell C - C скрипта окружења - Skalskript (csh) - C kabuk betiği - скрипт оболонки C - Văn lệnh trình bao C - C shell 脚本 - C shell 指令稿 - - - - - - - - - - - - - Xbase document - مستند Xbase - Dakument Xbase - Документ — Xbase - document Xbase - Dokument Xbase - Xbasedokument - Xbase-Dokument - έγγραφο Xbase - Xbase document - Xbase-dokumento - documento Xbase - Xbase dokumentua - Xbase-asiakirja - Xbase skjal - document Xbase - cáipéis Xbase - documento Xbase - מסמך Xbase - Xbase dokumentum - Dokumen Xbase - Documento Xbase - Xbase ドキュメント - Xbase құжаты - Xbase 문서 - Xbase dokumentas - Xbase dokuments - Xbase-dokument - Xbase-document - Xbase-dokument - Dokument Xbase - Documento do Xbase - Document Xbase - документ Xbase - Dokument Xbase - Dokument Xbase - Dokument Xbase - Xbase-dokument - Xbase belgesi - документ Xbase - Tài liệu Xbase - Xbase 文档 - Xbase 文件 - - - - - - - - ECMAScript program - برنامج ECMAScript - Prahrama ECMAScript - Програма — ECMAScript - programa ECMAScript - Program ECMAScript - ECMA-program - ECMAScript-Programm - πρόγραμμα ECMAScript - ECMAScript program - programa en ECMAScript - ECMAScript programa - ECMAScript-ohjelma - ECMAScript forrit - programme ECMAScript - ríomhchlár ECMAScript - programa en ECMAScript - תכנית EMCAScript - ECMAScript program - ECMAScript program - Program ECMAScript - Programma ECMAScript - ECMAScript プログラム - ECMAScript პროგრამა - ECMAScript программасы - ECMA스크립트 프로그램 - ECMAScript programa - ECMAScript programma - ECMAScript-program - ECMAScript-programma - ECMAScript-program - Pogram ECMAScript - Programa ECMAScript - Program ECMAScript - программа ECMAScript - Program ECMAScript - Programska datoteka ECMAScript - Program ECMAScript - ECMAScript-program - ECMAScript programı - програма мовою ECMAScript - Chương trình ECMAScript - ECMAScript 程序 - ECMAScript 程式 - - - - - - - Dreamcast ROM - Dreamcast ROM - Dreamcast ROM - ROM — Dreamcast - ROM de Dreamcast - ROM pro Dreamcast - Dreamcast-rom - Dreamcast-ROM - εικόνα μνήμης ROM Dreamcast - Dreamcast ROM - Dreamcast-NLM - ROM de Dreamcast - Dreamcast-en ROM - Dreamcast-ROM - Dreamcast ROM - ROM Dreamcast - ROM Dreamcast - ROM de Dreamcast - ROM של Dreamcast - Dreamcast ROM - Dreamcast ROM - Memori baca-saja Dreamcast - ROM Dreamcast - Dreamcast ROM - Dreamcast-ის ROM - Dreamcast ROM - 드림캐스트 롬 - Dreamcast ROM - Dreamcast ROM - ROM Dreamcast - Dreamcast-ROM - Dreamcast-ROM - Dreamcast-ROM - Plik ROM konsoli Dreamcast - ROM Dreamcast - ROM do Dreamcast - ROM Dreamcast - Dreamcast ROM - ROM pre Dreamcast - Bralni pomnilnik Dreamcast - ROM Dreamcast - Dreamcast ROM - Dreamcast-rom - ППП Dreamcast - ROM Dreamcast - Dreamcast ROM - Dreamcast ROM - - - - - Nintendo DS ROM - Nintendo DS ROM - Nintendo DS ROM - ROM — Nintendo DS - ROM de Nintendo DS - ROM pro Nintendo DS - Nintendo DS-rom - Nintendo-DS-ROM - εικόνα μνήημης ROM Nintendo DS - Nintendo DS ROM - ROM de Nintendo DS - Nintendo DS-ko ROMa - Nintendo DS-ROM - Nintendo DS ROM - ROM Nintendo DS - ROM Nintendo DS - ROM de Nintendo DS - ROM של Nintendo - Nintendo DS ROM - Nintendo DS ROM - Memori baca-saja Nintendo DS - ROM Nintendo DS - Nintendo DS ROM - Nintendo DS ROM - 닌텐도 DS 롬 - Nintendo DS ROM - Nintendo DS ROM - Nintendo DS-ROM - Nintendo-DS-ROM - Nintendo DS-ROM - Plik ROM konsoli Nintendo DS - ROM do Nintendo DS - ROM Nintendo DS - Nintendo DS ROM - ROM pre Nintendo DS - Bralni pomnilnik Nintendo DS - ROM Nintendo DS - Nintendo DS-rom - Nintendo DS ROM - ППП Nintendo - ROM DS Nintendo - Nintendo DS ROM - 任天堂 DS ROM - - - - - Debian package - حزمة ديبيان - Debian paketi - Pakunak Debian - Пакет — Debian - paquet Debian - Balíček Debianu - Pecyn Debian - Debianpakke - Debian-Paket - πακέτο Debian - Debian package - Debian-pakaĵo - paquete Debian - Debian paketea - Debian-paketti - Debian pakki - paquet Debian - pacáiste Debian - paquete de Debian - חבילת דביאן - Debian paket - Debian-csomag - Paket Debian - Pacchetto Debian - Debian パッケージ - Debian-ის პაკეტი - Debian дестесі - 데비안 패키지 - Debian paketas - Debian pakotne - Pakej Debian - Debian pakke - Debian-pakket - Debian pakke - Pakiet Debiana - pacote Debian - Pacote Debian - Pachet Debian - пакет Debian - Balíček Debianu - Datoteka paketa Debian - Paketë Debian - Debian пакет - Debianpaket - Debian paketi - пакунок Debian - Gói Debian - Debian 软件包 - Debian 套件 - - - - - - - - - - - Qt Designer file - ملف Qt Designer - Fajł Qt Designer - Файл — Qt Designer - fitxer de Qt Designer - Soubor Qt Designer - Qt Designer-fil - Qt-Designer-Datei - αρχείο Qt Designer - Qt Designer file - dosiero de Qt Designer - archivo de Qt Designer - Qt Designer Fitxategia - Qt Designer -tiedosto - Qt Designer fíla - fichier Qt Designer - comhad Qt Designer - ficheiro de Qt Designer - קובץ של Qt Designer - Qt Designer-fájl - Berkas Qt Designer - File Qt Designer - Qt Designer ファイル - Qt Designer файлы - Qt 디자이너 파일 - Qt Designer failas - Qt Designer datne - Fail Qt Designer - Qt Designer-fil - Qt Designer-bestand - Qt Designer-fil - Plik Qt Designer - ficheiro do Qt Designer - Arquivo do Qt Designer - Fișier Qt Designer - файл Qt Designer - Súbor Qt Designer - Datoteka Qt Designer - File Qt Designer - Qt Designer датотека - Qt Designer-fil - файл програми Qt-дизайнер - Tập tin thiết kế Qt Designer - Qt Designer 文件 - Qt Designer 檔案 - - - - - - - - - - Qt Markup Language file - Файл — Qt Markup - fitxer de llenguatge de marcadors Qt - Soubor Qt Markup Language - Qt Markup Language-fil - Qt-Auszeichnungssprachendatei - αρχείο Qt Markup Language - Qt Markup Language file - Archivo de lenguaje de marcado Qt - fichier Qt Markup Language - ficheiro de linguaxe de marcado Qt - קובץ שפת סימון של Qt - Qt jelölőnyelvű fájl - Berkas Bahasa Markup Qt - File Qt Markup Language - Qt マークアップ言語ファイル - Qt Markup Language файлы - Qt 마크업 언어 파일 - Qt marķēšanas valodas datne - Qt Markup Tallbestand - Plik języka znaczników Qt - Arquivo de Qt Markup Language - файл Qt Markup Language - Datoteka označevalnega jezika Qt - файл мови розмітки Qt - Qt - Qt 標記語言檔 - - - - - - - desktop configuration file - ملف تضبيط سطح المكتب - kanfihuracyjny fajł asiarodździa - Файл с информация за работния плот - fitxer de configuració d'escriptori - Soubor nastavení pracovní plochy - skrivebordskonfigurationsfil - Desktop-Konfigurationsdatei - ρυθμίσεις επιφάνειας εργασίας - desktop configuration file - dosiero de agordoj de labortablo - archivo de configuración del escritorio - Mahaigainaren konfigurazio-fitxategia - työpöydän asetustiedosto - skriviborðssamansetingarfíla - fichier de configuration desktop - comhad chumraíocht deisce - ficheiro de configuración de escritorio - קובץ הגדרות של שולחן העבודה - datoteka postavki radne površine - asztalbeállító fájl - berkas konfigurasi destop - File configurazione desktop - デスクトップ設定ファイル - жұмыс үстел баптаулар файлы - 데스크톱 설정 파일 - darbastalio konfigūracijos failas - darbvirsmas konfigurācijas datne - Fail konfigurasi desktop - konfigurasjonsfil for skrivebordet - bureaublad-configuratiebestand - skrivebordsoppsettfil - Plik konfiguracji środowiska - ficheiro de configuração de área de trabalho - Arquivo de configuração de área de trabalho - fișier de configurare al desktopului - файл настроек рабочего стола - Súbor nastavení pracovnej plochy - nastavitvena datoteka namizja - File konfigurimi desktop - датотека за подешавања радне површи - skrivbordskonfigurationsfil - файл конфігурації стільниці - tập tin cấu hình môi trường - 桌面配置文件 - 桌面組態檔 - - - - - - - - - - - - - - - FictionBook document - مستند FictionBook - Документ — FictionBook - document FictionBook - Dokument FictionBook - FictionBook-dokument - FictionBook-Dokument - έγγραφο FictionBook - FictionBook document - FictionBook-dokumento - documento FictionBook - FictionBook dokumentua - FictionBook-asiakirja - FictionBook skjal - document FictionBook - cáipéis FictionBook - documento de FictionBook - מסמך FictionBook - FictionBook dokument - FictionBook-dokumentum - Dokumen FictionBook - Documento FictionBook - FictionBook ドキュメント - FictionBook-ის დოკუმენტი - FictionBook құжаты - FictionBook 문서 - FictionBook dokumentas - FictionBook dokuments - FictionBook-document - Dokument FictionBook - Documento FictionBook - Document FictionBook - документ FictionBook - Dokument FictionBook - Dokument FictionBook - FictionBook-dokument - FictionBook belgesi - документ FictionBook - Tài liệu FictionBook - FictionBook 文档 - FictionBook 文件 - - - - - - - - - - Dia diagram - خطاطة Dia - Dia diaqramı - Dyjahrama Dia - Диаграма — Dia - diagrama de Dia - Diagram Dia - Diagram Dia - Dia-diagram - Dia-Diagramm - διάγραμμα Dia - Dia diagram - Dia-diagramo - diagrama de Dia - Dia diagrama - Dia-kaavio - Dia ritmynd - diagramme Dia - léaráid Dia - diagrama de Dia - גרף של Dia - Dia dijagram - Dia-diagram - Diagram Dia - Diagramma Dia - Dia ダイアグラム - Dia-ის დიაგრამა - Dia диаграммасы - Dia 도표 - Dia diagrama - Dia diagramma - Diagram Dia - Dia-diagram - Dia-diagram - Dia diagram - Diagram Dia - diagrama Dia - Diagrama do Dia - Diagramă Dia - диаграмма Dia - Diagram Dia - Datoteka diagrama Dia - Diagramë Dia - Диа дијаграм - Dia-diagram - діаграма Dia - Biểu đồ Dia - Dia 图表 - Dia 圖表 - - - - - - - - - - Dia shape - شكل Dia - Фигура — Dia - forma del Dia - Tvary Dia - Dia-figur - Dia-Form - σχήμα Dia - Dia shape - forma de Dia - Dia-ren forma - Dia skapur - forme Dia - cruth Dia - forma de Dia - צורה של Dia - Dia oblik - Dia alakzat - Shape Dia - Sagoma Dia - Dia 図形 - Dia сызбасы - Dia 그림 - Dia forma - Dia forma - Diavorm - Kształt Dia - Formato Dia - Figură Dia - фигура Dia - Datoteka oblik Dia - Dia-figur - форма Dia - Dia 形状 - Dia 形狀 - - - - - - - - - - TeX DVI document - مستند TeX DVI - Dakument TeX DVI - Документ — TeX DVI - document TeX DVI - Dokument TeX DVI - TeX DVI-dokument - TeX-DVI-Dokument - έγγραφο TeX DVI - TeX DVI document - DVI-dokumento de TeX - documento TeX DVI - TeX DVI dokumentua - TeX DVI -asiakirja - TeX DVI skjal - document TeX DVI - cáipéis DVI TeX - documento TeX DVI - מסמך מסוג TeX DVI - TeX DVI dokument - TeX DVI-dokumentum - Dokumen TeX DVI - Documento TeX DVI - TeX DVI ドキュメント - TeX DVI құжаты - TeX DVI 문서 - TeX DVI dokumentas - TeX DVI dokuments - Dokumen TeX DVI - TeX DVI-dokument - TeX DVI-document - TeX DVI-dokument - Dokument TeX DVI - documento TeX DVI - Documento DVI TeX - Document Tex DVI - документ TeX DVI - Dokument TeX DVI - Dokument TeX DVI - Dokument TeX DVI - ТеХ ДВИ документ - TeX DVI-dokument - документ TeX DVI - Tài liệu DVI Tex - TeX DVI 文档 - TeX DVI 文件 - DVI - Device independent file format - - - - - - - - Enlightenment theme - سمة Enlightenment - Enlightenment örtüyü - Matyŭ Enlightenment - Тема — Enlightenment - tema d'Enlightenment - Motiv Enlightenment - Thema Enlightenment - Enlightenmenttema - Enlightenment-Thema - Θέμα Enlightenment - Enlightenment theme - etoso de Enlightenment - tema de Enlightenment - Enlightenment gaia - Enlightenment-teema - Enlightenment tema - thème Enlightenment - téama Enlightenment - tema de Enlightenment - ערכת נושא של Enlightenment - Enlightenment tema - Enlightenment-téma - Tema Enlightenment - Tema Enlightenment - Enlightenment テーマ - Enlightenment-ის თემა - Enlightenment темасы - 인라이튼먼트 테마 - Enlightenment tema - Enlightenment motīvs - Tema Enlightenment - Enlightenment tema - Enlightenment-thema - Enlightenment-tema - Motyw Enlightenment - tema Enlightenment - Tema do Enlightenment - Temă Enlightenment - тема Enlightenment - Motív Enlightenment - Datoteka teme Enlightenment - Tema Enlightenment - Enlightenment тема - Enlightenment-tema - Enlightenment teması - тема Enlightenment - Sắc thái Enlightenment - Enlightenment 主题 - Enlightenment 佈景主題 - - - - Egon Animator animation - تحريكة محرك Egon - Animacyja Egon Animator - Анимация — Egon Animator - animació d'Egon Animator - Animace Egon Animator - Egon Animator-animation - Egon-Animator-Animation - κινούμενα σχέδια Egon Animator - Egon Animator animation - animacio de Egon Animator - animación de Egon Animator - Egon Animator-eko animazioa - Egon Animator -animaatio - Egon Animator teknimyndagerð - animation Egon Animator - beochan Egon Animator - animación de Egon Animator - אנימצייה של Egon Animator - Egon Animator animacija - Egon Animator-animáció - Animasi Egon Animator - Animazione Egon Animator - Egon Animator アニメーション - Egon Animator-ის ანიმაცია - Egon Animator анимациясы - Egon 애니메이터 애니메이션 - Egon Animator animacija - Egon Animator animācija - Animasi Egon Animator - Egon animator-animasjon - Egon Animator-animatie - Egon Animator-animasjon - Animacja Egon Animator - animação Egon Animator - Animação do Egon Animator - Animație Egon Animator - анимация Egon Animator - Animácia Egon Animator - Datoteka animacije Egon Animator - Animim Egon Animator - Егон аниматор анимација - Egon Animator-animering - анімація Egon Animator - Hoạt ảnh Egon Animator - Egon Animator 动画 - Egon Animator 動畫 - - - - - executable - تنفيذي - vykonvalny fajł - Изпълним файл - executable - Spustitelný soubor - kørbar - Programm - εκτελέσιμο - executable - plenumebla - ejecutable - exekutagarria - suoritettava ohjelma - inningarfør - exécutable - comhad inrite - executábel - קובץ הרצה - izvršna datoteka - futtatható - dapat dieksekusi - Eseguibile - 実行ファイル - орындалатын - 실행 파일 - vykdomasis failas - izpildāmais - Bolehlaksana - kjørbar - uitvoerbaar bestand - køyrbar - Program - executável - Executável - executabil - исполняемый - Spustiteľný súbor - izvedljiva datoteka - I ekzekutueshëm - извршна - körbar fil - çalıştırılabilir - виконуваний файл - thực hiện được - 可执行文件 - 可執行檔 - - - - - - - - - - - - - - - - - - - - - FLTK Fluid file - ملف FLTK Fluid - Fajł FLTK Fluid - Интерфейс — FLTK Fluid - fitxer Fluid FLTK - Soubor FLTK Fluid - FLTK Fluid-fil - FLTK-Fluid-Datei - FLTK Fluid file - archivo FLTK Fluid - FLTK Fluid fitxategia - FLTK Fluid -tiedosto - FLTK Fluid fíla - fichier Fluid FLTK - comhad FLTK Fluid - ficheiro FLTK Fluid - קובץ FLTK Fluid - FLTK Fluid datoteka - FLTK Fluid fájl - Berkas FLTK Fluid - File FLTK Fluid - FLTK Fluid ファイル - FLTK Fluid-ის ფაილი - FLTK Fluid файлы - FLTK Fluid 파일 - FLTK Fluid failas - FLTK Fluid datne - FLTK Fluid-fil - FLTK FLUID-bestand - FLTK Fluid-fil - Plik Fluid FLTK - Arquivo Fluid do FLTK - Fișier FLTK Fluid - файл FLTK Fluid - Súbor FLTK Fluid - Datoteka FLTK Fluid - File FLTK Fluid - FLTK Fluid-fil - FLTK Fluid dosyası - файл FLTK Fluid - Tập tin Fluid FLTK - FLTK 流体文档 - FLTK Fluid 檔 - FLTK - Fast Light Toolkit - - - - - - - - - WOFF font - WOFF - Web Open Font Format - - - - - - - - Postscript type-1 font - خط Postscript type-1 - Šryft Postscript type-1 - Шрифт — Postscript Type 1 - tipus de lletra Postscript type-1 - Písmo Postscript type-1 - PostScript type-1-skrifttype - Postscript-Typ-1-Schrift - Postscript type-1 font - tipografía PostScript tipo-1 - PostScript type-1 letra-tipoa - PostScript tyyppi-1 -asiakirja - Postscript type-1 stavasnið - police Postscript Type 1 - cló Postscript type-1 - tipo de letra PostScript tipo-1 - גופן של Postscript type-1 - Postscript type-1 betűkészlet - Fonta tipe-1 Postscript - Tipo carattere Postscript type-1 - PostScript type-1 フォント - Postscript type-1 қарібі - 포스트스크립트 Type-1 글꼴 - Postscript type-1 šriftas - Postscript 1-tipa fonts - Postscript type-1 skrift - PostScript type-1-lettertype - PostScript type 1-skrifttype - Czcionka PostScript Type-1 - Fonte PostScript tipo-1 - Font Postscript type-1 - шрифт PostScript Type-1 - Písmo Postscript type-1 - Datoteka pisave Postscript vrste-1 - Lloj gërmash Postscript type-1 - Postscript type-1-typsnitt - шрифт Postscript type-1 - Phông kiểu 1 PostScript - Postscript type-1 字体 - Postscript type-1 字型 - - - - - - - - - - - - - - - - Adobe font metrics - مقاييس خط أدوبي - Adobe yazı növü metrikləri - Metryka šryftu Adobe - Шрифтова метрика — Adobe - mètrica de tipus de lletra Adobe - Metrika písma Adobe - Metrigau Ffont Adobe - Adobe skrifttypefil - Adobe-Schriftmetriken - μετρικά γραμματοσειράς Adobe - Adobe font metrics - metrikoj de Adobe-tiparo - métricas de tipografía Adobe - Adobe letra-tipoen neurriak - Adobe-kirjasinmitat - métriques de police Adobe - meadarachtaí cló Adobe - métricas de fonte de Adobe - מדדי גופן של Adobe - Adobe mjere fonta - Adobe-betűmetrika - Metrik fonta Adobe - Metriche tipo carattere Adobe - Adobe フォントメトリック - Adobe қаріп метрикалары - 어도비 글꼴 메트릭 - Adobe šriftų metrika - Adobe fonta metrika - Metrik font Adobe - Adobe skrifttypefil - Adobe-lettertype-metrieken - Adobe skrifttypemetrikk - Metryka czcionki Adobe - métrica de tipos de letra Adobe - Métricas de fonte Adobe - Dimensiuni font Adobe - метрика шрифта Adobe - Metrika písma Adobe - Matrika pisave Adobe - Metrik lloj gërmash Adobe - Adobe метрика фонта - Adobe-typsnittsmetrik - метрики шрифту Adobe - Cách đo phông chữ Adobe - Adobe 字体参数 - Adobe 字型描述檔 - - - - - BDF font - خط BDF - BDF yazı növü - Šryft BDF - Шрифт — BDF - tipus de lletra BDF - Písmo BDF - Ffont BDF - BDF-skrifttype - BDF-Schrift - γραμματοσειρά BDF - BDF font - BDF-tiparo - tipografía BDF - BDF letra-tipoa - BDF-kirjasin - BDF stavasnið - police BDF - cló BDF - tipo de fonte BDF - גופן BDF - BDF font - BDF-betűkészlet - Fonta BDF - Tipo carattere BDF - BDF フォント - BDF қарібі - BDF 글꼴 - BDF šriftas - BDF fonts - Font BDF - BDF-skrifttype - BDF-lettertype - BDF-skrifttype - Czcionka BDF - tipo de letra BDF - Fonte BDF - Font BDF - шрифт BDF - Písmo BDF - Datoteka pisave BDF - Lloj gërme BDF - BDF фонт - BDF-typsnitt - BDF fontu - шрифт BDF - Phông chữ BDF - BDF 字体 - BDF 字型 - - - - - - - - DOS font - خط DOS - DOS yazı növü - Šryft DOS - Шрифт — DOS - tipus de lletra DOS - Písmo pro DOS - Ffont DOS - DOS-skrifttype - DOS-Schrift - γραμματοσειρά DOS - DOS font - DOS-tiparo - tipografía DOS - DOS letra-tipoa - DOS-kirjasin - DOS stavasnið - police DOS - cló DOS - tipo de fonte de DOS - גופן DOS - DOS font - DOS-betűkészlet - Fonta DOS - Tipo carattere DOS - DOS フォント - DOS қарібі - DOS 글꼴 - DOS šriftas - DOS fonts - Font DOS - DOS-skrifttype - DOS-lettertype - DOS-skrifttype - Czcionka DOS - tipo de letra DOS - Fonte do DOS - Font DOS - шрифт DOS - Písmo pre DOS - Datoteka pisave DOS - Gërmë DOS - DOS фонт - DOS-typsnitt - DOS fontu - шрифт DOS - Phông chữ DOS - DOS 字体 - DOS 字型 - - - - - - - - - Adobe FrameMaker font - خط أدوبي الصانع للإطارات - Adobe FrameMaker yazı növü - Šryft Adobe FrameMaker - Шрифт — Adobe FrameMaker - tipus de lletra d'Adobe FrameMaker - Písmo Adobe FrameMaker - Ffont Adobe FrameMaker - Adobe FrameMaker-skrifttype - Adobe-FrameMaker-Schrift - γραμματοσειρά Adobe FrameMaker - Adobe FrameMaker font - Tiparo de Adobe FrameMaker - tipografía de Adobe FrameMaker - Adobe FrameMaker-en letra-tipoa - Adobe FrameMaker -kirjasin - Adobe FrameMaker stavasnið - police Adobe FrameMaker - cló Adobe FrameMaker - tipo de fonte de Adobe FrameMaker - גופן של Adobe FrameMaker - Adobe FrameMaker font - Adobe FrameMaker-betűkészlet - Fonta Adobe FrameMaker - Tipo carattere Adobe FrameMaker - Adobe FrameMaker フォント - Adobe FrameMaker қарібі - 어도비 프레임메이커 글꼴 - Adobe FrameMaker šriftas - Adobe FrameMaker fonts - Font Adobe FrameMaker - Adobe FrameMaker skrifttype - Adobe FrameMaker-lettertype - Adobe FrameMaker-skrifttype - Czcionka Adobe FrameMaker - tipo de letra Adobe FrameMaker - Fonte do Adobe FrameMaker - Font Adobe FrameMaker - шрифт Adobe FrameMaker - Písmo Adobe FrameMaker - Datoteka pisave Adobe FrameMaker - Gërma Adobe FrameMaker - Adobe FrameMaker фонт - Adobe FrameMaker-typsnitt - шрифт Adobe FrameMaker - Phông chữ Adobe FrameMaker - Adobe FrameMaker 字体 - Adobe FrameMaker 字型 - - - - - - - LIBGRX font - خط LIBGRX - LIBGRX yazı növü - Šryft LIBGRX - Шрифт — LIBGRX - tipus de lletra LIBGRX - Písmo LIBGRX - Ffont LIBGRX - LIBGRX-skrifttype - LIBGRX-Schrift - γραμματοσειρά LIBGRX - LIBGRX font - LIBGRX-tiparo - tipografía LIBGRX - LIBGRX letra-tipoa - LIBGRX-kirjasin - LIBGRX stavasnið - police LIBGRX - cló LIBGRX - tipo de fonte en LIBGRX - גופן LIBGRX - LIBGRX font - LIBGRX-betűkészlet - Fonta LIBGRX - Tipo carattere LIBGRX - LIBGRX フォーマット - LIBGRX қарібі - LIBGRX 글꼴 - LIBGRX šriftas - LIBGRX fonts - Font LIBGRX - LIBGRX-skrifttype - LIBGRX-lettertype - LIBGRX skrifttype - Czcionka LIBGRX - tipo de letra LIBGRX - Fonte LIBGRX - Font LIBGRX - шрифт LIBGRX - Písmo LIBGRX - Datoteka pisave LIBGRX - Lloj gërme LIBGRX - LIBGRX фонт - LIBGRX-typsnitt - LIBGRX fontu - шрифт LIBGRX - Phông chữ LIBGRX - LIBGRX 字体 - LIBGRX 字型 - - - - - - - Linux PSF console font - خط كونسول PSF لينكس - Linux PSF konsol yazı növü - Kansolny šryft PSF dla Linuksa - Шрифт — PSF, за конзолата на Линукс - tipus de lletra de consola Linux PSF - Písmo PSF pro konzolu Linuxu - Ffont Linux PSF - Linux PSF-konsolskrifttype - Linux-PSF-Konsolenschrift - γραμματοσειρά κονσόλας PSF Linux - Linux PSF console font - PSF-tiparo de Linux-konzolo - tipografía de consola Linux PSF - Linux PSF kontsolako letra-tipoa - Linux PSF -konsolikirjasin - Linux PSF stýristøðs stavasnið - police console Linux PSF - cló chonsól Linux PSF - tipo de fonte de consola Linux PSF - גופן לקונסול מסוג Linux PSF - Linux PSF konzolni font - Linux PSF konzolos betűkészlet - Fonta konsol Linux PSF - Tipo carattere console Linux PSF - Linux PSF コンソールフォント - Linux PSF консольдік қарібі - 리눅스 PSF 콘솔 글꼴 - Linux PSF konsolės šriftas - Linux PSF konsoles fonts - Font konsol PSF Linux - Linux PSF konsollskrifttype - Linux PSF-console-lettertype - Linux PSF konsoll-skrifttype - Czcionka konsoli PSF Linux - tipo de letra de consola Linux PSF - Fonte de console Linux PSF - Font consolă Linux PSF - консольный шрифт Linux PSF - Písmo PSF pre konzolu Linuxu - Datoteka pisave konzole Linux PSF - Lloj gërme për konsolë Linux PSF - Линукс PSF конзолни фонт - Linux PSF-konsolltypsnitt - Linux PSF konsol fontu - консольний шрифт Linux PSF - Phông chữ bàn giao tiếp PSF Linux - Linux PSF 控制台字体 - Linux PSF console 字型 - - - - - - - - Linux PSF console font (gzip-compressed) - خط كونسول PSF لينكس (مضغوط-gzip) - Kansolny šryft PSF dla Linuksa (gzip-skampresavany) - Шрифт — Linux PSF, компресиран с gzip - tipus de lletra de consola Linux PSF (comprimida amb gzip) - Písmo PSF pro konzolu Linuxu (komprimované pomocí gzip) - Linux PSF-konsolskrifttype (gzip-komprimeret) - Linux-PSF-Konsolenschrift (gzip-komprimiert) - γραμματοσειρά κονσόλας PSF Linux (συμπιεσμένη με gzip) - Linux PSF console font (gzip-compressed) - tipografía de consola Linux PSF (comprimida con gzip) - Linux PSF kontsolako letra-tipoa (gzip-ekin konprimitua) - Linux PSF -konsolikirjasin (gzip-pakattu) - Linux PSF stýristøðs stavasnið (gzip-stappað) - police console Linux PSF (compressée gzip) - cló chonsól Linux PSF (comhbhrúite le gzip) - tipo de fonte de consola Linux PSF (comprimida con gzip) - גופן לקונסול מסוג Linux PSF (מכווץ ע"י gzip) - Linux PSF konzolni font (komprimiran gzip-om) - Linux PSF konzolos betűkészlet (gzip-tömörítésű) - Fonta konsol Linux PSF (terkompresi gzip) - Tipo carattere console Linux PSF (compresso con gzip) - Linux PSF コンソールフォント (gzip 圧縮) - Linux PSF консольдік қарібі (gzip-пен сығылған) - 리눅스 PSF 콘솔 글꼴 (GZIP 압축) - Linux PSF konsolės šriftas (suglaudintas su gzip) - Linux PSF konsoles fonts (saspiests ar gzip) - Linux PSF konsollskrifttype (gzip-komprimert) - Linux PSF-console-lettertype (ingepakt met gzip) - Linux PSF konsoll-skrifttype (gzip-pakka) - Czcionka konsoli PSF Linux (kompresja gzip) - Fonte de console Linux PSF (compactada com gzip) - Font consolă Linux PSF (compresie gzip) - консольный шрифт Linux PSF (сжатый gzip) - Písmo PSF pre konzolu Linuxu (komprimované pomocou gzip) - Datoteka pisave konzole Linux PSF (skrčena z gzip) - Lloj gërme për konsolë Linux PSF (komresuar me gzip) - Linux PSF-konsolltypsnitt (gzip-komprimerat) - Linux PSF konsol fontu (gzip ile sıkıştırılmış) - консольний шрифт Linux PSF (стиснений gzip) - Phông chữ bàn giao tiếp PSF Linux (đã nén gzip) - Linux PSF 控制台字体(gzip 压缩) - Linux PSF console 字型 (gzip 格式壓縮) - - - - - - PCF font - خط PCF - PCF yazı növü - Šryft PCF - Шрифт — PCF - tipus de lletra PCF - Písmo PCF - Ffont PCF - PCF-skrifttype - PCF-Schrift - γραμματοσειρά PCF - PCF font - PCF-tiparo - tipografía PCF - PCF letra-tipoa - PCF-kirjasin - PCF stavasnið - police PCF - cló PCF - tipo de letra PCF - פונט PCF - PCF-betűkészlet - Fonta PCF - Tipo carattere PCF - PCF フォント - PCF қарібі - PCF 글꼴 - PCF šriftas - PCF fonts - Font PCF - PCF-skrifttype - PCF-lettertype - PCF-skrifttype - Czcionka PCF - tipo de letra PCF - Fonte PCF - Font PCF - шрифт PCF - Písmo PCF - Datoteka pisave PCF - Gërma PCF - PCF фонт - PCF-typsnitt - PCF fontu - шрифт PCF - Phông chữ PCF - PCF 字体 - PCF 字型 - - - - - - - - - - OpenType font - خط OpenType - OpenType yazı növü - Šryft OpenType - Шрифт — OpenType - tipus de lletra OpenType - Písmo OpenType - Ffont OpenType - OpenType-skrifttype - OpenType-Schrift - γραμματοσειρά OpenType - OpenType font - OpenType-tiparo - tipografía de OpenType - OpenType letra-tipoa - OpenType-kirjasin - OpenType stavasnið - police OpenType - cló OpenType - tipo de fonte OpenType - גופן של OpenType - OpenType-betűkészlet - Fonta OpenType - Tipo carattere OpenType - OpenType フォント - OpenType қарібі - 오픈타입 글꼴 - OpenType šriftas - OpenType fonts - Font OpenType - OpenType-skrifttype - OpenType-lettertype - OpenType-skrifttype - Czcionka OpenType - tipo de letra OpenType - Fonte OpenType - Font OpenType - шрифт OpenType - Písmo OpenType - Datoteka pisave OpenType - Gërma OpenType - OpenType фонт - OpenType-typsnitt - OpenType fontu - шрифт OpenType - Phông chữ OpenType - OpenType 字体 - OpenType 字型 - - - - - - - - Speedo font - خط Speedo - Speedo yazı növü - Šryft Speedo - Шрифт — Speedo - tipus de lletra Speedo - Písmo Speedo - Ffont Speedo - Speedoskrifttype - Speedo-Schrift - γραμματοσειρά Speedo - Speedo font - Speedo-tiparo - tipografía Speedo - Speedo letra-tipoa - Speedo-kirjasin - Speedo stavasnið - police Speedo - cló Speedo - tipo de letra Speedo - גופן של Speedo - Speedo font - Speedo-betűkészlet - Fonta Speedo - Tipo carattere Speedo - Speedo フォント - Speedo қарібі - Speedo 글꼴 - Speedo šriftas - Speedo fonts - Font Speedo - Speedo-skrifttype - Speedo-lettertype - Speedo-skrifttype - Czcionka Speedo - tipo de letra Speedo - Fonte Speedo - Font Speedo - шрифт Speedo - Písmo Speedo - Datoteka pisave Speedo - Gërma Speedo - Speedo фонт - Speedo-typsnitt - Speedo fontu - шрифт Speedo - Phông chữ Speedo - Speedo 字体 - Speedo 字型 - - - - - - - - SunOS News font - خط SunOS News - SunOS News yazı növü - Šryft SunOS News - Шрифт — SunOS News - tipus de lletra SunOS News - Písmo SunOS News - Ffont SunOS News - SunOS News-skrifttype - SunOS-News-Schrift - γραμματοσειρά SunOS News - SunOS News font - tiparo de SunOS News - tipografía SunOS News - SunOs News letra-tipoa - SunOS News -kirjasin - SunOS News stavasnið - police SunOS News - cló SunOS News - tipo de letra SunOS News - גופן של SunOS News - SunOS News font - SunOS News-betűkészlet - Fonta SunOS News - Tipo carattere SunOS News - SunOS News フォント - SunOS News қарібі - SunOS News 글꼴 - SunOS News šriftas - SunOS News fonts - Font News SunOS - SunOS News-skrifttype - SunOS News-lettertype - SunOS NEWS-skrifttype - Czcionka SunOS News - tipo de letra SunOS News - Fonte SunOS News - Font SunOS News - шрифт SunOS News - Písmo SunOS News - Datoteka pisave SunOS News - Gërma SunOS News - SunOS News фонт - SunOS News-typsnitt - шрифт SunOS News - Phông chữ SunOS News - SunOS News 字体 - SunOS News 字型 - - - - - - - - - TeX font - خط TeX - TeX yazı növü - Šryft TeX - Шрифт — TeX - tipus de lletra TeX - Písmo TeX - Ffont TeX - TeX-skrifttype - TeX-Schrift - γραμματοσειρά TeX - TeX font - TeX-tiparo - tipografía de TeX - TeX letra-tipoa - TeX-kirjasin - TeX stavasnið - police TeX - cló TeX - tipo de letra de TeX - גופן TeX - TeX font - TeX-betűkészlet - Fonta TeX - Tipo carattere TeX - TeX フォント - TeX қарібі - TeX 글꼴 - TeX šriftas - TeX fonts - Font TeX - TeX-skrift - TeX-lettertype - TeX-skrifttype - Czcionka TeX - tipo de letra TeX - Fonte TeX - Font TeX - шрифт TeX - Písmo TeX - Datoteka pisave TeX - Gërma TeX - ТеХ фонт - TeX-typsnitt - TeX fontu - шрифт TeX - Phông chữ TeX - TeX 字体 - TeX 字型 - - - - - - - - - TeX font metrics - مقاييس خط TeX - TeX yazı növü metrikləri - Metryka šryftu TeX - Шрифтова метрика — TeX - mètrica de tipus de lletra TeX - Metrika písma TeX - Metrigau Ffont TeX - TeX-skrifttypeinformation - TeX-Schriftmetriken - μετρικά γραμματοσειράς TeX - TeX font metrics - metrikoj de TeX-tiparo - métricas de tipografía de TeX - TeX letra-tipoen neurriak - TeX-kirjasinmitat - métriques de police TeX - meadarachtaí cló TeX - Métricas de tipo de letra de TeX - גופן מטריקס של TeX - TeX mjere fonta - TeX-betűmetrika - Fonta metrik TeX - Metriche tipo carattere TeX - TeX フォントメトリック - TeX қаріп метрикалары - Tex 글꼴 메트릭 - TeX šriftų metrika - TeX fonta metrikas - Metrik font TeX - TeX skrifttypemetrikk - TeX-lettertype-metrieken - TeX skrifttypemetrikk - Metryki czcionki TeX - métricas de tipo de letra TeX - Métrica de fonte TeX - Dimensiuni font TeX - метрика шрифта TeX - Metrika písma TeX - Matrika pisave Tex - Gërma TeX metrics - ТеХ метрика фонта - TeX-typsnittsmetrik - метрики шрифту TeX - Cách đo phông chữ TeX - TeX 字体参数 - TeX 字型描述檔 - - - - - - - - TrueType font - خط TrueType - Šryft TrueType - Шрифт — TrueType - tipus de lletra TrueType - Písmo TrueType - TrueType-skrifttype - TrueType-Schrift - γραμματοσειρά TrueType - TrueType font - TrueType-tiparo - tipografía TrueType - TrueType letra-tipoa - TrueType-kirjasin - TrueType stavasnið - police Truetype - cló TrueType - tipo de letra TrueType - גופן מסוג TrueType - TrueType font - TrueType-betűkészlet - Fonta TrueType - Tipo carattere TrueType - TrueType フォント - TrueType қарібі - 트루타입 글꼴 - TrueType šriftas - TrueType fonts - Font TrueType - TrueType-skrift - TrueType-lettertype - TrueType-skrifttype - Czcionka TrueType - tipo de letra TrueType - Fonte TrueType - Font TrueType - шрифт TrueType - Písmo TrueType - Datoteka pisave TrueType - Lloj gërme TrueType - Трутајп фонт - Truetype-typsnitt - TrueType fontu - шрифт TrueType - Phông chữ TrueType - TrueType 字体 - TrueType 字型 - - - - - - - - - - - TrueType XML font - خط TrueType XML - Šryft TrueType XML - Шрифт — TrueType XML - tipus de lletra TrueType XML - Písmo TrueType XML - TrueType XML-skrifttype - TrueType-XML-Schrift - γραμματοσειρά XML TrueType - TrueType XML font - tipografía TrueType XML - TrueType XML letra-tipoa - TrueType-XML-kirjasin - TrueType XML stavasnið - police Truetype XML - cló XML TrueType - tipo de letra TrueType XML - גופן XML מסוג TrueType - TrueType XML font - TrueType XML betűkészlet - Fonta TrueType XML - Tipo carattere TrueType XML - TrueType XML フォント - TrueType XML қарібі - 트루타입 XML 글꼴 - TrueType XML šriftas - TrueType XML fonts - TrueType XML-skrift - TrueType XML-lettertype - TrueType XML-skrifttype - Czcionka TrueType XML - Fonte TrueType XML - Font XML TrueType - шрифт TrueType XML - Písmo TrueType XML - Datoteka pisave TrueType XML - Lloj gërme TrueType XML - Truetype XML-typsnitt - TrueType XML fontu - шрифт TrueType XML - Phông chữ XML TrueType - TrueType XML 字体 - TrueType XML 字型 - - - - - - - - - V font - خط V - V yazı növü - Šryft V - Шрифт — V - tipus de lletra V - Písmo V - Ffont V - V-skrifttype - V-Schrift - γραμματοσειρά V - V font - V-tiparo - tipografía V - V letra-tipoa - V-kirjasin - V stavasnið - police V - cló V - tipo de letra V - גופן של V - V font - V-betűkészlet - Fonta V - Tipo carattere V - V フォント - V font қарібі - V 글꼴 - V šriftas - V fonts - Font V - V-skrift - V-lettertype - V-skrifttype - Czcionka V - tipo de letra V - Fonte V - Font V - шрифт V font - Písmo V - Datoteka pisave V - Gërmë V - V фонт - V-typsnitt - V fontu - V-шрифт - Phông chữ V - V 字体 - V 字型 - - - - - - - Adobe FrameMaker document - مستند أدوبي الصانع للإطارات - Dakument Adobe FrameMaker - Документ — Adobe FrameMaker - document FrameMaker d'Adobe - Dokument Adobe FrameMaker - Adobe FrameMaker-dokument - Adobe-FrameMaker-Dokument - αρχείο Adobe FrameMaker - Adobe FrameMaker document - Dokumento de Adobe FrameMaker - documento de Adobe FrameMaker - Adobe FrameMaker-en dokumentua - Adobe FrameMaker -asiakirja - Adobe FrameMaker skjal - document Adobe FrameMaker - cáipéis Adobe FrameMaker - documento de Adobe FrameMaker - מסמך Adobe FrameMaker - Adobe FrameMaker dokument - Adobe FrameMaker-dokumentum - Dokumen Adobe FrameMaker - Documento Adobe FrameMaker - Adobe FrameMaker ドキュメント - Adobe FrameMaker-ის დოკუმენტი - Adobe FrameMaker құжаты - 어도비 프레임메이커 문서 - Adobe FrameMaker dokumentas - Adobe FrameMaker dokuments - Adobe FrameMaker-dokument - Adobe FrameMaker-document - Adobe FrameMaker-dokument - Dokument Adobe FrameMaker - Documento do Adobe FrameMaker - Document Adobe FrameMaker - документ Adobe FrameMaker - Dokument Adobe FrameMaker - Dokument Adobe FrameMaker - Dokument Adobe FrameMaker - Adobe FrameMaker-dokument - документ Adobe FrameMaker - Tài liệu Adobe FrameMaker - Adobe FrameMaker 文档 - Adobe FrameMaker 文件 - - - - - - - - - - - - - Game Boy ROM - Game Boy ROM - Game Boy ROM - ROM — Game Boy - ROM de Game Boy - ROM pro Game Boy - Game Boy-rom - Game-Boy-ROM - εικόνα μνήμης ROM GameBoy - Game Boy ROM - NLM de Game Boy - ROM de Game Boy - Game Boy-eko ROMa - Game Boy -ROM - Game Boy ROM - ROM Game Boy - ROM Game Boy - ROM de Game Boy - ROM של Game Boy - Game Boy ROM - Game Boy ROM - Memori baca-saja Game Boy - ROM Game Boy - ゲームボーイ ROM - Game Boy-ის ROM - Game Boy ROM - 게임보이 롬 - Game Boy ROM - Game Boy ROM - ROM Game Boy - Game Boy-ROM - Game Boy-ROM - Game Boy-ROM - Plik ROM konsoli Game Boy - ROM Game Boy - ROM do Game Boy - ROM Game Boy - Game Boy ROM - ROM pre Game Boy - Bralni pomnilnik Game Boy - ROM Game Boy - Гејмбој РОМ - Game Boy-rom - ППП Game Boy - ROM Game Boy - Game Boy ROM - Game Boy ROM - - - - - Game Boy Advance ROM - Game Boy Advance ROM - Game Boy Advance ROM - ROM — Game Boy Advance - ROM de Game Boy Advance - ROM pro Game Boy Advance - Game Boy Advance-rom - Game-Boy-Advance-ROM - εικόνα μνήμης Game Boy Advance - Game Boy Advance ROM - ROM de Game Boy Advance - Game Boy Advance-ko ROMa - Game Boy Advance -ROM - Game Boy Advance ROM - ROM Game Boy Advance - ROM Game Boy Advance - ROM de Game Boy Advance - ROM של Game Boy Advance - Game Boy Advance ROM - Game Boy Advance ROM - Memori baca-saja Game Boy Advance - ROM Game Boy Advance - ゲームボーイアドバンス ROM - Game Boy Advance-ის ROM - Game Boy Advance ROM - 게임보이 어드밴스 롬 - Game Boy Advance ROM - Game Boy Advance ROM - Game Boy Advance-ROM - Game Boy Advance-ROM - Game Boy Advance-ROM - Plik ROM konsoli Game Boy Advance - ROM do Game Boy Advance - ROM Game Boy Advance - Game Boy Advance ROM - ROM pre Game Boy Advance - Bralni pomnilnik Game Boy Advance - ROM Game Boy Advance - Game Boy Advance-rom - розширений ППП Game Boy - ROM Game Boy Advance - Game Boy Advance ROM - Game Boy Advance ROM - - - - - GDBM database - قاعدة بيانات GDBM - Baza źviestak GDBM - База от данни — GDBM - base de dades GDBM - Databáze GDBM - GDBM-database - GDBM-Datenbank - βάση δεδομένων GDBM - GDBM database - GDBM-datumbazo - base de datos GDBM - GDBM datu-basea - GDBM-tietokanta - GDBM dátustovnur - base de données GDBM - bunachar sonraí GDBM - base de datos GDBM - בסיס נתונים GDBM - GDBM baza podataka - GDBM adatbázis - Basis data GDBM - Database GDBM - GDBM データベース - GDBM მონაცემთა ბაზა - GDBM дерекқоры - GDBM 데이터베이스 - GDBM duomenų bazė - GDBM datubāze - GDBM-database - GDBM-gegevensbank - GDBM-database - Baza danych GDBM - Banco de dados GDBM - Bază de date GDBM - база данных GDBM - Databáza GDBM - Podatkovna zbirka GDBM - Bazë me të dhëna GDBM - GDBM-databas - GDBM veritabanı - база даних GDBM - Cơ sở dữ liệu GDBM - GDBM 数据库 - GDBM 資料庫 - GDBM - GNU Database Manager - - - - - - - - - Genesis ROM - Genesis ROM - Genesis ROM - ROM — Genesis - ROM de Genesis - ROM pro Genesis - Genesis-rom - Genesis-ROM - εικόνα μνήμης ROM Genesis - Genesis ROM - Genesis-NLM - ROM de Genesis (Mega Drive) - Genesis-eko ROMa - Genesis-ROM - Genesis ROM - ROM Mega Drive/Genesis - ROM Genesis - ROM xenérica - ROM של Genesis - Genesis ROM - Genesis ROM - Memori baca-saja Genesis - ROM Megadrive - メガドライブ ROM - Genesis ROM - 제네시스 롬 - Genesis ROM - Genesis ROM - ROM Genesis - Genesis-ROM - Mega Drive - Genesis-ROM - Plik ROM konsoli Mega Drive - ROM Genesis - ROM do Gênesis (Mega Drive) - ROM Genesis - Genesis ROM - ROM pre Megadrive - Bralni pomnilnik Genesis - ROM Genesis - Genesis РОМ - Genesis-rom - ППП Genesis - ROM Genesis - Genesis ROM - Genesis ROM - - - - - - - - - - translated messages (machine-readable) - رسائل مترجمة (مقروءة آليا) - pierakładzienyja paviedamleńni (dla čytańnia kamputaram) - Преведени съобщения — машинен формат - missatges traduïts (llegible per màquina) - Přeložené zprávy (strojově čitelné) - oversatte meddelelser (maskinlæsbare) - Übersetzte Meldungen (maschinenlesbar) - μεταφρασμένα μηνύματα (για μηχανική ανάγνωση) - translated messages (machine-readable) - tradukitaj mesaĝoj (maŝinlegebla) - mensajes traducidos (legibles por máquinas) - itzulitako mezuak (ordenagailuek irakurtzeko) - käännetyt viestit (koneluettava) - týdd boð (maskin-lesifør) - messages traduits (lisibles par machine) - teachtaireachtaí aistrithe (inléite ag meaisín) - mensaxes traducidos (lexíbeis por máquinas) - מסר מתורגם (מובן ע"י מכונה) - prevedene poruke (strojno čitljive) - lefordított üzenetek (gépi kód) - pesan diterjemahkan (dapat dibaca mesin) - Messaggi tradotti (leggibili da macchina) - 翻訳メッセージ (マシン用) - ნათარგმნი შეტყობინებები (მანქანისთვის განკუთვნილი) - аударылған хабарламалар (машиналық түрде) - 번역 메시지 (컴퓨터 사용 형식) - išversti užrašai (kompiuteriniu formatu) - pārtulkotie ziņojumi (mašīnlasāms) - Mesej diterjemah (bolehdibaca-mesin) - oversatte meldinger (maskinlesbar) - vertaalde berichten (machine-leesbaar) - oversette meldingar (maskinlesbare) - Przetłumaczone komunikaty (czytelne dla komputera) - mensagens traduzidas (leitura pelo computador) - Mensagens traduzidas (legível pelo computador) - mesaje traduse (citite de calculator) - переводы сообщений (откомпилированые) - Preložené správy (strojovo čitateľné) - prevedena sporočila (strojni zapis) - Mesazhe të përkthyer (të lexueshëm nga makina) - преведене поруке (машинама читљиво) - översatta meddelanden (maskinläsbara) - перекладені повідомлення (у машинній формі) - thông điệp đã dịch (máy đọc được) - 消息翻译(机读) - 翻譯訊息 (程式讀取格式) - - - - - - - - - GTK+ Builder - - - - - - - - - Glade project - مشروع Glade - Glade layihəsi - Prajekt Glade - Проект — Glade - projecte de Glade - Projekt Glade - Prosiect Glade - Gladeprojekt - Glade-Projekt - έργο Glade - Glade project - Glade-projekto - proyecto de Glade - Glade proiektua - Glade-projekti - Glade verkætlan - projet Glade - tionscadal Glade - proxecto de Glade - מיזם Glade - Glade projekt - Glade-projekt - Proyek Glade - Progetto Glade - Glade プロジェクト - Glade жобасы - Glade 프로젝트 - Glade projektas - Glade projekts - Projek Glade - Glade prosjekt - Glade-project - Glade prosjekt - Projekt Glade - projecto Glade - Projeto do Glade - Proiect Glade - проект Glade - Projekt Glade - Datoteka projekta Glade - Projekt Glade - Глејд пројекат - Glade-projekt - проект Glade - Dự án Glade - Glade 工程 - Glade 專案 - - - - - - - - - GMC link - وصلة GMC - GMC körpüsü - Spasyłka GMC - Връзка — GMC - enllaç GMC - Odkaz GMC - Cyswllt GMC - GMC-henvisning - GMC-Verweis - σύνδεσμος GMC - GMC link - GMC-ligilo - enlace GMC - GMC esteka - GMC-linkki - GMC leinkja - lien GMC - nasc GMC - ligazón GMC - קישור GMC - GMC veza - GMC-link - Taut GMC - Collegamento GMC - GMC リンク - GMC ბმული - GMC сілтемесі - GMC 연결 - GMC nuoroda - GMC saite - Pautan GMC - GMC-lenke - GMC-verwijzing - GMC-lenkje - Odnośnik GMC - 'link' GMC - Link GMC - Legătură GMC - ссылка GMC - Odkaz GMC - Datoteka povezave GMC - Lidhje GMC - GMC веза - GMC-länk - GMC bağlantısı - посилання GMC - Liên kết GMC - GMC 链接 - GMC 鏈結 - - - - - - - GnuCash financial data - معلومات GnuCash المالية - Финансови данни — GnuCash - dades financeres del GnuCash - Finanční data GnuCash - Finansielle data til GnuCash - GnuCash-Finanzdaten - οικονομικά στοιχεία GnuCash - GnuCash financial data - datos financieros GnuCash - GnuCash finantzako datuak - GnuCash-taloustiedot - GnuCash fíggjarligar dátur - données financières GnuCash - sonraí airgeadúla GnuCash - datos financeiros de GNUCash - מידע כלכלי של GnuCash - GnuCash financijski podaci - GnuCash pénzügyi adatok - Data keuangan GnuCash - Dati finanziari GnuCash - GnuCash 会計データ - GnuCash қаржы ақпараты - GnuCash 재정 자료 - GnuCash finansiniai duomenys - GnuCash finanšu dati - GnuCash financiële gegevens - Dane finansowe GnuCash - Dados financeiros do GnuCash - Date financiare GnuCash - финансовые данные GnuCash - Finančné údaje GnuCash - Datoteka finančnih podatkov GnuCash - GnuCash-finansdata - фінансові дані GnuCash - Dữ liệu tài chính GnuCash - GnuCash 财务数据 - GnuCash 財務資料 - - - - - - - Gnumeric spreadsheet - جدول Gnumeric - Raźlikovy arkuš Gnumeric - Таблица — Gnumeric - full de càlcul de Gnumeric - Sešit Gnumeric - Gnumeric-regneark - Gnumeric-Tabelle - Λογιστικό φύλλο Gnumeric - Gnumeric spreadsheet - Gnumeric-kalkultabelo - hoja de cálculo de Gnumeric - Gnumeric kalkulu-orria - Gnumeric-taulukko - Gnumeric rokniark - feuille de calcul Gnumeric - scarbhileog Gnumeric - folla de cálculo de Gnumeric - גליון עבודה Gnumeric - Gnumeric proračunska tablica - Gnumeric-munkafüzet - Lembar sebar Gnumeric - Foglio di calcolo Gnumeric - Gnumeric スプレッドシート - Gnumeric электрондық кестесі - Gnumeric 스프레드시트 - Gnumeric skaičialentė - Gnumeric izklājlapa - Hamparan Gnumeric - Gnumeric-regneark - Gnumeric-rekenblad - Gnumeric-rekneark - Arkusz Gnumeric - folha de cálculo Gnumeric - Planilha do Gnumeric - Foaie de calcul Gnumeric - электронная таблица Gnumeric - Zošit Gnumeric - Razpredelnica Gnumeric - Fletë llogaritjesh Gnumeric - Гнумерик табеларни рачун - Gnumeric-kalkylblad - ел. таблиця Gnumeric - Bảng tính Gnumeric. - Gnumeric 工作簿 - Gnumeric 試算表 - - - - - - - - - Gnuplot document - مستند Gnuplot - Dakument Gnuplot - Документ — Gnuplot - document gnuplot - Dokument Gnuplot - Gnuplotdokument - Gnuplot-Dokument - έγγραφο Gnuplot - Gnuplot document - Gnuplot-dokumento - documento de Gnuplot - Gnuplot dokumentua - Gnuplot-asiakirja - Gnuplot skjal - document Gnuplot - cáipéis Gnuplot - documento de Gnuplot - מסמך Gnuplot - Gnuplot dokument - Gnuplot dokumentum - Dokumen Gnuplot - Documento Gnuplot - Gnuplot ドキュメント - Gnuplot құжаты - Gnuplot 문서 - Gnuplot dokumentas - Gnuplot dokuments - Gnuplot-dokument - Gnuplot-document - Gnuplot-dokument - Dokument Gnuplot - Documento do Gnuplot - Document Gnuplot - документ Gnuplot - Dokument Gnuplot - Dokument Gnuplot - Dokument Gnuplot - Gnuplot-dokument - документ Gnuplot - Tài liệu Gnuplot - Gnuplot 文档 - Gnuplot 文件 - - - - - - - - Graphite scientific graph - مبيان الجرافيت العلمي - Navukovy hrafik Graphite - Графика — Graphite - gràfic científic Graphite - Vědecký graf Graphite - Graphite videnskabelig graf - Wissenschaftlicher Graphite-Graph - επιστημονικό γράφημα Graphite - Graphite scientific graph - scienca grafikaĵo de Graphite - gráfica científica de Graphite - Graphite - grafiko zientifikoak - Graphite- tieteellinen graafi - Grapite vísindarlig ritmynd - graphe Graphite scientific - graf eolaíoch Graphite - gráfica científica de Graphite - גרך מדעי של Graphite - Graphite znanstveni grafikon - Graphite tudományos grafikon - Grafik sains Graphite - Grafico scientifico Graphite - Graphite scientific グラフ - Graphite ғылыми кескіні - Graphite 과학 그래프 - Graphite mokslinė diagrama - Graphite zinātniskais grafiks - Graf saintifik Graphite - Vitenskapelig graf fra Graphite - Graphite wetenschappelijke grafiek - Graphite vitskaplege graf - Wykres naukowy Graphite - gráfico científico Graphite - Gráfico científico do Graphite - Grafic științific Graphite - научная диаграмма Graphite - Vedecký graf Graphite - Datoteka znanstvenega grafa Graphite - Grafik shkencor Graphite - Graphite научни графикони - Vetenskaplig Graphite-grafer - наукова графіка Graphite - Biểu đồ khoa học Graphite - Graphite 科学图形 - Graphite 科學圖表 - - - - - GTKtalog catalog - كتالوج GTKtalog - Kataloh GTKtalog - Каталог — Gtktalog - catàleg de GTKtalog - Katalog GTKtalog - GTKtalog-katalog - GTKtalog-Katalog - Κατάλογος GTKtalog - GTKtalog catalogue - katalogo de GTKtalog - catálogo de GTKtalog - Gtktalog katalogoa - GTKtalog-luettelo - GTKtalog skrá - catalogue Gtktalog - catalóg GTKtalog - catálogo de GTKtalog - קטלוג GTKtalog - GTKtalog katalog - GTKtalog-katalógus - Katalog GTKtalog - Catalogo GTKtalog - GTKtalog カタログ - GTKtalog-ის კატალოგი - GTKtalog каталогы - GTKtalog 카탈로그 - GTKtalog katalogas - GTKtalog katalogs - Katalog GTKtalog - GTKtalog-katalog - GTKtalog-catalogus - GTKtalog-katalog - Katalog programu GTKtalog - catálogo GTKtalog - Catálogo GTKtalog - Catalog GTKalog - каталог GTKtalog - Katalóg GTKtalog - Datoteka kataloga GTKtalog - Katallog GTKtalog - Гткталог каталог - GTKtalog-katalog - каталог GTKtalog - Phân loại GTKtalog - GTKtalog 目录 - GTKtalog 光碟目錄 - - - - - - - TeX DVI document (gzip-compressed) - مستند TeX DVI (مضغوط-gzip) - Dakument TeX DVI (gzip-skampresavany) - Документ — TeX DVI, компресиран с gzip - document TeX DVI (comprimit amb gzip) - Dokument TeX DVI (komprimovaný pomocí gzip) - TeX DVI-dokument (gzip-komprimeret) - TeX-DVI-Dokument (gzip-komprimiert) - αρχείο TeX DVI (συμπιεσμένο με gzip) - TeX DVI document (gzip-compressed) - documento DVI de TeX (comprimido con gzip) - TeX DVI dokumentua (gzip-ekin konprimitua) - TeX DVI -asiakirja (gzip-pakattu) - TeX DVI skjal (gzip-stappað) - document DVI TeX (compressé gzip) - cáipéis DVI TeX (comhbhrúite le gzip) - documento DVI de TeX (comprimido con gzip) - מסמך מסוג TeX DVI (מכווץ ע"י gzip) - TeX DVI dokument (komprimiran gzip-om) - TeX DVI dokumentum (gzip-pel tömörítve) - Dokumen TeX DVI (terkompresi gzip) - Documento Tex DVI (compresso con gzip) - Tex DVI ドキュメント (gzip 圧縮) - TeX DVI құжаты (gzip-пен сығылған) - TeX DVI 문서 (GZIP 압축) - TeX DVI dokumentas (suglaudintas su gzip) - TeX DVI dokuments (saspiests ar gzip) - TeX DVI-dokument (gzip-komprimert) - TeX DVI-document (ingepakt met gzip) - TeX DVI-dokument (pakka med gzip) - Dokument TeX DVI (kompresja gzip) - Documento DVI TeX (compactado com gzip) - Document TeX DVI (comprimat gzip) - документ TeX DVI (сжатый gzip) - Dokument TeX DVI (komprimovaný pomocou gzip) - Dokument TeX DVI (stisnjen z gzip) - Dokument TeX DVI (i kompresuar me gzip) - TeX DVI-dokument (gzip-komprimerat) - TeX DVI belgesi (gzip ile sıkıştırılmış) - документ TeX DVI (стиснений gzip) - Tài liệu DVI TeX (đã nén gzip) - TeX DVI 文档(gzip 压缩) - TeX DVI 文件 (gzip 格式壓縮) - - - - - - Gzip archive - أرشيف Gzip - Archiŭ gzip - Архив — gzip - arxiu gzip - Archiv gzip - Gzip-arkiv - Gzip-Archiv - συμπιεσμένο αρχείο Gzip - Gzip archive - Gzip-arkivo - archivador Gzip - Gzip artxiboa - Gzip-arkisto - Gzip skjalasavn - archive gzip - cartlann Gzip - arquivo Gzip - ארכיון Gzip - Gzip arhiva - Gzip archívum - Arsip Gzip - Archivio gzip - Gzip アーカイブ - Gzip архиві - GZIP 압축 파일 - Gzip archyvas - Gzip arhīvs - Gzip-arkiv - Gzip-archief - Gzip-arkiv - Archiwum gzip - Pacote Gzip - Arhivă Gzip - архив GZIP - Archív gzip - Datoteka arhiva Gzip - Arkiv gzip - Gzip-arkiv - архів gzip - Kho nén gzip - Gzip 归档文件 - Gzip 封存檔 - - - - - - - - - PDF document (gzip-compressed) - مستند PDF (مضغوط-gzip) - Dakument PDF (gzip-skampresavany) - Документ — PDF, компресиран с gzip - document PDF (comprimit amb gzip) - Dokument PDF (komprimovaný pomocí gzip) - PDF-dokument (gzip-komprimeret) - PDF-Dokument (gzip-komprimiert) - έγγραφο PDF (συμπιεσμένο με gzip) - PDF document (gzip-compressed) - documento PDF (comprimido con gzip) - PDF dokumentua (gzip-ekin konprimitua) - PDF-asiakirja (gzip-pakattu) - PDF skjal (gzip-stappað) - document PDF (compressé gzip) - cáipéis PDF (comhbhrúite le gzip) - documento PDF (comprimido en gzip) - מסמך PDF (מכווץ ע"י gzip) - PDF dokumentum (gzip-tömörítésű) - Dokumen PDF (terkompresi gzip) - Documento PDF (compresso con gzip) - PDF ドキュメント (gzip 圧縮) - PDF құжаты (gzip-пен сығылған) - PDF 문서 (GZIP 압축) - PDF dokumentas (suglaudintas su gzip) - PDF dokuments (saspiests ar gzip) - PDF-dokument (gzip-komprimert) - PDF-document (ingepakt met gzip) - PDF-dokument (pakka med gzip) - Dokument PDF (kompresja gzip) - Documento PDF (compactado com gzip) - Document PDF (comprimat gzip) - документ PDF (сжатый gzip) - Dokument PDF (komprimovaný pomocou gzip) - Dokument PDF (stisnjen z gzip) - Dokument PDF (i kompresuar me gzip) - PDF-dokument (gzip-komprimerat) - PDF belgesi (gzip ile sıkıştırılmış) - документ PDF (стиснений gzip) - Tài liệu PDF (đã nén gzip) - PDF 文档(gzip 压缩) - PDF 文件 (gzip 格式壓縮) - - - - - - PostScript document (gzip-compressed) - مستند PostScript (مضغوط-gzip) - Dakument PostScript (gzip-skampresavany) - Документ — PostScript, компресиран с gzip - document PostScript (comprimit amb gzip) - Dokument PostScript (komprimovaný pomocí gzip) - PostScript-dokument (gzip-komprimeret) - PostScript-Dokument (gzip-komprimiert) - έγγραφο PostScript (συμπιεσμένο με gzip) - PostScript document (gzip-compressed) - PostScript-dokumento (kunpremita per gzip) - documento PostScript (comprimido con gzip) - PostScript dokumentua (gzip-konprimitua) - PostScript-asiakirja (gzip-pakattu) - PostScript skjal (gzip-stappað) - document PostScript (compressé gzip) - cáipéis PostScript (comhbhrúite le gzip) - documento PostScript (comprimido con gzip) - מסמך PostScript (מכוות ע"י gzip) - PostScript-dokumentum (gzip-pel tömörítve) - Dokumen PostScript (terkompresi gzip) - Documento PostScript (compresso con gzip) - PostScript ドキュメント (gzip 圧縮) - PostScript құжаты (gzip-пен сығылған) - 포스트스크립트 문서 (GZIP 압축) - PostScript dokumentas (suglaudintas su gzip) - PostScript dokuments (saspiests ar gzip) - Dokumen PostScript (dimampatkan-gzip) - PostScript-dokument (gzip-komprimert) - PostScript-document (ingepakt met gzip) - PostScript-dokument (pakka med gzip) - Dokument Postscript (kompresja gzip) - documento PostScript (comprimido com gzip) - Documento PostScript (compactado com gzip) - Document PostScript (comprimat gzip) - документ PostScript (сжатый gzip) - Dokument PostScript (komprimovaný pomocou gzip) - Dokument PostScript (stisnjen z gzip) - Dokument PostScript (i kompresuar me gzip) - Постскрипт документ (компресована gzip-ом) - Postscript-dokument (gzip-komprimerat) - документ PostScript (стиснене gzip) - Tài liệu PostScript (đã nén gzip) - PostScript 文档(gzip 压缩) - PostScript 文件 (gzip 格式壓縮) - - - - - - HDF document - مستند HDF - HDF sənədi - Dakument HDF - Документ — HDF - document HDF - Dokument HDF - Dogfen HDF - HDF-dokument - HDF-Dokument - έγγραφο HDF - HDF document - HDF-dokumento - documento HDF - HDF dokumentua - HDF-asiakirja - HDF skjal - document HDF - cáipéis HDF - documento HDF - מסמך HDF - HDF dokument - HDF-dokumentum - Dokumen HDF - Documento HDF - HDF ドキュメント - HDF құжаты - HDF 문서 - HDF dokumentas - HDF dokuments - Dokumen HDF - HDF-dokument - HDF-document - HDF-dokument - Dokument HDF - documento HDF - Documento HDF - Document HDF - документ HDF - Dokument HDF - Dokument HDF - Dokument HDF - HDF документ - HDF-dokument - документ HDF - Tài liệu HDF - HDF 文档 - HDF 文件 - HDF - Hierarchical Data Format - - - - - - - - - - - - - IFF file - IFF - Interchange File Format - - - - - - iPod firmware - برنامج عتاد الـiPod - Firmware iPod - Фърмуер за iPod - microprogramari d'iPod - Firmware iPod - iPod-styreprogram - iPod-Firmware - εικόνα μνήμης firmware iPod - iPod firmware - iPod-mikroprogramaro - firmware de iPod - iPod firmwarea - iPod-laiteohjelmisto - iPod fastbúnaður - firmware iPod - dochtearraí iPod - firmware de iPod - קושחת ipod - iPod-firmware - peranti tegar iPod - Firmware iPod - iPod ファームウェア - iPod микробағдарламасы - iPod 펌웨어 - iPod programinė įranga - iPod aparātprogrammatūra - Firmware iPod - iPod-firmware - iPod-firmware - iPod-firmvare - Oprogramowanie wewnętrzne iPod - 'firmware' iPod - Firmware do iPod - Firmware iPod - микропрограмма iPod - Firmware iPod - Programska strojna oprema iPod - Firmware iPod - iPod програм - fast iPod-program - мікропрограма iPod - phần vững iPod - iPod 固件 - iPod 韌體 - - - - - - Java archive - أرشيف Java - Archiŭ Java - Архив — Java - arxiu Java - Archiv Java - Javaarkiv - Java-Archiv - αρχείο Java - Java archive - Java-arkivo - archivador Java - Java artxiboa - Java-arkisto - Java skjalasavn - archive Java - cartlann Java - arquivo Java - ארכיון Java - Java arhiva - Java-archívum - Arsip Java - Archivio Java - Java アーカイブ - Java архиві - 자바 묶음 파일 - Java archyvas - Java arhīvs - Arkib Java - Java-arkiv - Java-archief - Java-arkiv - Archiwum Java - arquivo Java - Pacote Java - Arhivă Java - архив Java - Archív Java - Datoteka arhiva Java - Arkiv Java - Јава архива - Java-arkiv - Java arşivi - архів Java - Kho nén Java - Java 归档文件 - Java 封存檔 - - - - - - - - Java class - صنف java - Klasa Java - Клас на Java - classe Java - Třída Java - Javaklasse - Java-Klasse - κλάση Java - Java class - Java-klaso - clase Java - Java-ko klasea - Java-luokka - Java flokkur - classe Java - aicme Java - clase de Java - מחלקת Java - Java klasa - Java-osztály - Kelas Java - Classe Java - Java クラス - Java класы - 자바 클래스 - Java klasė - Java klase - Kelas Java - Java-klasse - Java-klasse - Java-klasse - Klasa Java - classe Java - Classe Java - Clasă Java - класс Java - Trieda Java - Datoteka razreda Java - Klasë Java - Јава класа - Java-klass - Java sınıfı - клас Java - Hạng Java - Java 类 - Java class - - - - - - - - - - - - JNLP file - ملف JNLP - Fajł JNLP - Файл — JNLP - fitxer JNLP - Soubor JNLP - JNPL-fil - JNLP-Datei - αρχείο JNLP - JNLP file - JNLP-dosiero - archivo JNPL - JNLP fitxategia - JNLP-tiedosto - JNLP fíla - fichier JNLP - comhad JNLP - ficheiro JNLP - קובץ JNLP - JNLP datoteka - JNLP fájl - Berkas JNLP - File JNPL - JNLP ファイル - JNLP файлы - JNLP 파일 - JNLP failas - JNLP datne - JNLP-fil - JNLP-bestand - JNLP-fil - Plik JNLP - Arquivo JNLP - Fișier JNLP - файл JNLP - Súbor JNLP - Datoteka JNLP - File JNLP - JNLP-fil - JNLP dosyası - файл JNLP - Tập tin JNLP - JNLP 文件 - JNLP 檔案 - JNLP - Java Network Launching Protocol - - - - - - - - - Java keystore - مخزن مفاتيح جافا - Ключодържател — Java - magatzem de claus Java - Java keystore - Javanøglelager - Java-Schlüsselbund - χώρος αποθήκευσης κλειδιών Java - Java keystore - almacén de claves de Java - Java-ren gako-biltegia - Java-avainvarasto - Java lyklagoymsla - stockage de clés Java - eochairstór Java - almacén de chaves de Java - הקשת מקלדת של Java - Java kulcstároló - Penyimpanan kunci Java - Keystore Java - Java キーストア - Java сақталымы - 자바 키 저장소 - Java raktų saugykla - Java keystore - Java keystore - Baza kluczy Java - Keystore de Java - Stocare chei Java - хранилище ключей Java - Úložisko kľúčov Java - Datoteka tipkovne razporeditve Java - Java-nyckellager - сховище ключів Java - Java 密钥库 - Java 金鑰儲存 - - - - - - - - - Java JCE keystore - مخزن مفاتيح Java JCE - Ключодържател — Java JCE - magatzem de claus JCE Java - Java JCE keystore - Java JCE-nøglelager - Java JCE-Schlüsselbund - Java JCE keystore - almacén de claves JCE de Java - Java JCE-ren gako-biltegia - Java JCE -avainvarasto - Java JCE lyklagoymsla - stockage de clés Java JCE - eochairstór Java JCE - almacén de chves JCE de Java - הקשה מסוג Java JCE - Java JCE kulcstároló - Penyimpanan kunci Java JCE - Keystore Java JCE - Java JCE キーストア - Java JCE сақталымы - 자바 JCE 키 저장소 - Java JCE raktų saugykla - Java JCE keystore - Java JCE keystore - Baza kluczy Java JCE - Keystore JCE do Java - Stocare chei Java JCE - хранилище ключей Java JCE - Úložisko kľúčov Java JCE - Datoteka tipkovne razporeditve Java JCE - Java JCE-nyckellager - сховище ключів JCE Java - Java JCE 密钥库 - Java JCE 金鑰儲存 - JCE - Java Cryptography Extension - - - - - - - Pack200 Java archive - أرشيف Pack200 Java - Archiŭ Pack200 Java - Архив — Java Pack200 - arxiu Java Pack200 - Archiv Java Pack200 - Pack200 Java-arkiv - Pack200-Java-Archiv - αρχείο Java Pack200 - Pack200 Java archive - archivador Pack200 Java - Pack2000 Java artxiboa - Pack200-Java-arkisto - Pack200 Java skjalasavn - archive Java Pack200 - cartlann Java Pack200 - arquivo Pack200 Java - ארכיון מסוג Pack200 Java - Pack200 Java-archívum - Arsip Pack200 Java - Archivio Pack200 Java - Pack200 Java アーカイブ - Pack200 Java архиві - Pack200 자바 압축 파일 - Pack200 Java archyvas - Pack200 Java arhīvs - Pack200 Java-arkiv - Pack200 Java-archief - Pack200 Java-arkiv - Archiwum Java Pack200 - Pacote Java Pack200 - Arhivă Java Pack2000 - архив Java Pack200 - Archív Java Pack200 - Datoteka arhiva Pack200 Java - Arkiv Java Pack200 - Pack200 Java-arkiv - Pack200 Java arşivi - архів Java Pack200 - Kho nén Java Pack200 - Pack200 Java 归档文件 - Pack200 Java 封存檔 - - - - - - - - JavaScript program - برنامج جافاسكربت - Prahrama JavaScript - Програма на JavaScript - programa JavaScript - Program v JavaScriptu - JavaScript-program - JavaScript-Programm - πρόγραμμα JavaScript - JavaScript program - JavaScript-programo - programa en JavaScript - JavaScript programa - JavaScript-ohjelma - JavaScript forrit - programme JavaScript - ríomhchlár JavaScript - programa JavaScript - תכנית JavaScript - JavaScript program - JavaScript-program - Program JavaScript - Programma JavaScript - JavaScript プログラム - JavaScript бағдарламасы - 자바스크립트 프로그램 - JavaScript programa - JavaScript programma - Program JavaScript - JavaScript-program - JavaScript-programma - JavaScript-program - Pogram JavaScript - Programa JavaScript - Program JavaScript - сценарий JavaScript - Program jazyka JavaScript - Programska datoteka JavaScript - Program JavaScript - JavaScript-program - JavaScript programı - програма мовою JavaScript - Chương trình JavaScript - Javascript 程序 - JavaScript 程式 - - - - - - - - JBuilder project - مشروع JBuilder - Prajekt JBuilder - Проект — JBuilder - projecte de JBuilder - Projekt JBuilder - JBuilder-projekt - JBuilder-Projekt - έργο JBuilder - JBuilder project - JBuilder-projekto - proyecto JBuilder - JBuilder proiektua - JBuilder-projekti - JBuilder verkætlan - projet JBuilder - tionscadal JBuilder - proxecto de JBuilder - מיזם JBuilder - JBuilder projekt - JBuilder-projekt - Proyek JBuilder - Progetto JBuilder - JBuilder プロジェクト - JBuilder жобасы - JBuilder 프로젝트 - JBuilder projektas - JBuilder projekts - Projek JBuilder - JBuilder-prosjekt - JBuilder-project - JBuilder-prosjekt - Projekt JBuilder - projecto JBuilder - Projeto do JBuilder - Proiect JBuilder - проект JBuilder - Projekt JBuilder - Datoteka projekta JBuilder - Projekt JBuilder - JBuilder пројекат - JBuilder-projekt - JBuilder projesi - проект JBuilder - Dự án JBuilder - JBuilder 工程 - JBuilder 專案 - - - - - - Karbon14 drawing - تصميم Karbon14 - Rysunak Karbon14 - Чертеж — Karbon14 - dibuix de Karbon14 - Kresba Karbon14 - Karbon14-tegning - Karbon14-Zeichnung - σχέδιο Karbon14 - Karbon14 drawing - Karbon14-grafikaĵo - dibujo de Karbon14 - Karbon14 marrazkia - Karbon14-piirros - Karbon14 tekning - dessin Karbon14 - líníocht Karbon14 - debuxo de Karbon14 - ציור Karbon14 - Karbon14 crtež - Karbon14-rajz - Gambar Karbon14 - Disegno Karbon14 - Karbon14 ドロー - Karbon14 суреті - Karbon14 그림 - Karbon14 piešinys - Karbon14 zīmējums - Lukisan Karbon14 - Karbon14-tegning - Karbon14-tekening - Karbon14-teikning - Rysunek Karbon14 - desenho Karbon14 - Desenho do Karbon14 - Desen Karbon14 - изображение Karbon14 - Kresba Karbon14 - Datoteka risbe Karbon14 - Vizatim Karbon14 - Karbon14 цртеж - Karbon14-teckning - Karbon14 çizimi - малюнок Karbon14 - Bản vẽ Karbon14 - Karbon14 绘图 - Karbon14 繪圖 - - - - - - - - - - - - - - - - - KChart chart - رسم بياني KChart - Hrafik KChart - Диаграма — KChart - diagrama de KChart - Graf Chart - KChart-diagram - KChart-Diagramm - γράφημα KChart - KChart chart - KChart-diagramo - gráfica de KChart - KChart diagrama - KChart-kaavio - KChart strikumynd - graphique KChart - cairt KChart - gráfica de KChart - תרשים KChart - KChart grafikon - KChart-grafikon - Bagan KChart - Grafico KChart - KChart チャート - KChart диаграммасы - KChart 차트 - KChart diagrama - KChart diagramma - Carta KChart - KChart-graf - KChart-grafiek - KChart-diagram - Wykres KChart - gráfico KChart - Gráfico do KChart - Diagramă KChart - диаграмма KChart - Graf KChart - Datoteka grafikona KChart - Grafik KChart - KChart графикон - KChart-diagram - діаграма KChart - Sơ đồ KChart - KChart 图表 - KChart 圖表 - - - - - - - - - - - - - - - - - Kexi settings for database server connection - إعدادات Kexi للإتصال بخادم قاعدة البيانات - Връзка към база от данни — Kexi - configuració del Kexi per a la connexió al servidor de bases de dades - Nastavení Kexi ke spojení s databázovým serverem - Kexiopsætning til forbindelsen for databaseserveren - Kexi-Einstellungen für Verbindung zum Datenbankserver - ρυθμίσεις Kexi για σύνδεση με εξυπηρετητή βάσεων δεδομένων - Kexi settings for database server connection - configuración de Kexi para la conexión con el servidor de bases de datos - Kexi-ren ezarpenak datu-basearen zerbitzariarekin konektatzeko - Kexi-tietokantayhteysasetukset - Kexi stillingar fyri dátustovnsambætara sambinding - paramètres Kexi pour connexion au serveur de base de données - socruithe Kexi do cheangal le freastalaí bunachair sonraí - configuración de Kexi para conexión con servidor de base de datos - הגדרות של Kexi עבור חיבור שרת לבסיס נתונים - Kexi beállítások adatbáziskiszolgáló-kapcsolathoz - Tatanan Kexi bagi koneksi server basis data - Impostazioni Kexi per connessione a server di database - データベースサーバ接続用の Kexi 設定 - Дерекқор серверге байланыс Kexi баптаулары - Kexi 데이터베이스 서버 연결 설정 - Kexi duomenų bazės ryšio su serveriu parametrai - Kexi iestatījumi datubāzes servera savienojumam - Kexi instellingen voor database server connectie - Ustawienia Kexi dla połączenia serwera bazy danych - Configurações do Kexi para conexão a servidor de banco de dados - Configurări Kexi pentru conexiunea la serverul de baze de date - параметры Kexi для подключения к серверу БД - Nastavenia Kexi pre pripojenie k databázovému serveru - Strežniška povezava do nastavitvene datoteke Kexi. - Kexi-inställningar för anslutning till databasserver - параметри Kexi для встановлення з’єднання з сервером бази даних - Kexi 数据库服务器连接设置 - Kexi 設定值 (資料庫伺服器連線用) - - - - shortcut to Kexi project on database server - اختصار لمشروع Kexi على خادم قاعدة بيانات - Връзка към проект — Kexi - drecera a projecte del Kexi en un servidor de base de dades - Zástupce projektu Kexi na databázovém serveru - genvej til Kexiprojekt på databaseserver - Schnellzugriff zum Kexi-Projekt auf dem Datenbankserver - συντόμευση σε έργο Kexi στον εξυπηρετητή βάσης δεδομένων - shortcut to Kexi project on database server - acceso directo a proyecto Kexi en el servidor de bases de datos - lasterbidea datu-basearen zerbitzariko Kexi proiekturako - snarvegur til Kexi verkætlan á dátustovnsambætara - raccourci vers projet Kexi sur serveur de base de données - aicearra go tionscadal Kexi ar fhreastalaí bunachair sonraí - acceso directo a proxecto Kexi no servidor de bases de datos - קיצור דרך לפרוירט Kexi בשרת נתונים - prečac za Kexi projekt na poslužitelju baze podataka - indítóikon adatbázis-kiszolgálón lévő Kexi projektre - pintasan ke projek Kexi pada server basis data - Scorciatoia a progetto Kexi su server di database - データベースサーバの Kexi プロジェクトへのショートカット - дерекқор серверіндегі Kexi жобасына сілтеме - 데이터베이스 서버의 Kexi 프로젝트 바로 가기 - nuoroda į Kexi projektą duomenų bazės serveryje - īsceļš uz Kexi projektu datubāzes serverī - shortcut naar Kexi project op database server - Skrót do projektu Kexi na serwerze bazy danych - Atalho para projeto Kexi no servidor de banco de dados - scurtătură către un proiect Kexi pe un server de baze de date - ссылка на проект Kexi на сервере БД - bližnjica do Kexi projekta na podatkovnem strežniku - genväg till Kexi-projekt på databasserver - скорочення для проекту Kexi на сервері бази даних - 数据库服务器上 Kexi 项目的快捷方式 - 資料庫伺服器上 Kexi 專案的捷徑 - - - - Kexi database file-based project - مشروع قاعدة بيانات Kexi يعتمد على ملفات - Проект с база от данни — Kexi - projecte basat en fitxer de base de dades del Kexi - Projekt založený na souboru databáze Kexi - Filbaseret projekt for Kexidatabase - Dateibasiertes Kexi-Datenbankprojekt - Kexi database file-based project - proyecto basado en el archivo-base de datos Kexi - Kexi datu-baseko fitxategian oinarritutako proiektua - Kexi dátustovns fílugrundað verkætlan - projet de base de données Kexi en mode fichier - tionscadal bunachair sonraí Kexi bunaithe ar chomhaid - proxecto baseado no ficheiro-base de datos Kexi - פרויקט בסיס נתונים מבוסס-קובץ של Kexi - Kexi adatbázisfájl-alapú projekt - Projek berbasis berkas basis data Kexi - Progetto su file di database Kexi - Kexi データベース ファイルベースプロジェクト - Файл негізінде жоба үшін Kexi дерекқоры - Kexi 데이터베이스 파일 기반 프로젝트 - Kexi duomenų bazės failo tipo projektas - Kexi datubāzes datnes balstīts projekts - Kexi database bestandgebaseerd project - Projekt bazy danych Kexi oparty na pliku - Projeto de banco de dados baseado em arquivo do Kexi - Proiect bazat pe fișiere al bazei de date Kexi - файловый проект базы данных Kexi - Datoteka projekta podatkovne zbirke Kexi - Kexi-databas för filbaserat projekt - проект файлової бази даних Kexi - Kexi 基于文件的数据库项目 - Kexi 資料庫檔案基礎專案 - - - - - Kexi database file-based project - مشروع قاعدة بيانات Kexi يعتمد على ملفات - Проект с база от данни — Kexi - projecte basat en fitxer de base de dades del Kexi - Projekt založený na souboru databáze Kexi - Filbaseret projekt for Kexidatabase - Dateibasiertes Kexi-Datenbankprojekt - Kexi database file-based project - proyecto basado en el archivo-base de datos Kexi - Kexi datu-baseko fitxategian oinarritutako proiektua - Kexi dátustovns fílugrundað verkætlan - projet de base de données Kexi en mode fichier - tionscadal bunachair sonraí Kexi bunaithe ar chomhaid - proxecto baseado no ficheiro-base de datos Kexi - פרויקט בסיס נתונים מבוסס-קובץ של Kexi - Kexi adatbázisfájl-alapú projekt - Projek berbasis berkas basis data Kexi - Progetto su file di database Kexi - Kexi データベース ファイルベースプロジェクト - Файл негізінде жоба үшін Kexi дерекқоры - Kexi 데이터베이스 파일 기반 프로젝트 - Kexi duomenų bazės failo tipo projektas - Kexi datubāzes datnes balstīts projekts - Kexi database bestandgebaseerd project - Projekt bazy danych Kexi oparty na pliku - Projeto de banco de dados baseado em arquivo do Kexi - Proiect bazat pe fișiere al bazei de date Kexi - файловый проект базы данных Kexi - Datoteka projekta podatkovne zbirke Kexi - Kexi-databas för filbaserat projekt - проект файлової бази даних Kexi - Kexi 基于文件的数据库项目 - Kexi 資料庫檔案基礎專案 - - - - - - - KFormula formula - صيغة KFormula - Formuła KFormula - Формула — KFormula - fórmula de KFormula - Vzorec KFormula - KFormula-formel - KFormula-Formel - μαθηματικός τύπος KFormula - KFormula formula - KFormula-formulo - fórmula de KFormula - KFormula formula - KFormula-kaava - KFormula frymil - formule KFormula - foirmle KFormula - fórmula de KFormula - נוסחת KFormula - KFormula formula - KFormula-képlet - Formula KFormula - Formula KFormula - KFormula 計算式 - KFormula формуласы - KFormula 수식 - KFormula formulė - KFormula formula - Formula KFormula - KFormula-formel - KFormula-formule - KFormula-formel - Formuła KFormula - fórmula KFormula - Fórmula do KFormula - Formulă KFormula - формула KFormula - Vzorec KFormula - Datoteka formule KFormula - Formulë KFormula - KFormula формула - KFormula-formel - KFormula formülü - формула KFormula - Công thức KFormula - KFormula 公式 - KFormula 公式 - - - - - - - - - - - - - - - - - KIllustrator drawing - تصميم KIllustrator - Rysunak KIllustrator - Чертеж — KIllustrator - dibuix de KIllustrator - Kresba KIllustrator - KIllustrator-tegning - KIllustrator-Zeichnung - σχέδιο KIllustrator - KIllustrator drawing - KIllustrator-grafikaĵo - dibujo de KIllustrator - KIllustrator marrazkia - KIllustrator-piirros - KIllustrator tekning - dessin KIllustrator - líníocht KIllustrator - debuxo de KIllustrator - ציור KIllustrator - KIllustrator crtež - KIllustrator-rajz - Gambar KIllustrator - Disegno KIllustrator - KIllustrator ドロー - KIllustrator суреті - KIllustrator 그림 - KIllustrator piešinys - KIllustrator zīmējums - Lukisan KIllustrator - KIllustrator-tegning - KIllustrator-tekening - KIllustrator-teikning - Rysunek KIllustrator - desenho KIllustrator - Desenho do KIllustrator - Desen KIllustrator - изображение KIllustrator - Kresba KIllustrator - Datoteka risbe KIllustrator - Vizatim KIllustrator - KIllustrator цртеж - KIllustrator-teckning - KIllustrator çizimi - малюнок KIllustrator - Bản vẽ KIllustrator - KIllustrator 绘图 - KIllustrator 繪圖 - - - - - - - - - - - - Kivio flowchart - قائمة تدفق Kivio - Blok-schiema Kivio - Диаграма — Kivio - diagrama de flux de Kivio - Vývojový diagram Kivio - Kiviorutediagram - Kivio-Flussdiagramm - διάγραμμα ροής Kivio - Kivio flowchart - Kivo-fluskemo - diagrama de flujo de Kivio - Kivio diagrama - Kivio-vuokaavio - Kivio leiðarit - diagramme de flux Kivio - sreabhchairt Kivio - gráfica de fluxo de Kivio - תרשים זרימה של Kivio - Kivio dijagram toka - Kivio-folyamatábra - Bagan Kivio - Diagramma di flusso Kivio - Kivio フローチャート - Kivio диаграммасы - Kivio 흐름도 - Kivio eigos diagrama - Kivio blokshēma - Cartalir Kivio - Kivio-flytdiagram - Kivio-stroomschema - Kivio-flytdiagram - Diagram przepływów Kivio - gráfico de fluxo Kivio - Fluxograma do Kivio - Diagramă Kivio - диаграмма Kivio - Vývojový diagram Kivio - Datoteka grafikona Kivio - Diagramë fluksi Kivio - Kivio дијаграм - Kivio-flödesschema - блок-схема Kivio - Lược đồ Kivio - Kivio 流程图 - Kivio 圖表 - - - - - - - - - - - - - - - - - Kontour drawing - تصميم Kontour - Rysunak Kontour - Чертеж — Kontour - dibuix de Kontour - Kresba Kontour - Kontourtegning - Kontour-Zeichnung - σχέδιο Kontour - Kontour drawing - Kontour-grafikaĵo - dibujo de Kontour - Kontour marrazkia - Kontour-piirros - Kontour tekning - dessin Kontour - líníocht Kontour - debuxo de Kontour - ציור Kontour - Kontour crtež - Kontour-rajz - Gambar Kontour - Disegno Kontour - Kontour ドロー - Kontour суреті - Kontour 그림 - Kontour piešinys - Kontour zīmējums - Lukisan Kontour - Kontour-tegning - Kontour-tekening - Kontour-teikning - Rysunek Kontour - desenho Kontour - Desenho do Kontour - Desen Kontour - изображение Kontour - Kresba Kontour - Datoteka risbe Kontour - Vizatim Kontour - Kontour цртеж - Kontour-teckning - Kontour çizimi - малюнок Kontour - Bản vẽ Kontour - Kontour 绘图 - Kontour 繪圖 - - - - - - - - - - - - - - - - - KPovModeler scene - مشهد KPovModeler - Scena KPovModeler - Сцена — KPovModeler - escena de KPovModeler - Scéna KPovModeler - KPovModeler-scene - KPovModeler-Szene - σκηνή KPovModeler - KPovModeler scene - KPovModeler-sceno - escena de KPovModeler - KPovModeler eszena - KPovModeler-näkymä - KPovModeler leikmynd - scène KPovModeler - radharc KPovModeler - escena de KPovModeler - סצנת KPovModeler - KPovModeler scena - KPovModeler-jelenet - Scene KPovModeler - Scena KPovModeler - KPovModeler シーン - KPovModeler сахнасы - KPovModeler 장면 - KPovModeler scena - KPovModeler aina - Babak KPovModeler - KPovModeler-scene - KPovModeler-scène - KPovModeler-scene - Scena KPovModeler - cenário KPovModeler - Cena do KPovModeler - Scenă KPovModeler - сцена KPovModeler - Scéna KPovModeler - Datoteka scene KPovModeler - Skenë KPovModeler - KPovModeler сцена - KPovModeler-scen - сцена KPovModeler - Cảnh KPovModeler - KPovModeler 场景 - KPovModeler 場景 - - - - - KPresenter presentation - عرض تقديمي KPresenter - Prezentacyja KPresenter - Презентация — KPresenter - presentació de KPresenter - Prezentace KPresenter - KPresenter-præsentation - KPresenter-Präsentation - παρουσίαση KPresenter - KPresenter presentation - KPresenter-prezentaĵo - presentación de KPresenter - Kpresenter aurkezpena - KPresenter-esitys - KPresenter framløga - présentation KPresenter - láithreoireacht KPresenter - presentación de KPresenter - מצגת KPresenter - KPresenter prezentacija - KPresenter-bemutató - Presentasi KPresenter - Presentazione KPresenter - KPresenter プレゼンテーション - KPresenter презентациясы - KPresenter 프리젠테이션 - KPresenter pateiktis - KPresenter prezentācija - Persembahan Kpresenter - KPresenter-presentasjon - KPresenter-presentatie - KPresenter-presentasjon - Prezentacja KPresenter - apresentação KPresenter - Apresentação do KPresenter - Prezentare KPresenter - презентация KPresenter - Prezentácia KPresenter - Predstavitev KPresenter - Prezantim i KPresenter - KPresenter презентација - KPresenter-presentation - KPresenter sunum dosyası - презентація KPresenter - Trình diễn KPresenter - KPresenter 演示文稿 - KPresenter 簡報檔 - - - - - - - - - - - - - - - - - - Krita document - مستند Krita - Dakument Krita - Документ — Krita - document de Krita - Dokument Krita - Kritadokument - Krita-Dokument - έγγραφο Krita - Krita document - Krita-dokumento - documento de Krita - Krita dokumentua - Krita-asiakirja - Krita skjal - document Krita - cáipéis Krita - documento de Krita - מסמך Krita - Krita dokument - Krita-dokumentum - Dokumen Krita - Documento Krita - Krita ドキュメント - Krita құжаты - Krita 문서 - Krita dokumentas - Krita dokuments - Dokumen Krita - Krita-dokument - Krita-document - Krita-dokument - Dokument Krita - documento Krita - Documento do Krita - Document Krita - документ Krita - Dokument Krita - Dokument Krita - Dokument Krita - Krita документ - Krita-dokument - Krita belgesi - документ Krita - Tài liệu Krita - Krita 文档 - Krita 文件 - - - - - - - - - - - - - - - - - KSpread spreadsheet - جدول KSpread - Raźlikovy arkuš KSpread - Таблица — KSpread - full de càlcul de KSpread - Sešit KSpread - KSpread-regneark - KSpread-Tabelle - λογιστικό φύλλο KSpread - KSpread spreadsheet - KSpread-kalkultabelo - hoja de cálculo de KSpread - KSpread kalkulu-orria - KSpread-taulukko - KSpread rokniark - feuille de calcul KSpread - scarbhileog KSpread - folla de cálculo de KSpread - גליון נתונים של Kspread - KSpread proračunska tablica - KSpread-munkafüzet - Lembar sebar KSpread - Foglio di calcolo KSpread - KSpread スプレッドシート - KSpread электрондық кестесі - KSpread 스프레드시트 - KSpread skaičialentė - KSpread izklājlapa - Hamparan KSpread - KSpread-regneark - KSpread-rekenblad - KSpread-rekneark - Arkusz KSpread - folha de cálculo KSpread - Planilha do KSpread - Foaie de calcul KSpread - электронная таблица KSpread - Zošit KSpread - Preglednica KSpread - Fletë llogaritjesh KSpread - KSpread табеларни прорачун - KSpread-kalkylblad - ел. таблиця KSpread - Bảng tính KSpread - KSpread 工作簿 - KSpread 試算表 - - - - - - - - - - - - - - - - - KSpread spreadsheet (encrypted) - جدول KSpread (مشفر) - Raźlikovy arkuš KSpread (zašyfravany) - Таблица — KSpread, шифрирана - full de càlcul de KSpread (xifrat) - Sešit KSpread (šifrovaný) - KSpread-regneark (krypteret) - KSpread-Tabelle (verschlüsselt) - λογιστικό φύλλο KSpread (κρυπτογραφημένο) - KSpread spreadsheet (encrypted) - KSpread-kalkultabelo (ĉifrita) - hoja de cálculo de KSpread (cifrada) - KSpread kalkulu-orria (enkriptatua) - KSpread-taulukko (salattu) - KSpread rokniark (bronglað) - feuille de calcul KSpread (chiffrée) - scarbhileog KSpread (criptithe) - folla de cálculo de KSpread (cifrada) - גליון נתונים של KSpread (מוצפן) - KSpread proračunska tablica (šifrirana) - KSpread-munkafüzet (titkosított) - Lembar sebar KSpread (terenkripsi) - Foglio di calcolo KSpread (cifrato) - KSpread (暗号化) スプレッドシート - KSpread электрондық кестесі (шифрленген) - 암호화된 KSpread 스프레드시트 - KSpread skaičialentė (užšifruota) - KSpread izklājlapa (šifrēta) - Hampatan KSpread (terenkripsi) - KSpread-regneark (kryptert) - KSpread-rekenblad (versleuteld) - Kryptert KSpread-rekneark - Arkusz KSpread (zaszyfrowany) - folha de cálculo KSpread (cifrada) - Planilha do KSpread (criptografada) - Foaie de calcul KSpread (criptat) - электронная таблица KSpread (зашифрованная) - Zošit KSpread (šifrovaný) - Preglednica KSpread (šifrirana) - Fletë llogaritjesh KSpread (e kriptuar) - KSpread табеларни прорачун (шифровани) - KSpread-kalkylblad (krypterat) - ел. таблиця KSpread (зашифрована) - Bảng tính KSpread (đã mật mã) - KSpread 加密工作簿 - KSpread 試算表 (已加密) - - - - - - - KSysV init package - حزمة KSysV init - Inicyjalny pakunak KSysV - Пакет — KSysV init - paquet d'inici KSysV - Balíček init KSysV - KSsV init-pakke - KSysV-Init-Paket - KSysV init package - paquete de configuración de init para KSysV - KSysV hasieratzeko paketea - KSysV init -paketti - KSysV init pakki - paquet d'initialisation KSysV - pacáiste thosú KSysV - paquete de KsysV init - חבילת KSysV init - KSysV init paket - KSysV init csomag - Paket init KSysV - Pacchetto init KSysV - KSysV init パッケージ - KSysV инициализация дестесі - KSysV init 패키지 - KSysV init paketas - KSysV inicializācijas pakotne - KSysV init-pakke - KSysV-init-pakket - KSysV init-pakke - Pakiet KSysV init - Pacote init do KSysV - Pachet KSysV init - пакет инициализации KSysV - Balíček KSysV init - Datoteka paketa KSysV init - Paketë init KSysV - KSysV init-paket - пакунок KSysV init - Gói sở khởi KSysV - KSysV init 软件包 - KSysV init 套件 - - - - - - - - - Kugar document - مستند Kugar - Dakument Kugar - Документ — Kugar - document de Kugar - Dokument Kugar - Kugardokument - Kugar-Dokument - έγγραφο Kugar - Kugar document - Kugar-dokumento - documento de Kugar - Kugar dokumentua - Kugar-asiakirja - Kugar skjal - document Kugar - cáipéis Kugar - documento de Kugar - מסמך Kugar - Kugar dokument - Kugar-dokumentum - Dokumen Kugar - Documento Kugar - KuKrita ドキュメント - Kugar құжаты - Kugar 문서 - Kugar dokumentas - Kugar dokuments - Dokumen Kugar - Kugar-dokument - Kugar-document - Kugar-dokument - Dokument Kuguar - documento Kugar - Documento do Kugar - Document Kugar - документ Kugar - Dokument Kugar - Dokument Kugar - Dokument Kugar - Kugar документ - Kugar-dokument - Kugar belgesi - документ Kugar - Tài liệu Kugar - Kugar 文档 - Kugar 文件 - - - - - KWord document - مستند KWord - Dakument KWord - Документ — KWord - document de KWord - Dokument KWord - Dogfen KWord - KWord-dokument - KWord-Dokument - έγγραφο KWord - KWord document - KWord-dokumento - documento de KWord - KWord dokumentua - KWord-asiakirja - KWord skjal - document KWord - cáipéis KWord - documento de KWord - מסמך KWord - KWord dokument - KWord-dokumentum - Dokumen KWord - Documento KWord - KWord ドキュメント - KWord құжаты - KWord 문서 - KWord dokumentas - KWord dokuments - Dokumen KWord - KWord-dokument - KWord-document - KWord-dokument - Dokument KWord - documento KWord - Documento do KWord - Document KWord - документ KWord - Dokument KWord - Dokument KWord - Dokument KWord - KWord документ - KWord-dokument - KWord belgesi - документ KWord - Tài liệu KWord - KWord 文档 - KWord 文件 - - - - - - - - - - - - - - - - - - KWord document (encrypted) - مستند KWord (مشفر) - Dakument KWord (zašyfravany) - Документ — KWord, шифриран - document de KWord (xifrat) - Dokument KWord (šifrovaný) - KWord-dokument (krypteret) - KWord-Dokument (verschlüsselt) - έγγραφο KWord (κρυπτογραφημένο) - KWord document (encrypted) - KWord-dokumento (ĉifrita) - documento de KWord (cifrado) - KWord dokumentua (enkriptatua) - KWord-asiakirja (salattu) - KWord skjal (bronglað) - document KWord (chiffré) - cáipéis KWord (criptithe) - documento de KWord (cifrado) - מסמך KWord (מוצפן) - KWord dokument (šifriran) - KWord-dokumentum (titkosított) - Dokumen KWord (terenkripsi) - Documento KWord (cifrato) - KWord (暗号化) ドキュメント - KWord құжаты (шифрленген) - 암호화된 KWord 문서 - KWord dokumentas (užšifruotas) - KWord dokuments (šifrēts) - Dokumen Kword (terenkripsi) - KWord-dokument (kryptert) - KWord-document (versleuteld) - Kryptert KWord-dokument - Dokument KWord (zaszyfrowany) - documento KWord (cifrado) - Documento do KWord (criptografado) - Document KWord (criptat) - документ KWord (зашифрованный) - Dokument KWord (šifrovaný) - Dokument KWord (šifriran) - Dokument KWord (i kriptuar) - KWord документ (шифровани) - KWord-dokument (krypterat) - KWord belgesi (şifreli) - документ KWord (зашифрований) - Tài liệu KWord (đã mật mã) - KWord 加密文档 - KWord 文件 (已加密) - - - - - - - LHA archive - أرشيف LHA - LHA arxivi - Archiŭ LHA - Архив — LHA - arxiu LHA - Archiv LHA - Archif LHA - LHA-arkiv - LHA-Archiv - αρχείο LHA - LHA archive - LHA-arkivo - archivador LHA - LHA artxiboa - LHA-arkisto - LHA skjalasavn - archive LHA - cartlann LHA - arquivo LHA - ארכיון LHA - LHA arhiva - LHA-archívum - Arsip LHA - Archivio LHA - LHA アーカイブ - LHA архиві - LHA 압축 파일 - LHA archyvas - LHA arhīvs - Arkib LHA - LHA-arkiv - LHA-archief - LHA-arkiv - Archiwum LHA - arquivo LHA - Pacote LHA - Arhivă LHA - архив LHA - Archív LHA - Datoteka arhiva LHA - Arkiv LHA - LHA архива - LHA-arkiv - LHA arşivi - архів LHA - Kho nén LHA - LHA 归档文件 - LHA 封存檔 - - - - - - - - - - - - - - - - - - - - - LHZ archive - أرشيف LHZ - Archiŭ LHZ - Архив — LHZ - arxiu LHZ - Archiv LHZ - LHZ-arkiv - LHZ-Archiv - αρχείο LHZ - LHZ archive - LHZ-arkivo - archivador LHZ - LHZ artxiboa - LHZ-arkisto - LHZ skjalasavn - archive LHZ - cartlann LHZ - arquivo LHZ - ארכיון LHZ - LHZ arhiva - LHZ-archívum - Arsip LHZ - Archivio LHZ - LHZ アーカイブ - LHZ архиві - LHZ 압축 파일 - LHZ archyvas - LHZ arhīvs - Arkib LHZ - LHZ-arkiv - LHZ-archief - LHZ-arkiv - Archiwum LHZ - arquivo LHZ - Pacote LHZ - Arhivă LHZ - архив LHZ - Archív LHZ - Datoteka arhiva LHZ - Arkiv LHZ - LHZ архива - LHZ-arkiv - LHZ arşivi - архів LHZ - Kho nén LHZ (LHA đã nén) - LHZ 归档文件 - LHZ 封存檔 - - - - - message catalog - كتالوج الرسالة - kataloh paviedamleńniaŭ - Каталог със съобщения - catàleg de missatges - Katalog zpráv - meddelelseskatalog - Nachrichtenkatalog - κατάλογος μηνυμάτων - message catalogue - katalogo de mesaĝoj - catálogo de mensajes - mezuen katalogoa - viestiluettelo - boðskrá - catalogue de messages - catalóg theachtaireachtaí - catálogo de mensaxes - קטלוג הודעות - katalog poruka - üzenetkatalógus - katalog pesan - Catalogo di messaggi - メッセージカタログ - мәлімдемелер каталогы - 메시지 카탈로그 - laiškų katalogas - ziņojumu katalogs - Katalog mesej - meldingskatalog - berichtencatalogus - meldingskatalog - Katalog wiadomości - catálogo de mensagens - Catálogo de mensagens - catalog de mesaje - каталог сообщений - Katalóg správ - katalogov sporočil - Katallog mesazhesh - каталог порука - meddelandekatalog - каталог повідомлень - phân loại thông điệp - 消息库 - 訊息目錄 - - - - - - - - - LyX document - مستند LyX - Dakument LyX - Документ — LyX - document de LyX - Dokument LyX - LyX-dokument - LyX-Dokument - έγγραφο LyX - LyX document - LyX-dokumento - documento de LyX - LyX dokumentua - LyX-asiakirja - LyX skjal - document LyX - cáipéis LyX - documento LyX - מסמך Lyx - LyX dokument - LyX-dokumentum - Dokumen LyX - Documento LyX - LyX ドキュメント - LyX құжаты - LyX 문서 - LyX dokumentas - LyX dokuments - Dokumen LyX - LyX-dokument - LyX-document - LyX-dokument - Dokument LyX - documento LyX - Documento LyX - Document LyX - документ LyX - Dokument LyX - Dokument LyX - Dokument LyX - LyX документ - LyX-dokument - документ LyX - Tài liệu LyX - LyX 文档 - LyX 文件 - - - - - - - - - - Lzip archive - أرشيف Lzip - Архив — lzip - arxiu lzip - Archiv Lzip - Lzip-arkiv - Lzip-Archiv - συμπιεσμένο αρχείο Lzip - Lzip archive - Lzip-arkivo - archivador Lzip - Lzip artxiboa - Lzip-arkisto - Lzip skjalasavn - archive lzip - cartlann Lzip - arquivo Lzip - ארכיון Lzip - Lzip arhiva - Lzip archívum - Arsip Lzip - Archivio Lzip - Lzip アーカイブ - Lzip архиві - LZIP 압축 파일 - Lzip archyvas - Lzip arhīvs - Lzip archief - Archiwum lzip - Pacote Lzip - Arhivă Lzip - архив LZIP - Archív Lzip - Datoteka arhiva Lzip - Lzip-arkiv - архів lzip - Lzip 归档文件 - Lzip 封存檔 - - - - - - - - LZMA archive - أرشيف LZMA - Archiŭ LZMA - Архив — LZMA - arxiu LZMA - Archiv LZMA - LZHA-arkiv - LZMA-Archiv - συμπιεσμένο αρχείο LZMA - LZMA archive - LZMA-arkivo - archivador LZMA - LZMA artxiboa - LZMA-arkisto - LZMA skjalasavn - archive LZMA - cartlann LZMA - arquivo LZMA - ארכיון LZMA - LZMA arhiva - LZMA-archívum - Arsip LZMA - Archivio LZMA - LZMA アーカイブ - LZMA архиві - LZMA 압축 파일 - LZMA archyvas - LZMA arhīvs - LZMA-arkiv - LZMA-archief - LZMA-arkiv - Archiwum LZMA - Pacote LZMA - Arhivă LZMA - архив LZMA - Archív LZMA - Datoteka arhiva LZMA - Arkiv LZMA - LZMA-arkiv - LZMA arşivi - архів LZMA - Kho nén LZMA - LZMA 归档文件 - LZMA 封存檔 - LZMA - Lempel-Ziv-Markov chain-Algorithm - - - - - Tar archive (LZMA-compressed) - أرشيف Tar (مضغوط-LZMA) - Archiŭ tar (LZMA-skampresavany) - Архив — tar, компресиран с LZMA - arxiu tar (comprimit amb LZMA) - Archiv tar (komprimovaný pomocí LZMA) - Tar-arkiv (LZMA-komprimeret) - Tar-Archiv (LZMA-komprimiert) - αρχείο Tar (συμπιεσμένο με LZMA) - Tar archive (LZMA-compressed) - archivador Tar (comprimido con LZMA) - Tar artxiboa (LZMA-rekin konprimitua) - Tar-arkisto (LZMA-pakattu) - Tar skjalasavn (LZMA-stappað) - archive tar (compression LZMA) - cartlann Tar (comhbhrúite le LZMA) - arquivo Tar (comprimido con LZMA) - ארכיון Tar (מכווץ ע"י LZMA) - Tar arhiva (komprimirana LZMA-om) - Tar archívum (LZMA-val tömörítve) - Arsip Tar (terkompresi LZMA) - Archivio tar (compresso con LZMA) - Tar アーカイブ (LZMA 圧縮) - Tar архиві (LZMA-мен сығылған) - TAR 묶음 파일 (LZMA 압축) - Tar archyvas (suglaudintas su LZMA) - Tar arhīvs (saspiests ar LZMA) - Tar-arkiv (LZMA-komprimert) - Tar-archief (ingepakt met LZMA) - Tar-arkiv (pakka med LZMA) - Archiwum tar (kompresja LZMA) - Pacote tar (compactado com LZMA) - Arhivă Tar (comprimată LZMA) - архив TAR (сжатый LZMA) - Archív tar (komprimovaný pomocou LZMA) - Datoteka arhiva Tar (stisnjen z LZMA) - Arkiv tar (i kompresuar me LZMA) - Tar-arkiv (LZMA-komprimerat) - архів tar (стиснений LZMA) - Kho nén tar (đã nén LZMA) - Tar 归档文件 (LZMA 压缩) - Tar 封存檔 (LZMA 格式壓縮) - - - - - - - LZO archive - أرشيف LZO - Archiŭ LZO - Архив — LZO - arxiu LZO - Archiv LZO - LZO-arkiv - LZO-Archiv - αρχείο LZO - LZO archive - LZO-arkivo - archivador LZO - LZO artxiboa - LZO-arkisto - LZO skjalasavn - archive LZO - cartlann LZO - arquivo LZO - ארכיון LZO - LZO arhiva - LZO-archívum - Arsip LZO - Archivio LZO - LZO アーカイブ - LZO архиві - LZO 압축 파일 - LZO archyvas - LZO arhīvs - Arkib LZO - LZO-arkiv - LZO-archief - LZO-arkiv - Archiwum LZO - arquivo LZO - Pacote LZO - Arhivă LZO - архив LZO - Archív LZO - Datoteka arhiva LZO - Arkiv LZO - LZO архива - LZO-arkiv - LZO arşivi - архів LZO - Kho nén LZO - LZO 归档文件 - LZO 封存檔 - LZO - Lempel-Ziv-Oberhumer - - - - - - - - MagicPoint presentation - عرض تقديمي MagicPoint - Prezentacyja MagicPoint - Презентация — MagicPoint - presentació de MagicPoint - Prezentace MagicPoint - Cyflwyniad MagicPoint - MagicPoint-præsentation - MagicPoint-Präsentation - παρουσίαση MagicPoint - MagicPoint presentation - MagicPoint-prezentaĵo - presentación de MagicPoint - MagicPoint aurkezpena - MagicPoint-esitys - MagicPoint framløga - présentation MagicPoint - láithreoireacht MagicPoint - presentación de MagicPoint - מצגת MagicPoint - MagicPoint prezentacija - MagicPoint-bemutató - Presentasi MagicPoint - Presentazione MagicPoint - MagicPoint プレゼンテーション - MagicPoint-ის პრეზენტაცია - MagicPoint презентациясы - MagicPoint 프리젠테이션 - MagicPoint pateiktis - MagicPoint prezentācija - Persembahan MagicPoint - MagicPoint-presentasjon - MagicPoint-presentatie - MagicPoint-presentasjon - Prezentacja programu MagicPoint - apresentação MagicPoint - Apresentação do MagicPoint - Prezentare MagicPoint - презентация MagicPoint - Prezentácia MagicPoint - Predstavitev MagicPoint - Prezantim MagicPoint - MagicPoint презентација - MagicPoint-presentation - презентація MagicPoint - Trình diễn MagicPoint - MagicPoint 演示文稿 - MagicPoint 簡報檔 - - - - - - Macintosh MacBinary file - ملف Macintosh MacBinary - Fajł Macintosh MacBinary - Файл — MacBinary - fitxer MacBinary de Macintosh - Soubor MacBinary pro Macintosh - Macintosh MacBinary-fil - Macintosh-MacBinary-Datei - εκτελέσιμο Macintosh MacBinary - Macintosh MacBinary file - MacBinary-dosiero de Macintosh - archivo de Macintosh MacBinary - Macintosh MacBinary fitxategia - Macintosh MacBinary -tiedosto - Macintosh MacBinary fíla - fichier Macintosh MacBinary - comhad Macintosh MacBinary - ficheiro MacBinary de Macintosh - קובץ בינארי של מקינטוש - Macintosh MacBinary datoteka - Macintosh MacBinary-fájl - Berkas Macintosh MacBinary - File Macintosh MacBinary - MacBinary MacBinary ファイル - Macintosh MacBinary файлы - MacBinary 파일 - Macintosh MacBinary failas - Macintosh MacBinary datne - Fail MacBinary Macintosh - Macintosh MacBinary-fil - Macintosh MacBinary-bestand - Macintosh MacBinary-fil - Plik MacBinary Macintosh - ficheiro MacBinary de Macintosh - Arquivo do Macintosh MacBinary - Fișier Macintosh MacBinary - файл Macintosh MacBinary - Súbor pre Macintosh MacBinary - Izvedljiva dvojiška datoteka Macintosh MacBinary - File MacBinary Macintosh - Мекинтош MacBinary датотека - Macintosh MacBinary-fil - файл Macintosh MacBinary - Tập tin nhị phân MacBinary của Macintosh - Macintosh MacBinary 文件 - Macintosh MacBinary 檔 - - - - - - - Matroska stream - دفق Matroska - Płyń Matroska - Поток — Matroska - flux Matroska - Proud Matroska - Matroskastrøm - Matroska-Datenstrom - ροή Matroska - Matroska stream - flujo Matroska - Matroska korrontea - Matroska-virta - Matroska streymur - flux Matroska - sruth Matroska - fluxo de Matroska - זרימת Matroska - Matroska adatfolyam - Stream Matroska - Stream Matroska - Matroska ストリーム - Matroska-ის ნაკადი - Matroska ағымы - Matroska 스트림 - Matroska srautas - Matroska straume - Matroska-stream - Matroska-straum - Strumień Matroska - Transmissão do Matroska - Flux Matroska - поток Matroska - Stream Matroska - Pretočni vir Matroska - Stream Matroska - Matroska-ström - потік даних Matroska - Luồng Matroska - Matroska 流 - Matroska 串流 - - - - - - - - - - - - - - Matroska video - Matroska مرئي - Videa Matroska - Видео — Matroska - vídeo Matroska - Video Matroska - Matroskavideo - Matroska-Video - βίντεο Matroska - Matroska video - Matroska-video - vídeo Matroska - Matroska bideoa - Matroska-video - Matroska video - vidéo Matroska - físeán Matroska - vídeo de Matroska - וידאו Matroska - Matroska video - Matroska-videó - Video Matroska - Video Matroska - Matroska 動画 - Matroska-ის ვიდეო - Matroska видеосы - Matroska 비디오 - Matroska vaizdo įrašas - Matroska video - Video Matroska - Matroska-film - Matroska-video - Matroska-video - Plik wideo Matroska - vídeo Matroska - Vídeo Matroska - Video Matroska - видео Matroska - Video Matroska - Video datoteka Matroska - Video Matroska - Матрошка видео - Matroska-video - відеокліп Matroska - Ảnh động Matroska - Matroska 视频 - Matroska 視訊 - - - - - Matroska 3D video - - - - - Matroska audio - سمعي Matroska - Aŭdyjo Matroska - Аудио — Matroska - àudio Matroska - Zvuk Matroska - Matroskalyd - Matroska-Audio - ήχος Matroska - Matroska audio - Matroska-sondosiero - sonido Matroska - Matroska audioa - Matroska-ääni - Matroska ljóður - audio Matroska - fuaim Matroska - son de Matroska - שמע Matroska - Matroska audio - Matroska hang - Audio Matroska - Audio Matroska - Matroska オーディオ - Matroska-ის აუდიო - Matroska аудиосы - Matroska 오디오 - Matroska garso įrašas - Matroska audio - Matroska-lyd - Matroska-audio - Matroska-lyd - Plik dźwiękowy Matroska - Áudio Matroska - Audio Matroska - аудио Matroska - Zvuk Matroska - Zvočna datoteka Matroska - Audio Matroska - Matroska-ljud - звук Matroska - Âm thanh Matroska - Matroska 音频 - Matroska 音訊 - - - - - WebM video - WebM مرئي - Видео — WebM - vídeo WebM - Video WebM - WebM-video - WebM-Video - βίντεο WebM - WebM video - WebM-video - vídeo WebM - WebM-video - WebM video - vidéo WebM - físeán WebM - vídeo WebM - וידאו WebM - WebM video - WebM videó - Video WebM - Video WebM - WebM 動画 - WebM видеосы - WebM 비디오 - WebM vaizdo įrašas - WebM video - WebM video - Plik wideo WebM - Vídeo WebM - Video WebM - видео WebM - Video WebM - Video datoteka WebM - WebM-video - відео WebM - WebM 视频 - WebM 視訊 - - - - - - - - - - - - - - WebM audio - WebM سمعي - Аудио — WebM - àudio WebM - Zvuk WebM - WebM-lyd - WebM-Audio - ήχος WebM - WebM audio - WebM-sondosiero - sonido WebM - WebM-ääni - WebM ljóður - audio WebM - fuaim WebM - son WebM - שמע WebM - WebM audio - WebM hang - Audio WebM - Audio WebM - WebM オーディオ - WebM аудиосы - WebM 오디오 - WebM garso įrašas - WebM audio - WebM audio - Plik dźwiękowy WebM - Áudio WebM - Audio WebM - аудио WebM - Zvuk WebM - Zvočna datoteka WebM - WebM-ljud - звук WebM - WebM 音频 - WebM 音訊 - - - - MHTML web archive - MHTML - MIME HTML - - - - - - MXF video - MXF مرئي - Видео — MXF - vídeo MXF - Video MXF - MXF-video - MXF-Video - βίντεο MXF - MXF video - MXF-video - vídeo MXF - MXF bideoa - MXF-video - MXF video - vidéo MXF - físeán MXF - vídeo MXF - וידאו MXF - MXF video - MXF videó - Video MXF - Video MXF - MXF 動画 - MXF ვიდეო - MXF видеосы - MXF 비디오 - MXF vaizdo įrašas - MXF video - MXF video - Plik wideo MXF - Vídeo MXF - Video MXF - видео MXF - Video MXF - Video datoteka MXF - MXF-video - відеокліп MXF - MXF 视频 - MXF 視訊 - MXF - Material Exchange Format - - - - - - - - OCL file - ملف OCL - Fajł OCL - Файл — OCL - fitxer OCL - Soubor OCL - OCL-fil - OCL-Datei - αρχείο OCL - OCL file - OCL-dosiero - archivo OCL - OCL fitxategia - OCL-tiedosto - OCL fíla - fichier OCL - comhad OCL - ficheiro OCL - קובץ OCL - OCL datoteka - OCL fájl - Berkas OCL - File OCL - OCL ファイル - OCL файлы - OCL 파일 - OCL failas - OCL datne - OCL-fil - OCL-bestand - OCL-fil - Plik OCL - Arquivo OCL - Fișier OCL - файл OCL - Súbor OCL - Datoteka OCL - File OCL - OCL-fil - OCL dosyası - файл OCL - Tập tin OCL - OCL 文件 - OCL 檔 - OCL - Object Constraint Language - - - - - COBOL source file - Изходен код — COBOL - codi font en COBOL - Zdrojový soubor COBOL - COBOL-kildefil - COBOL-Quelldatei - πηγαίο αρχείο COBOL - COBOL source file - COBOL-fontdosiero - Archivo fuente de COBOL - COBOL-lähdekoodi - fichier source COBOL - ficheiro fonte de COBOL - קובץ מקור של COBOL - COBOL izvorna datoteka - COBOL forrásfájl - Berkas sumber COBOL - File sorgente COBOL - COBOL ソースファイル - COBOL-ის საწყისი ფაილი - COBOL бастапқы коды - COBOL 소스 파일 - COBOL pirmkods - COBOL bronbestand - Plik źródłowy COBOL - Arquivo de código-fonte em COBOL - файл исходного кода на COBOL - Izvorna koda COBOL - COBOL-källkodsfil - вихідний код мовою COBOL - COBOL 源 - COBOL 源檔 - COBOL - COmmon Business Oriented Language - - - - - - Mobipocket e-book - Е-книга — Mobipocket - llibre electrònic Mobipocket - Elektronická kniha Mobipocket - Mobipocket e-bog - Mobipocket E-Book - ηλεκτρονικό βιβλίο Mobipocket - Mobipocket e-book - Libro electrónico Mobipocket - Mobipocket e-kirja - livre numérique Mobipocket - E-book Mobipocket - ספר אלקטרוני של Mobipocket - Mobipocket e-knjiga - Mobipocket e-könyv - e-book Mobipocket - E-book Mobipocket - Mobipocket 電子書籍 - Mobipocket-ის ელწიგნი - Mobipocket эл. кітабы - Mobipocket 전자책 - Mobipocket e-grāmata - Mobipocket e-book - E-book Mobipocket - E-book Mobipocket - электронная книга Mobipocket - e-knjiga Mobipocket - електронна книга Mobipocket - Mobipocket 电子书 - Mobipocket e-book - - - - - - - - - - - - - - Adobe FrameMaker MIF document - مستند أدوبي الصانع للإطارات MIF - Dakument Adobe FrameMaker MIF - Документ — Adobe FrameMaker MIF - document de FrameMaker MIF d'Adobe - Dokument Adobe FrameMaker MIF - Adobe FrameMaker MIF-dokument - Adobe-FrameMaker-MIF-Dokument - αρχείο MIF του Adobe FrameMaker - Adobe FrameMaker MIF document - MIF-dokumento de Adobe FrameMaker - documento MIF de Adobe FrameMaker - Adobe FrameMaker-en MIF dokumentua - Adobe FrameMaker MIF -asiakirja - Adobe FrameMaker MIF skjal - document MIF Adobe FrameMaker - cáipéis MIF Adobe FrameMaker - documento MIF de Adobe FrameMaker - מסמך MIF של Adobe FrameMaker - Adobe FrameMaker MIF dokument - Adobe FrameMaker MIF-dokumentum - Dokumen Adobe FrameMaker MIF - Documento MIF Adobe FrameMaker - Adobe FrameMaker MIF ドキュメント - Adobe FrameMaker-ის MIF დოკუმენტი - Adobe FrameMaker MIF құжаты - 어도비 프레임메이커 MIF 문서 - Adobe FrameMaker MIF dokumentas - Adobe FrameMaker MIF dokuments - Adobe FrameMaker MIF-dokument - Adobe FrameMaker MIF-document - Adobe FrameMaker MIF-dokument - Dokument MIF Adobe FrameMaker - Documento MIF do Adobe FrameMaker - Document Adobe FrameMaker MIF - документ Adobe FrameMaker MIF - Dokument Adobe FrameMaker MIF - Dokument Adobe FrameMaker MIF - Dokument MIF Adobe FrameMaker - Adobe FrameMaker MIF-dokument - документ Adobe FrameMaker MIF - Tài liệu Adobe FrameMaker MIF - Adobe FrameMaker MIF 文档 - Adobe FrameMaker MIF 文件 - - - - Mozilla bookmarks - علامات موزيلا - Zakładki Mozilla - Отметки — Mozilla - llista d'adreces d'interès de Mozilla - Záložky Mozilla - Mozillabogmærker - Mozilla-Lesezeichen - σελιδοδείκτες Mozilla - Mozilla bookmarks - Mozilla-legosignoj - marcadores de Mozilla - Mozillako laster-markak - Mozilla-kirjanmerkit - Mozilla bókamerki - marque-pages Mozilla - leabharmharcanna Mozilla - Marcadores de Mozilla - סמניה של Mozilla - Mozilla knjižne oznake - Mozilla-könyvjelzők - Bookmark Mozilla - Segnalibri Mozilla - Mozilla ブックマーク - Mozilla бетбелгілері - 모질라 책갈피 - Mozilla žymelės - Mozilla grāmatzīmes - Tandabuku Mozilla - Mozilla-bokmerker - Mozilla-bladwijzers - Mozilla-bokmerker - Zakładki Mozilla - marcadores do Mozilla - Marcadores do Mozilla - Semne de carte Mozilla - закладки Mozilla - Záložky Mozilla - Datoteka zaznamkov Mozilla - Libërshënues Mozilla - Mozilla обележивачи - Mozilla-bokmärken - закладки Mozilla - Liên kết đã lưu Mozilla - Mozilla 书签 - Mozilla 書籤 - - - - - - - - - DOS/Windows executable - تنفيذي DOS/Windows - Vykonvalny fajł DOS/Windows - Изпълним файл — DOS/Windows - executable de DOS/Windows - Spustitelný soubor pro DOS/Windows - DOS-/Windowskørbar - DOS/Windows-Programm - εκτελέσιμο DOS/Windows - DOS/Windows executable - DOS/Windows-plenumebla - ejecutable de DOS/Windows - DOS/Windows-eko exekutagarria - DOS/Windows-ohjelma - DOS/Windows inningarfør - exécutable DOS/Windows - comhad inrite DOS/Windows - executábel de DOS/Windows - קובץ בר־הרצה של DOS/חלונות - DOS/Windows izvršna datoteka - DOS/Windows futtatható - DOS/Windows dapat dieksekusi - Eseguibile DOS/Windows - DOS/Windows 実行ファイル - DOS/Windows გაშვებადი ფაილი - DOS/Windows орындалатын файлы - DOS/Windows 실행 파일 - DOS/Windows vykdomasis failas - DOS/Windows izpildāmais - Bolehlaksana DOS/Windows - Kjørbar fil for DOS/Windows - DOS/Windows-uitvoerbaar bestand - DOS/Windows køyrbar fil - Program DOS/Windows - executável DOS/Windows - Executável do DOS/Windows - Executabil DOS/Windows - исполняемый файл DOS/Windows - Spustiteľný súbor pre DOS/Windows - Izvedljiva datoteka DOS/Windows - I ekzekutueshëm DOS/Windows - ДОС/Виндоуз извршна датотека - Körbar DOS/Windows-fil - DOS/Windows çalıştırılabilir - виконуваний файл DOS/Windows - Tập tin có thực hiện được DOS/Windows - DOS/Windows 可执行文件 - DOS/Windows 可執行檔 - - - - - - - - Internet shortcut - اختصار الإنترنت - Sieciŭnaja spasyłka - Адрес в Интернет - drecera d'Internet - Odkaz do Internetu - Internetgenvej - Internet-Verweis - συντόμευση διαδικτύου - Internet shortcut - acceso directo a Internet - Interneteko lasterbidea - Internet-pikakuvake - Alnetssnarvegur - raccourci Internet - aicearra Idirlín - atallo de Internet - קיצור דרך של האינטרנט - Internetski prečac - Internetes indítóikon - Jalan pintas Internet - Scorciatoia Internet - インターネットショートカット - Интернет сілтемесі - 인터넷 바로 가기 - Interneto nuoroda - Interneta īsceļš - Internettsnarvei - internetkoppeling - Internett-snarveg - Skrót internetowy - Atalho da internet - Scurtătură Internet - Интернет-ссылка - Internetový odkaz - Internetna bližnjica - Shkurtim internet - Internetgenväg - інтернет-посилання - Lối tắt Internet - Internet 快捷方式 - 網際網路捷徑 - - - - - - - - - - WRI document - مستند WRI - Dakument WRI - Документ — WRI - document WRI - Dokument WRI - WRI-dokument - WRI-Dokument - έγγραφο WRI - WRI document - WRI-dokumento - documento WRI - WRI dokumentua - WRI-asiakirja - WRI skjal - document WRI - cáipéis WRI - documento WRI - מסמך WRI - WRI dokument - WRI dokumentum - Dokumen WRI - Documento WRI - WRI ドキュメント - WRI құжаты - WRI 문서 - WRI dokumentas - WRI dokuments - WRI-dokument - WRI-document - WRI-dokument - Dokument WRI - Documento WRI - Document WRI - документ WRI - Dokument WRI - Dokument WRI - Dokument WRI - WRI-dokument - WRI belgesi - документ WRI - Tài liệu WRI - WRI 文档 - WRI 文件 - - - - - MSX ROM - MSX ROM - MSX ROM - ROM — MSX - ROM de MSX - ROM pro MSX - ROM MSX - MSX-rom - MSX-ROM - εικόνα μνήμης ROM MSX - MSX ROM - MSX-NLM - ROM de MSX - MSX-ko ROMa - MSX-ROM - MSX ROM - ROM MSX - ROM MSX - ROM de MSX - MSX ROM - MSX ROM - MSX ROM - Memori baca-saja MSX - ROM MSX - MSX ROM - MSX-ის ROM - MSX ROM - MSX 롬 - MSX ROM - MSX ROM - ROM MSX - MSX-ROM - MSX-ROM - MSX-ROM - Plik ROM konsoli MSX - ROM MSX - ROM do MSX - ROM MSX - MSX ROM - ROM pre MSX - Bralni pomnilnik MSX - ROM MSX - MSX ром - MSX-rom - ППП MSX - ROM MSX - MSX ROM - MSX ROM - - - - - M4 macro - M4 macro - Makras M4 - Макроси — M4 - macro M4 - Makro M4 - M4-makro - M4-Makro - μακροεντολή m4 - M4 macro - macro M4 - M4 makroa - M4-makro - M4 fjølvi - macro M4 - macra M4 - macro M4 - מאקרו M4 - M4 makro - M4 makró - Makro M4 - Macro M4 - M4 マクロ - M4 макросы - M4 매크로 - M4 macro - M4 makross - M4-makro - M4-macro - M4-makro - Makro M4 - Macro M4 - Macro M4 - макрос M4 - Makro M4 - Makro datoteka M4 - Macro M4 - M4-makro - макрос M4 - Vĩ lệnh M4 - M4 宏 - M4 巨集 - - - - - - Nintendo64 ROM - Nintendo64 ROM - Nintendo64 ROM - ROM — Nintendo64 - ROM de Nintendo64 - ROM pro Nintendo64 - Nintendo64-rom - Nintendo64-ROM - εικόνα μνήμης ROM Nintendo64 - Nintendo64 ROM - Nintendo64-NLM - ROM de Nintendo64 - Nintendo64-ko ROMa - Nintendo64-ROM - Nintendo64 ROM - ROM Nintendo64 - ROM Nintendo64 - ROM de Nintendo64 - ROM של Nןמאקמגם64 - Nintendo64 ROM - Nintendo64 ROM - Memori baca-saja Nintendo64 - ROM Nintendo64 - Nintendo64 ROM - Nintendo64 ROM - 닌텐도 64 롬 - Nintendo64 ROM - Nintendo64 ROM - ROM Nintendo64 - Nintendo64-ROM - Nintendo64-ROM - Nintendo64-ROM - Plik ROM konsoli Nintendo64 - ROM Nintendo64 - ROM do Nintendo64 - ROM Nintendo64 - Nintendo64 ROM - ROM pre Nintendo64 - Bralni pomnilnik Nintendo64 - ROM Nintendo64 - Нинтендо64 РОМ - Nintendo64-rom - Nintendo64 ROM - ППП Nintendo64 - ROM Nintendo64 - Nintendo64 ROM - Nintendo64 ROM - - - - - Nautilus link - وصلة Nautilus - Nautilus körpüsü - Spasyłka Nautilus - Връзка — Nautilus - enllaç de Nautilus - Odkaz Nautilus - Cyswllt Nautilus - Nautilus-henvisning - Nautilus-Verknüpfung - σύνδεσμος Nautilus - Nautilus link - Nautilus-ligilo - enlace de Nautilus - Nautilus esteka - Nautilus-linkki - Nautilus leinkja - lien Nautilus - nasc Nautilus - ligazón de nautilus - קישור של Nautilus - Nautilus veza - Nautilus-link - Taut Nautilus - Collegamento Nautilus - Nautilus リンク - Nautilus сілтемесі - 노틸러스 바로 가기 - Nautilus nuoroda - Nautilus saite - Pautan Nautilus - Nautilus-lenke - Nautilus-verwijzing - Nautilus-lenke - Odnośnik Nautilus - atalho Nautilus - Link do Nautilus - Legătură Nautilus - ссылка Nautilus - Odkaz Nautilus - Datoteka povezave Nautilus - Lidhje Nautilus - Наутилус веза - Nautiluslänk - Nautilus bağlantısı - посилання Nautilus - Liên kết Nautilus - Nautilus 链接 - Nautilus 鏈結 - - - - - - - - - NES ROM - NES ROM - NES ROM - ROM — NES - ROM de NES - ROM pro NES - ROM NES - NES-rom - NES-ROM - εικόνα μνήμης ROM NES - NES ROM - NES-NLM - ROM de NES - NES-eko ROMa - NES-ROM - NES ROM - ROM NES - ROM NES - ROM de NES - ROM של NES - NES ROM - NES ROM - Memori baca-saja NES - ROM NES - ファミコン ROM - NES ROM - NES 롬 - NES ROM - NES ROM - ROM NES - NES ROM - Nintendo - NES-ROM - Plik ROM konsoli NES - ROM NES - ROM do NES - ROM NES - NES ROM - ROM pre NES - Bralni pomnilnik NES - ROM NES - NES ром - NES-rom - NES ROM - ППП NES - ROM NES - NES ROM - 任天堂 ROM - - - - - Unidata NetCDF document - مستند Unidata NetCDF - Dakument Unidata NetCDF - Документ — Unidata NetCDF - document Unidata NetCDF - Dokument Unidata NetCDF - Unidata NetCDF-dokument - Unidata-NetCDF-Dokument - έγγραφο Unidata NetCDF - Unidata NetCDF document - dokumento en NetCDF-formato de Unidata - documento de Unidata NetCDF - Unidata NetCDF dokumentua - Unidata NetCDF -asiakirja - Unidata NetCDF skjal - document Unidata NetCDF - cáipéis Unidata NetCDF - Documentno de Unixdata NetCDF - מסמך של Unidata NetCDF - Unidata NetCDF dokument - Unidata NetCDF-dokumentum - Dokumen Unidata NetCDF - Documento Unidata NetCDF - Unidata NetCDF ドキュメント - Unidata NetCDF құжаты - Unidata NetCDF 문서 - Unidata NetCDF dokumentas - Unidata NetCDF dokuments - Dokumen Unidata NetCDF - Unidata NetCDF-dokument - Unidata NetCDF-document - Unidata netCDF-dokument - Dokument Unidata NetCDF - documento Unidata NetCDF - Documento do Unidata NetCDF - Document Unidata NetCDF - документ Unidata NetCDF - Dokument Unidata NetCDF - Dokument Unidata NetCDF - Dokument Unidata NetCDF - Unidata NetCDF документ - Unidata NetCDF-dokument - Unidata NetCDF belgesi - документ Unidata NetCDF - Tài liệu NetCDF Unidata - Unidata NetCDF 文档 - Unidata NetCDF 文件 - NetCDF - Network Common Data Form - - - - - - NewzBin usenet index - Индекс — Usenet, NewzBin - índex d'Usenet NewzBin - Index NewzBin diskuzních skupin Usenet - NewzBin-brugernetindex - NewzBin-Usenet-Index - ευρετήριο usenet NewzBin - NewzBin usenet index - Índice NewzBin de usenet - index usenet - Índice de usenet NEwzBin - אינדקס שרתי חדשות NewzBin - NewzBin usenet index - Indeks usenet NewzBin - Indice Usenet NewzBiz - NewzBin Usenet インデックス - NewzBin usenet индексі - NewzBin 유즈넷 인덱스 - NewzBin usenet rādītājs - NewzBin usenet index - Indeks grup dyskusyjnych NewzBin - Índice de usenet NewzBin - индекс usenet NewzBin - Kazalo usenet NewzBin - покажчик usenet NewzBin - NewzBin usenet 索引 - NewzBin usenet 索引 - - - - - - - - object code - رمز الكائن - abjektny kod - Обектен код - codi objecte - Objektový kód - objektkode - Objekt-Code - μεταφρασμένος κώδικας - object code - celkodo - código objeto - objektu kodea - objektikoodi - code objet - cód réada - código obxecto - קוד אובייקט - kod objekta - tárgykód - kode object - Codice oggetto - オブジェクトコード - объектті коды - 개체 코드 - objektinis kodas - objekta kods - Kod objek - objektkode - objectcode - objektkode - Kod obiektowy - código de objecto - Código-objeto - cod sursă obiect - объектный код - Objektový kód - predmetna koda - Kod objekti - објектни ко̂д - objektkod - об'єктний код - mã đối tượng - 目标代码 - 目的碼 - - - - - - - - - - - - - - - - - Annodex exchange format - صيغة Annodex البديلة - Формат за обмяна — Annodex - format d'intercanvi Annodex - Výměnný formát Annodex - Udvekslingsformat for Annodex - Annodex-Wechselformat - μορφή ανταλλαγής Annodex - Annodex exchange format - formato de intercambio Annodex - Annodex trukatze-formatua - Annodex-siirtomuoto - Annodex umbýtingarsnið - format d'échange Annodex - formáid mhalairte Annodex - formato intercambiábel de Annodex - פורמט החלפת Annodex - Annodex oblik za razmjenu - Annodex csereformátum - Format pertukaran Annodex - Formato di scambio Annodex - Annodex 交換フォーマット - Annodex-ის გაცვლითი ფორმატი - Annodex алмасу пішімі - Annodex 교환 형식 - Annodex mainų formatas - Annodex apmaiņas formāts - Annodex-exchange - Format wymiany Annodex - Formato de troca Annodex - Format schimb Annodex - формат обмена Annodex - Formát pre výmenu Annodex - Izmenjalna datoteka Annodex - Annodex-utväxlingsformat - формат обміну даними Annodex - Định dạng trao đổi Annodex - Annodex 交换格式 - Annodex 交換格式 - - - - - - - - - - - - - Annodex Video - Annodex مرئي - Видео — Annodex - Annodex Video - Annodex Video - Annodexvideo - Annodex-Video - βίντεο Annodex - Annodex Video - Annodex-video - vídeo Annodex - Annodex bideoa - Annodex-video - Annodex video - vidéo Annodex - físeán Annodex - vídeo de Annodex - וידאו Annodex - Annodex Video - Annodex videó - Video Annodex - Video Annodex - Annodex 動画 - Annodex-ის ვიდეო - Annodex видеосы - Annodex 비디오 - Annodex vaizdo įrašas - Annodex video - Annodex Video - Plik wideo Annodex - Vídeo Annodex - Video Annodex - видео Annodex - Video Annodex - Video datoteka Annodex - Annodex-video - відеокліп Annodex - Ảnh động Annodex - Annodex 视频 - Annodex 視訊 - - - - - - - - - - - - - Annodex Audio - Annodex سمعي - Аудио — Annodex - Annodex Audio - Annodex Audio - Annodexlyd - Annodex-Audio - ήχος Annodex - Annodex Audio - Annodex-sondosiero - sonido Annodex - Annodex audioa - Annodex-ääni - Annodex ljóður - audio Annodex - fuaim Annodex - son de Annodex - שמע Annodex - Annodex Audio - Annodex hang - Audio Annodex - Audio Annodex - Annodex オーディオ - Annodex-ის აუდიო - Annodex аудиосы - Annodex 오디오 - Annodex garso įrašas - Annodex audio - Annodex Audio - Plik dźwiękowy Annodex - Áudio Annodex - Audio Annodex - аудио Annodex - Zvuk Annodex - Zvočna datoteka Annodex - Annodex-ljud - звук Annodex - Âm thanh Annodex - Annodex 音频 - Annodex 音訊 - - - - - - - - - - - - - Ogg multimedia file - ملف وسائط متعددة Ogg - Multymedyjny fajł Ogg - Мултимедия — Ogg - fitxer Ogg multimèdia - Soubor multimédií Ogg - Ogg multimedie-fil - Ogg-Multimediadatei - Αρχείο πολυμέσων Ogg - Ogg multimedia file - archivo multimedia Ogg - Ogg multimediako fitxategia - Ogg-multimediatiedosto - Ogg margmiðlafíla - fichier multimédia Ogg - comhad ilmheán Ogg - ficheiro multimedia Ogg - קובץ מולטימדיה Ogg - Ogg multimédiafájl - Berkas multimedia Ogg - File multimediale Ogg - Ogg マルチメディアファイル - Ogg-ის მულტიმედია ფაილი - Ogg мультимедиа файлы - Ogg 멀티미디어 파일 - Ogg multimedijos failas - Ogg multimediju datne - Ogg-multimediafil - Ogg-multimediabestand - Ogg multimediafil - Plik multimedialny Ogg - Arquivo multimídia Ogg - Fișier multimedia Ogg - мультимедийный файл Ogg - Súbor multimédií Ogg - Večpredstavnostna datoteka Ogg - File multimedial Ogg - Ogg-multimediafil - мультимедійний файл Ogg - Tập tin đa phương tiện Ogg - Ogg 多媒体文件 - Ogg 多媒體檔案 - - - - - - - - - Ogg Audio - Ogg سمعي - Aŭdyjo Ogg - Аудио — Ogg - àudio Ogg - Zvuk Ogg - Ogg-lyd - Ogg-Audio - ήχος Ogg - Ogg Audio - sonido Ogg - Ogg audioa - Ogg-ääni - Ogg ljóður - audio Ogg - fuaim Ogg - son Ogg - שמע Ogg - Ogg hang - Audio Ogg - Audio Ogg - Ogg オーディオ - Ogg-ის აუდიო - Ogg аудиосы - Ogg 오디오 - Ogg garso įrašas - Ogg audio - Ogg lyd - Ogg-audio - Ogg-lyd - Plik dźwiękowy Ogg - Áudio Ogg - Audio Ogg - аудио Ogg - Zvuk Ogg - Zvočna datoteka Ogg - Audio Ogg - Ogg-ljud - звук ogg - Âm thanh Ogg - Ogg 音频 - Ogg 音訊 - - - - - - - - - - Ogg Video - Ogg مرئي - Videa Ogg - Видео — Ogg - vídeo Ogg - Video Ogg - Ogg-video - Ogg-Video - βίντεο Ogg - Ogg Video - vídeo Ogg - Ogg bideoa - Ogg-video - Ogg Video - vidéo Ogg - físeán Ogg - vídeo Ogg - וידאו Ogg - Ogg videó - Video Ogg - Video Ogg - Ogg 動画 - Ogg ვიდეო - Ogg видеосы - Ogg 비디오 - Ogg vaizdo įrašas - Ogg video - Ogg video - Ogg-video - Ogg-video - Plik wideo Ogg - Vídeo Ogg - Video Ogg - видео Ogg - Video Ogg - Video datoteka Ogg - Video Ogg - Ogg-video - відеокліп ogg - Ảnh động Ogg - Ogg 视频 - Ogg 視訊 - - - - - - - - - - Ogg Vorbis audio - Ogg Vorbis سمعي - Ogg Vorbis audio faylı - Aŭdyjo Ogg Vorbis - Аудио — Ogg Vorbis - àudio Ogg Vorbis - Zvuk Ogg Vorbis - Sain Ogg Vorbis - Ogg Vorbis-lyd - Ogg-Vorbis-Audio - ήχος Ogg Vobris - Ogg Vorbis audio - Ogg-Vorbis-sondosiero - sonido Ogg Vorbis - Ogg Vorbis audioa - Ogg Vorbis -ääni - Ogg Vorbis ljóður - audio Ogg Vorbis - fuaim Ogg Vorbis - son Ogg Vorbis - שמע Ogg Vorbis - Ogg Vorbis hang - Audio Ogg Vorbis - Audio Ogg Vorbis - Ogg Vorbis オーディオ - Ogg Vorbis აუდიო - Ogg Vorbis аудиосы - Ogg Vorbis 오디오 - Ogg Vorbis garso įrašas - Ogg Vorbis audio - Audio Ogg Vorbis - Ogg Vorbis lyd - Ogg Vorbis-audio - Ogg Vorbis-lyd - Plik dźwiękowy Ogg Vorbis - áudio Ogg Vorbis - Áudio do Ogg Vorbis - Audio Ogg Vorbis - аудио Ogg Vorbis - Zvuk Ogg Vorbis - Zvočna datoteka Ogg Vorbis - Audio Ogg Vorbis - Ог-ворбис звучни запис - Ogg Vorbis-ljud - звук ogg Vorbis - Âm thanh Vorbis Ogg - Ogg Vorbis 音频 - Ogg Vorbis 音訊 - - - - - - - - - - - - - Ogg FLAC audio - Ogg FLAC سمعي - Aŭdyjo Ogg FLAC - Аудио — Ogg FLAC - àudio Ogg FLAC - Zvuk Ogg FLAC - Ogg FLAC-lyd - Ogg-FLAC-Audio - ήχος Ogg FLAC - Ogg FLAC audio - sonido Ogg FLAC - Ogg FLAC audioa - Ogg FLAC -ääni - Ogg FLAC ljóður - audio Ogg FLAC - fuaim Ogg FLAC - son Ogg FLAC - שמע Ogg FLAC - Ogg FLAC hang - Audio Ogg FLAC - Audio Ogg FLAC - Ogg FLAC オーディオ - Ogg FLAC აუდიო - Ogg FLAC аудиосы - Ogg FLAC 오디오 - Ogg FLAC garso įrašas - Ogg FLAC audio - Ogg FLAC-lyd - Ogg FLAC-audio - Ogg FLAC-lyd - Plik dźwiękowy Ogg FLAC - Áudio FLAC Ogg - Audio Ogg FLAC - аудио Ogg FLAC - Zvuk Ogg FLAC - Zvočna datoteka Ogg FLAC - Audio Ogg FLAC - Ogg FLAC-ljud - звук ogg FLAC - Âm thanh FLAC Ogg - Ogg FLAC 音频 - Ogg FLAC 音訊 - - - - - - - - - - - - - - - Ogg Speex audio - Ogg Speex سمعي - Aŭdyjo Ogg Speex - Аудио — Ogg Speex - àudio Ogg Speex - Zvuk Ogg Speex - Ogg Speex-lyd - Ogg-Speex-Audio - ήχος Ogg Speex - Ogg Speex audio - sonido Ogg Speex - Ogg Speex audioa - Ogg Speex -ääni - Ogg Speex ljóður - audio Ogg Speex - fuaim Ogg Speex - son Ogg Speex - שמע Ogg Speex - Ogg Speex hang - Audio Ogg Speex - Audio Ogg Speex - Ogg Speex オーディオ - Ogg Speex აუდიო - Ogg Speex аудиосы - Ogg Speex 오디오 - Ogg Speex garso įrašas - Ogg Speex audio - Ogg Speex lyd - Ogg Speex-audio - Ogg Speex-lyd - Plik dźwiękowy Ogg Speex - Áudio Speex Ogg - Audio Ogg Speex - аудио Ogg Speex - Zvuk Ogg Speex - Zvočna datoteka Ogg Speex - Audio Ogg Speex - Ogg Speex-ljud - звук ogg Speex - Âm thanh Speex Ogg - Ogg Speex 音频 - Ogg Speex 音訊 - - - - - - - - - - - Speex audio - Speex سمعي - Aŭdyjo Speex - Аудио — Speex - àudio Speex - Zvuk Speex - Speexlyd - Speex-Audio - ήχος Speex - Speex audio - sonido Speex - Speex audioa - Speex-ääni - Speex ljóður - audio Speex - fuaim Speex - son Speex - שמע של Speex - Speex audio - Speex hang - Audio Speex - Audio Speex - Speex オーディオ - Speex аудиосы - Speex 오디오 - Speex garso įrašas - Speex audio - Speex lyd - Speex-audio - Speex-lyd - Plik dźwiękowy Speex - Áudio Speex - Audio Speex - аудио Speex - Zvuk Speex - Zvočna datoteka Speex - Audio Speex - Speex-ljud - звук Speex - Âm thanh Speex - Speex 音频 - Speex 音訊 - - - - - - - Ogg Theora video - Ogg Theora مرئي - Videa Ogg Theora - Видео — Ogg Theora - vídeo Ogg Theora - Video Ogg Theora - Ogg Theora-video - Ogg-Theora-Video - βίντεο Ogg Theora - Ogg Theora video - vídeo Ogg Theora - Ogg Theora bideoa - Ogg Theora -video - Ogg Theora video - vidéo Ogg Theora - físeán Ogg Theora - vídeo Ogg Theora - שמע Ogg Theora - Ogg Theora videó - Video Ogg Theora - Video Ogg Theora - Ogg Theora 動画 - Ogg Theora ვიდეო - Ogg Theora видеосы - Ogg Theora 비디오 - Ogg Theora vaizdo įrašas - Ogg Theora video - Ogg Theora video - Ogg Theora-video - Ogg Theora-video - Plik wideo Ogg Theora - Vídeo do Ogg Theora - Video Ogg Theora - видео Ogg Theora - Video Ogg Theora - Video datoteka Ogg Theora - Video Ogg Theora - Ogg Theora-video - відеокліп ogg Theora - Ảnh động Theora Ogg - Ogg Theora 视频 - Ogg Theora 視訊 - - - - - - - - - - - OGM video - OGM مرئي - Videa OGM - Видео — OGM - vídeo OGM - Video OGM - OGM-video - OGM-Video - βίντεο OGM - OGM video - OGM-video - vídeo OGM - OGM bideoa - OGM-video - OGM video - vidéo OGM - físeán OGM - vídeo OGM - וידאו OGM - OGM video - OGM-videó - Video OGM - Video OGM - OGM 動画 - OGM ვიდეო - OGM видеосы - OGM 비디오 - OGM vaizdo įrašas - OGM video - OGM-film - OGM-video - OGM-video - Plik wideo OGM - Vídeo OGM - Video OGM - видео OGM - Video OGM - Video datoteka OGM - Video OGM - OGM-video - відеокліп OGM - Ảnh động OGM - OGM 视频 - OGM 視訊 - - - - - - - - - - - - OLE2 compound document storage - تخزين مجمع مستند OLE2 - Schovišča dla kampanentaŭ dakumentu OLE2 - Съставен документ-хранилище — OLE2 - emmagatzematge de documents composats OLE2 - Úložiště složeného dokumentu OLE2 - OLE2-sammensat dokumentlager - OLE2-Verbunddokumentenspeicher - αρχείο συμπαγούς αποθήκευσης εγγράφων OLE2 - OLE2 compound document storage - OLE2-deponejo de parentezaj dokumentoj - almacenamiento de documentos compuestos OLE2 - OLE2 konposatutako dokumentu-bilduma - OLE2-yhdisteasiakirjatallenne - OLE2 samansett skjalagoymsla - document de stockage composé OLE2 - stóras cháipéisí comhshuite OLE2 - almacenamento de documento composto OLE2 - אחסון מסמך משותף OLE2 - OLE2 összetett dokumentumtároló - penyimpan dokumen kompon OLE2 - Memorizzazione documento composto OLE2 - OLE2 複合ドキュメントストレージ - OLE2 құрама құжаттар қоймасы - OLE2 복합 문서 - OLE2 sudėtinių dokumentų laikmena - OLE2 savienoto dokumentu glabātuve - Storan dokumen halaman OLE2 - OLE-lager for sammensatte dokumenter - OLE2-samengestelde documentopslag - OLE2 lager for samansett dokument - Magazyn dokumentu złożonego OLE2 - armazenamento de documento composto OLE2 - Armazenamento de documento composto OLE2 - Document de stocare compus OLE2 - хранилище составных документов OLE2 - Úložisko zloženého dokumentu OLE2 - Združeni dokument OLE2 - Arkiv dokumenti i përbërë OLE2 - ОЛЕ2 сједињени документ - Sammansatt OLE2-dokumentlager - сховище складних документів OLE2 - Kho lưu tài liệu ghép OLE2 - OLE2 组合文档存储 - OLE2 複合文件儲存 - - - - - - - - Microsoft Publisher document - - - - - Windows Installer package - حزمة مثبّت ويندوز - Pakunak Windows Installer - Пакет — инсталация за Windows - paquet de Windows Installer - Balíček Windows Installer - Windows Installer-pakke - Windows Installationspaket - πακέτο Windows Installer - Windows Installer package - paquete de instalación de Windows - Windows-eko pakete instalatzailea - Windows-asennuspaketti - Windows innleggingarpakki - paquet d'installation Windows - pacáiste Windows Installer - paquete de instalación de Windows - חבילה של Windows Installer - Windows Installer paket - Windows Installer csomag - Paket Windows Installer - Pacchetto Windows Installer - Windodws インストーラパッケージ - Windows Installer дестесі - Windows 설치 패키지 - Windows Installer paketas - Windows Installer pakotne - Windows-installatiepakket - Windows Installer-pakke - Pakiet instalatora Windows - Pacote do instalador do Windows - Pachet instalator Windows - пакет Windows Installer - Balík Windows Installer - Datoteka paketa Windows namestilnika - Paketë Windows Installer - Windows Installer-paket - Windows Installer paketi - пакунок Windows Installer - Gói cài đặt Windows - Windows 程序安装包 - Windows Installer 套件 - - - - - GNU Oleo spreadsheet - جدول جنو Oleo - Raźlikovy arkuš GNU Oleo - Таблица — GNU Oleo - full de càlcul de GNU Oleo - Sešit GNU Oleo - GNU Oleo-regneark - GNU-Oleo-Tabelle - λογιστικό φύλλο GNU Oleo - GNU Oleo spreadsheet - Kalkultabelo de GNU Oleo - hoja de cálculo de GNU Oleo - GNU Oleo kalkulu-orria - GNU Oleo -taulukko - GNU Oleo rokniark - feuille de calcul GNU Oleo - scarbhileog GNU Oleo - folla de cálculo de Oleo GNU - גליון נתונים של GNU Oleo - GNU Oleo proračunska tablica - GNU Oleo-munkafüzet - Lembar sebar GNU Oleo - Foglio di calcolo GNU Oleo - GNU Oleo スプレッドシート - GNU Oleo ცხრილი - GNU Oleo электрондық кестесі - GNU Oleo 스프레드시트 - GNU Oleo skaičialentė - GNU Oleo izklājlapa - Hamparan GNU Oleo - GNU Oleo regneark - GNU Oleo-rekenblad - GNU Oleo-rekneark - Arkusz GNU Oleo - folha de cálculo GNU Oleo - Planilha do GNU Oleo - Foaie de calcul GNU Oleo - электронная таблица GNU Oleo - Zošit GNU Oleo - Preglednica GNU Oleo - Fletë llogaritje GNU Oleo - ГНУ Oleo табеларни прорачун - GNU Oleo-kalkylblad - ел. таблиця GNU Oleo - Bảng tính Oleo của GNU - GNU Oleo 工作簿 - GNU Oleo 試算表 - - - - - - - - PAK archive - أرشيف PAK - Archiŭ PAK - Архив — PAK - arxiu PAK - Archiv PAK - PAK-arkiv - PAK-Archiv - συμπιεσμένο αρχείο PAK - PAK archive - PAK-arkivo - archivador PAK - PAK artxiboa - PAK-arkisto - PAK skjalasavn - archive PAK - cartlann PAK - arquivo PAK - ארכיון PAK - PAK-archívum - Arsip PAK - Archivio PAK - PAK アーカイブ - PAK არქივი - PAK архиві - PAK 압축 파일 - PAK archyvas - PAK arhīvs - PAK-arkiv - PAK-archief - PAK-arkiv - Archiwum PAK - Pacote PAK - Arhivă PAK - архив PAK - Archív PAK - Datoteka arhiva PAK - Arkiv PAK - PAK-arkiv - PAK arşivi - архів PAK - Kho nén PAK - AR 归档文件 - PAK 封存檔 - - - - - - - - Palm OS database - قاعدة بيانات Palm OS - Palm OS mə'lumat bazası - Baza źviestak Palm OS - База от данни — Palm OS - base de dades Palm OS - Databáze Palm OS - Cronfa Ddata Palm OS - Palm OS-database - Palm-OS-Datenbank - βάση δεδομένων Palm OS - Palm OS database - datumbazo de Palm OS - base de datos de Palm OS - Palm OS datu-basea - Palm OS -tietokanta - Palm OS dátustovnur - base de données Palm OS - bunachar sonraí Palm OS - base de datos de Palm OS - מסד נתונים של Palm OS - Palm OS-adatbázis - Basis data Palm OS - Database Palm OS - Palm OS データベース - Palm OS дерекқоры - Palm OS 데이터베이스 - Palm OS duomenų bazė - Palm OS datubāze - Pangkalandata PalmOS - Palm OS-database - Palm OS-gegevensbank - Palm OS-database - Baza danych Palm OS - base de dados do Palm OS - Banco de dados do Palm OS - Bază de date Palm OS - база данных Palm OS - Databáza Palm OS - Podatkovna zbirka Palm OS - Bankë me të dhëna Palm OS - Palm OS база података - Palm OS-databas - Palm OS veritabanı - база даних Palm OS - Cơ sở dữ liệu PalmOS - Palm OS 数据库 - Palm OS 資料庫 - - - - - - - - Parchive archive - أرشيف Parchive - Archiŭ Parchive - Архив — parchive - arxiu Parchive - Archiv Parchive - Parchive-arkiv - Parchive-Archiv - συμπιεσμένο αρχείο Parchive - Parchive archive - archivador Parchive - Parchive artxiboa - Parchive-arkisto - Parchive skjalasavn - archive Parchive - cartlann Parchive - arquivo Parchive - ארכיון של Parchive - Parchive archívum - Arsip Parchive - Archivio Parchive - Parchive アーカイブ - Parchive архиві - Parchive 압축 파일 - Parchive archyvas - Parchive arhīvs - Parchive-arkiv - Parchive-archief - Parchive-arkiv - Archiwum parchive - Pacote Parchive - Arhivă Parchive - архив Parchive - Archív Parchive - Datoteka arhiva Parchive - Arkiv Parchive - Parchive-arkiv - Parchive arşivi - архів Parchive - Kho nén Parchive - Parchive 归档文件 - Parchive 封存檔 - Parchive - Parity Volume Set Archive - - - - - - - - - PEF executable - PEF تنفيذي - Vykonvalny fajł PEF - Изпълним файл — PEF - executable PEF - Spustitelný soubor PEF - PEF-kørbar - PEF-Programm - εκτελέσιμο PEF - PEF executable - PEF-plenumebla - ejecutable PEF - PEF exekutagarria - PEF-ohjelma - PEF inningarfør - exécutable PEF - comhad inrite PEF - Executábel PEF - קובץ הרצה PEF - PEF futtatható - PEF dapat dieksekusi - Eseguibile PEF - PEF 実行ファイル - PEF орындалатын файлы - PEF 실행 파일 - PEF vykdomasis failas - PEF izpildāmais - Bolehlaksana PEF - PEF-kjørbar - PEF-uitvoerbaar bestand - Køyrbar PEF-fil - Program PEF - executável PEF - Executável PEF - Executabil PEF - исполняемый файл PEF - Spustiteľný súbor PEF - Izvedljiva datoteka PEF - E ekzekutueshme PEF - PEF извршна - Körbar PEF-fil - PEF çalıştırılabilir - виконуваний файл PEF - Tập tin thực hiện được PEF - PEF 可执行文件 - PEF 可執行檔 - - - - - - - Perl script - سكربت بيرل - Skrypt Perl - Скрипт — Perl - script Perl - Skript v Perlu - Sgript Perl - Perlprogram - Perl-Skript - πρόγραμμα εντολών Perl - Perl script - Perl-skripto - script en Perl - Perl script-a - Perl-komentotiedosto - Perl boðrøð - script Perl - script Perl - Script de Perl - תסריט מעטפת של Perl - Perl-parancsfájl - Skrip Perl - Script Perl - Perl スクリプト - Perl сценарийі - 펄 스크립트 - Perl scenarijus - Perl skripts - Skrip Perl - Perl skript - Perl-script - Perl-skript - Skrypt Perl - 'script' Perl - Script Perl - Script Perl - сценарий Perl - Skript jazyka Perl - Skriptna datoteka Perl - Script Perl - Перл скрипта - Perlskript - Perl betiği - скрипт на Perl - Văn lệnh Perl - Perl 脚本 - Perl 指令稿 - - - - - - - - - - - - - - - - - - - - - - - - - - - - PHP script - سكربت PHP - PHP skripti - Skrypt PHP - Скрипт — PHP - script PHP - Skript PHP - Sgript PHP - PHP-program - PHP-Skript - πρόγραμμα εντολών PHP - PHP script - PHP-skripto - script en PHP - PHP script-a - PHP-komentotiedosto - PHP boðrøð - script PHP - script PHP - Script de PHP - תסריט מעטפת של PHP - PHP-parancsfájl - Skrip PHP - Script PHP - PHP スクリプト - PHP сценарийі - PHP 스크립트 - PHP scenarijus - PHP skripts - Skrip PHP - PHP-skript - PHP-script - PHP-skript - Skrypt PHP - 'script' PHP - Script PHP - Script PHP - сценарий PHP - Skript PHP - Skriptna datoteka PHP - Script PHP - PHP скрипта - PHP-skript - PHP betiği - скрипт PHP - Văn lệnh PHP - PHP 脚本 - PHP 指令稿 - - - - - - - - - - - - - PKCS#7 certificate bundle - رزمة الشهادة PKCS#7 - Сбор със сертификати — PKCS#7 - conjunt de certificats PKCS#7 - Svazek certifikátů PKCS#7 - PKCS#7-certifikatbundt - PKCS#7-Zertifikatspaket - πακέτο ψηφιακών πιστοποιητικών PKCS#7 - PKCS#7 certificate bundle - lote de certificados PCKS#7 - PKCS#7 zertifikazio sorta - PKCS#7-varmennenippu - PKCS#7 váttanar bundi - lot de certificats PKCS#7 - cuach theastas PKCS#7 - paquete de certificado PKCS#7 - בקשה מוסמכת PKCS#7 - PKCS#7-tanúsítványcsomag - Bundel sertifikat PKCS#7 - Bundle certificato PKCS#7 - PKCS#7 証明書 - PKCS#7 сертификаттар дестесі - PKCS#7 인증서 묶음 - PKCS#7 liudijimų ryšulys - PKCS#7 sertifikātu saišķis - PKCS#7-certificaatbundel - Pakiet certyfikatu PKCS#7 - Pacote de certificados PKCS#7 - Pachet certificat PKCS#7 - пакет сертификатов PKCS#7 - Zväzok certifikátov PKCS#7 - Datoteka potrdila PKCS#7 - PKCS#7-certifikatsamling - комплект сертифікатів PKCS#7 - Bó chứng nhận PKCS#7 - PKCS#7 证书束 - PKCS#7 憑證綁包 - PKCS - Public-Key Cryptography Standards - - - - - PKCS#12 certificate bundle - رزمة الشهادة PKCS#12 - Viazka sertyfikataŭ PKCS#12 - Сбор със сертификати — PKCS#12 - conjunt de certificats PKCS#12 - Svazek certifikátů PKCS#12 - PKCS#12-certifikatbundt - PKCS#12-Zertifikatspaket - πακέτο ψηφιακών πιστοποιητικών PKCS#12 - PKCS#12 certificate bundle - ligaĵo de PKCS#12-atestiloj - lote de certificados PCKS#12 - PKCS#12 zertifikazio sorta - PKCS#12-varmennenippu - PKCS#12 váttanar bundi - lot de certificats PKCS#12 - cuach theastas PKCS#12 - paquete de certificado PKCS#12 - בקשה מוסמכת PKCS#12 - PKCS#12-tanúsítványcsomag - Bundel sertifikat PKCS#12 - Bundle certificato PKCS#12 - PKCS#12 証明書 - PKCS#12 сертификаттар дестесі - PKCS#12 인증서 묶음 - PKCS#12 liudijimų ryšulys - PKCS#12 sertifikātu saišķis - Sijil PKCS#12 - PKCS#12 sertifikathaug - PKCS#12-certificaatbundel - PKCS#12-sertifikatbunt - Pakiet certyfikatu PKCS#12 - conjunto de certificados PKCS#12 - Pacote de certificados PKCS#12 - Certificat împachetat PKCS#12 - пакет сертификатов PKCS#12 - Zväzok certifikátov PKCS#12 - Datoteka potrdila PKCS#12 - Bundle çertifikate PKCS#12 - PKCS#12 пакет сертификата - PKCS#12-certifikatsamling - комплект сертифікатів PKCS#12 - Bó chứng nhận PKCS#12 - PKCS#12 证书束 - PKCS#12 憑證檔 - PKCS - Public-Key Cryptography Standards - - - - - PlanPerfect spreadsheet - جدول PlanPerfect - Raźlikovy arkuš PlanPerfect - Таблица — PlanPerfect - full de càlcul de PlanPerfect - Sešit PlanPerfect - PlanPerfect-regneark - PlanPerfect-Tabelle - φύλλο εργασίας PlanPerfect - PlanPerfect spreadsheet - hoja de cálculo de PlanPerfect - PlanPerfect kalkulu-orria - PlanPerfect-taulukko - PlanPerfect rokniark - feuille de calcul PlanPerfect - scarbhileog PlanPerfect - folla de cálculo de PlanPerfect - גליון נתונים של PlanPerfect - PlanPerfect táblázat - Lembar sebar PlanPerfect - Foglio di calcolo PlanPerfect - PlanPerfect スプレッドシート - PlanPerfect электрондық кестесі - PlanPerfect 스프레드시트 - PlanPerfect skaičialentė - PlanPerfect izklājlapa - PlanPerfect-regneark - PlanPerfect-rekenblad - PlanPerfect-rekneark - Arkusz PlanPerfect - Planilha do PlanPerfect - Foaie de calcul PlanPerfect - электронная таблица PlanPerfect - Zošit PlanPerfect - Preglednica PlanPerfect - Fletë llogaritjesh PlanPerfect - PlanPerfect-kalkylblad - ел. таблиця PlanPerfect - Bảng tính PlanPerfect - PlanPerfect 工作簿 - PlanPerfect 試算表 - - - - - Pocket Word document - مستند Pocket Word - Документ — Pocket Word - document Pocket Word - Dokument Pocket Word - Pocket Word-dokument - Pocket-Word-Dokument - έγγραφο Pocket Word - Pocket Word document - documento de Pocket Word - Pocket Word dokumentua - Pocket Word -asiakirja - Pocket Word skjal - document Pocket Word - cáipéis Pocket Word - documento de Pocket Word - מסמך של Pocket Word - Pocket Word dokumentum - Dokumen Pocket Word - Documento Pocket Word - Pocket Word ドキュメント - Pocket Word құжаты - Pocket Word 문서 - Pocket Word dokumentas - Pocket Word dokuments - Pocket Word-document - Dokument Pocket Word - Documento do Pocket Word - Document Pocket Word - документ Pocket Word - Dokument Pocket Word - Dokument Pocket Word - Pocket Word-dokument - Pocket Word belgesi - документ Pocket Word - Tài liệu Pocket Word - Pocket Word 文档 - Pocket Word 文件 - - - - - - - - profiler results - نتائج المحلل - profiler nəticələri - vyniki profilera - Резултати от анализатора - resultats del perfilador - Výsledky profiler - canlyniadau proffeilio - profileringsresultater - Profiler-Ergebnisse - αποτελέσματα μετρήσεων για την εκτέλεση προγράμματος - profiler results - resultoj de profililo - resultados del perfilador - profiler-aren emaitzak - profilointitulokset - résultats de profileur - torthaí próifíleora - resultados do perfilador - תוצאות מאבחן - profilírozó-eredmények - hasil profiler - Risultati profiler - プロファイラー結果 - прифильдеу нәтижелері - 프로파일러 결과 - profiliklio rezultatai - profilētāja rezultāti - Hasil pemprofil - profileingsresultat - profiler-resultaten - profileringsresultat - Wyniki profilowania - resultados do 'profiler' - Resultados do profiler - rezultate profiler - результаты профилирования - Výsledky profilera - rezultati profilirnika - Rezultate të profiluesit - резултати профилатора - profilerarresultat - результати профілювання - kết quả nét hiện trạng - profiler 结果 - 硬體資訊產生器成果 - - - - - - Pathetic Writer document - مستند Pathetic Writer - Dakument Pathetic Writer - Документ — Pathetic Writer - document de Pathetic Writer - Dokument Pathetic Writer - Pathetic Writer-dokument - Pathetic-Writer-Dokument - έγγραφο Pathetic Writer - Pathetic Writer document - dokumento de Pathetic Writer - documento de Pathetic Writer - Pathetic Writer dokumentua - Pathetic Writer -asiakirja - Pathetic Writer skjal - document Pathetic Writer - cáipéis Pathetic Writer - documento de Pathetic Writer - מסמך של Pathetic Writer - Pathetic Writer-dokumentum - Dokumen Pathetic Writer - Documento Pathetic Writer - Pathetic Writer ドキュメント - Pathetic Writer құжаты - Pathetic Writer 문서 - Pathetic Writer dokumentas - Pathetic Writer dokuments - Dokumen Pathetic Writer - Pathetic Writer-dokument - Pathetic Writer-document - Pathetic Writer-dokument - Dokument Pathetic Writer - documento do Pathetic Writer - Documento do Pathetic Writer - Document Pathetic Writer - документ Pathetic Writer - Dokument Pathetic Writer - Dokument Pathetic Writer - Dokument Pathetic Writer - Документ Патетичног писца - Pathetic Writer-dokument - Pathetic Writer belgesi - документ Pathetic Writer - Tài liệu Pathetic Writer - Pathetic Writer 文档 - Pathetic Writer 文件 - - - - - Python bytecode - Python bytecode - Python bayt kodu - Bajtavy kod Python - Байт код — Python - bytecode de Python - Bajtový kód Python - Côd beit Python - Pythonbytekode - Python-Bytecode - συμβολοκώδικας Python - Python bytecode - Python-bajtkodo - bytecode Python - Python byte-kodea - Python-tavukoodi - Python býtkota - bytecode Python - beartchód Python - bytecode de Python - Bytecode של Python - Python-bájtkód - Kode bita Python - Bytecode Python - Python バイトコード - Python байткоды - 파이썬 바이트코드 - Python baitinis kodas - Python bitkods - Kodbait Python - Python-bytekode - Python-bytecode - Python-bytekode - Kod bajtowy Python - código binário Python - Código compilado Python - Bytecode Python - байт-код Python - Bajtový kód Python - Datoteka bitne kode Python - Bytecode Python - Питонов бајт ко̂д - Python-bytekod - байт-код Python - Mã byte Python - Python 字节码 - Python 位元組碼 - - - - - - - - QtiPlot document - - - - - - - - - - Quattro Pro spreadsheet - جدول Quattro Pro - Raźlikovy arkuš Quattro Pro - Таблица — Quattro Pro - full de càlcul de Quattro Pro - Sešit Quattro Pro - Quattro Pro-regneark - Quattro-Pro-Tabelle - λογιστικό φύλλο Quattro Pro - Quattro Pro spreadsheet - sterntabelo de Quattro Pro - hoja de cálculo Quattro Pro - Quattro Pro kalkulu-orria - Quattro Pro -taulukko - Quattro Pro rokniark - feuille de calcul Quattro Pro - scarbhileog Quattro Pro - folla de cálculo Quattro Pro - גליון נתונים של Quattro Pro - Quattro Pro proračunska tablica - Quattro Pro-munkafüzet - Lembar sebar Quattro Pro - Foglio di calcolo Quattro Pro - Quattro Pro スプレッドシート - Quattro Pro электрондық кестесі - Quattro Pro 스프레드시트 - Quattro Pro skaičialentė - Quattro Pro izklājlapa - Hamparan Quatro Pro - Quattro Pro-regneark - Quattro Pro-rekenblad - Quattro Pro-rekneark - Arkusz Quattro Pro - folha de cálculo Quattro Pro - Planilha do Quattro Pro - Foaie de calcul Quattro Pro - электронная таблица Quattro Pro - Zošit Quattro Pro - Preglednica Quattro Pro - Fletë llogaritjesh Quattro Pro - Quattro Pro табеларни рачун - Quattro Pro-kalkylblad - ел. таблиця Quattro Pro - Bảng tính Quattro Pro - Quattro Pro 工作簿 - Quattro Pro 試算表 - - - - - - - QuickTime metalink playlist - قائمة تشغيل QuickTime metalink - śpis metaspasyłak na pieśni QuickTime - Списък за изпълнение — QuickTime - llista de reproducció de metaenllaços QuickTime - Seznam skladeb metalink QuickTime - QuickTime metalink-afspilningsliste - QuickTime-Metalink-Wiedergabeliste - λίστα αναπαραγωγής metalinks QuickTime - QuickTime metalink playlist - lista de reproducción de metaenlaces QuickTime - QuickTime meta-esteken erreprodukzio-zerrenda - QuickTime metalink -soittolista - QuickTime metaleinkju avspælingarlisti - liste de lecture metalink QuickTime - seinmliosta meiteanasc QuickTime - lista de reprodución de metaligazóns QuickTime - רשימת השמעה מקושרת של QuickTime - QuickTime metalink lejátszólista - Senarai berkas taut meta QuickTime - Scaletta metalink QuickTime - QuickTime メタリンク再生リスト - QuickTime метасілтемелер ойнау тізімі - 퀵타임 메타링크 재생 목록 - QuickTime metanuorodos grojaraštis - QuickTime metasaites repertuārs - QuickTime metalink-spilleliste - QuickTime metalink-afspeellijst - QuickTime metalink-speleliste - Lista odtwarzania metaodnośników QuickTime - Lista de reprodução metalink do QuickTime - Listă cu metalegături QuickTime - список воспроизведения мета-ссылок QuickTime - Zoznam skladieb metalink QuickTime - Seznam predvajanja QuickTime - Listë titujsh metalink QuickTime - QuickTime-metalänkspellista - список відтворення QuickTime metalink - Danh mục nhạc siêu liên kết Quicktime - QuickTime 元链接播放列表 - QuickTime metalink 播放清單 - - - - - - - - - - - - - - - Quicken document - مستند Quicken - Quicken sənədi - Dakument Quicken - Документ — Quicken - document de Quicken - Dokument Quicken - Dogfen Quicken - Quickendokument - Quicken-Dokument - έγγραφο Quicken - Quicken document - Quicken-dokumento - documento de Quicken - Quicken dokumentua - Quicken-asiakirja - Quicken skjal - document Quicken - cáipéis Quicken - documento de Quicken - מסמך של Quicken - Quicken dokument - Quicken-dokumentum - Dokumen Quicken - Documento Quicken - Quicken ドキュメント - Quicken құжаты - Quicken 문서 - Quicken dokumentas - Quicken dokuments - Dokumen Quicken - Quicken-dokument - Quicken-document - Quicken-dokument - Dokument Quicken - documento Quicken - Documento do Quicken - Document Quicken - документ Quicken - Dokument Quicken - Dokument Quicken - Dokument Quicken - Quicken документ - Quicken-dokument - документ Quicken - Tài liệu Quicken - Quicken 文档 - Quicken 文件 - - - - - RAR archive - أرشيف RAR - Archiŭ RAR - Архив — RAR - arxiu RAR - Archiv RAR - Archif RAR - RAR-arkiv - RAR-Archiv - αρχείο RAR - RAR archive - RAR-arkivo - archivador RAR - RAR artxiboa - RAR-arkisto - RAR skjalasavn - archive RAR - cartlann RAR - ficheiro RAR - ארכיון RAR - RAR arhiva - RAR-archívum - Arsip RAR - Archivio RAR - RAR アーカイブ - RAR архиві - RAR 압축 파일 - RAR archyvas - RAR arhīvs - Arkib RAR - RAR-arkiv - RAR-archief - RAR-arkiv - Archiwum RAR - arquivo RAR - Pacote RAR - Arhivă RAR - архив RAR - Archív RAR - Datoteka arhiva RAR - Arkiv RAR - РАР архива - RAR-arkiv - архів RAR - Kho nén RAR - RAR 归档文件 - RAR 封存檔 - RAR - Roshal ARchive - - - - - - - - - DAR archive - أرشيف DAR - Archiŭ DAR - Архив — DAR - arxiu DAR - Archiv DAR - DAR-arkiv - DAR-Archiv - συμπιεσμένο αρχείο DAR - DAR archive - DAR-arkivo - archivador DAR - DAR artxiboa - DAR-arkisto - DAR skjalasavn - archive DAR - cartlann DAR - arquivo DAR - ארכיון DAR - DAR arhiva - DAR archívum - Arsip DAR - Archivio DAR - DAR アーカイブ - DAR არქივი - DAR архиві - DAR 묶음 파일 - DAR archyvas - DAR arhīvs - DAR-arkiv - DAR-archief - DAR-arkiv - Archiwum DAR - Pacote DAR - Arhivă DAR - архив DAR - Archív DAR - Datoteka arhiva DAR - Arkiv DAR - DAR-arkiv - архів DAR - Kho nén DAR - DAR 归档文件 - DAR 封存檔 - - - - - - - - Alzip archive - أرشيف Alzip - Archiŭ Alzip - Архив — alzip - arxiu Alzip - Archiv Alzip - Alziparkiv - Alzip-Archiv - Alzip archive - Alzip-arkivo - archivador Alzip - Alzip artxiboa - Alzip-arkisto - Alsip skjalasavn - archive alzip - cartlann Alzip - arquivo Alzip - ארכיון Alzip - Alzip arhiva - Alzip archívum - Arsip Alzip - Archivio Alzip - Alzip アーカイブ - Alzip არქივი - Alzip архиві - 알집 압축 파일 - Alzip archyvas - Alzip arhīvs - Alzip-arkiv - Alzip-archief - Alzip-arkiv - Archiwum alzip - Pacote Alzip - Arhivă Alzip - архив ALZIP - Archív Alzip - Datoteka arhiva Alzip - Arkiv Alzip - Alzip-arkiv - Alzip arşivi - архів Alzip - Kho nén Alzip - Alzip 归档文件 - Alzip 封存檔 - - - - - - - - rejected patch - رقعة مرفوضة - niepryniaty patch - Отхвърлен файл с кръпка - pedaç rebutjat - Odmítnutá záplata - afvist tekstlap - Abgelehnter Patch - μπάλωμα που απορρίφθηκε - rejected patch - reĵeta flikaĵo - parche rechazado - baztertutako bide-izena - hylättyjen muutosten tiedosto - vrakað rætting - correctif rejeté - paiste diúltaithe - parche rexeitado - תלאי שנדחה - odbijena zakrpa - visszautasított folt - patch ditolak - Patch rifiutata - 拒否されたパッチ - алынбаған патч - 거부된 패치 파일 - atmestas lopas - noraidītais ceļš - Tampungan ditolak - avvist patchfil - verworpen patch - avvist programfiks - Odrzucona łata - ficheiro de patch rejeitado - Arquivo de patch rejeitado - petec respsins - отвергнутый патч - Odmietnutá záplata - zavrnjen popravek - Patch i kthyer mbrapsht - одбијена закрпа - avvisad programfix - відхилена латка - đắp vá bị từ chối - 拒绝的补丁 - 回絕的修補 - - - - - - - RPM package - حزمة RPM - Pakunak RPM - Пакет — RPM - paquet RPM - Balíček RPM - RPM-pakke - RPM-Paket - πακέτο RPM - RPM package - RPM-pakaĵo - paquete RPM - RPM paketea - RPM-paketti - RPM pakki - paquet RPM - pacáiste RPM - paquete RFM - חבילת RPM - RPM paket - RPM-csomag - Paket RPM - Pacchetto RPM - RPM パッケージ - RPM дестесі - RPM 패키지 - RPM paketas - RPM pakotne - Pakej RPM - RPM-pakke - RPM-pakket - RPM-pakke - Pakiet RPM - pacote RPM - Pacote RPM - Pachet RPM - пакет RPM - Balík RPM - Datoteka paketa RPM - Paketë RPM - RPM пакет - RPM-paket - пакунок RPM - Gói RPM - RPM 软件包 - RPM 套件 - - - - - - - - - Source RPM package - - - - - - - Ruby script - سكربت روبي - Skrypt Ruby - Скрипт — Ruby - script Ruby - Skript v Ruby - Rubyprogram - Ruby-Skript - πρόγραμμα εντολών Ruby - Ruby script - Ruby-skripto - script en Ruby - Ruby script-a - Ruby-komentotiedosto - Ruby boðrøð - script Ruby - script Ruby - Script de Ruby - תסריט Ruby - Ruby skripta - Ruby-parancsfájl - Skrip Ruby - Script Ruby - Ruby スクリプト - Ruby сценарийі - 루비 스크립트 - Ruby scenarijus - Ruby skripts - Skrip Ruby - Ruby-skript - Ruby-script - Ruby-skript - Skrypt Ruby - 'script' Ruby - Script Ruby - Script Ruby - сценарий Ruby - Skript Ruby - Skriptna datoteka Ruby - Script Ruby - Руби скрипта - Ruby-skript - Ruby betiği - скрипт Ruby - Văn lệnh Ruby - Ruby 脚本 - Ruby 指令稿 - - - - - - - - - - - Markaby script - سكربت Markaby - Skrypt Markaby - Скрипт — Markaby - script Markaby - Skript Markaby - Markabyprogram - Markaby-Skript - δέσμη εντολών Markaby - Markaby script - Markaby-skripto - script en Markaby - Markaby script-a - Markaby-komentotiedosto - Markaby boðrøð - script Markaby - script Markaby - Script de Markaby - תסריט Markby - Markaby skripta - Markaby parancsfájl - Skrip Markaby - Script Markaby - Markaby スクリプト - Markaby-ის სცენარი - Markaby сценарийі - Markaby 스크립트 - Markaby scenarijus - Markaby skripts - Markaby-skript - Markaby-script - Markaby-skript - Skrypt Markaby - Script Markaby - Script Markaby - сценарий Markaby - Skript Markaby - Skriptna datoteka Markaby - Script Markaby - Markaby-skript - Markaby betiği - скрипт Markaby - Văn lệnh Markaby - RMarkaby 脚本 - Markaby 指令稿 - - - - - - SC/Xspread spreadsheet - جدول SC/Xspread - Raźlikovy arkuš SC/Xspread - Таблица — SC/Xspread - full de càlcul de SC/Xspread - Sešit SC/Xspread - SC/Xspread-regneark - SX/Xspread-Tabelle - φύλλο εργασίας SC/Xspread - SC/Xspread spreadsheet - SC/Xspread-kalkultabelo - hoja de cálculo SC/Xspread - SC/Xspread kalkulu-orria - SC/Xspread-taulukko - SC/Xspread rokniark - feuille de calcul SC/Xspread - scarbhileog SC/Xspread - folla de cálculo SC/Xspread - גליון נתונית של SC/Xspread - SC/Xspread proračunska tablica - SC/Xspread táblázat - Lembar sebar SC/Xspread - Foglio di calcolo SC/Xspread - SC/Xspread スプレッドシート - SC/Xspread электрондық кестесі - SC/Xspread 스프레드시트 - SC/Xspread skaičialentė - SC/Xspread izklājlapa - SC/Xspread-regneark - SC/Xspread-rekenblad - SC/Xspread-rekneark - Arkusz SC/Xspread - Planilha do SC/Xspread - Foaie de calcul SC/Xspread - электронная таблица SC/Xspread - Zošit SC/Xspread - Preglednica SC/Xspread - Fletë llogaritjesh SC/Xspread - SC/Xspread-kalkylblad - ел. таблиця SC/Xspread - Bảng tính SC/Xspread - SC/Xspread 工作簿 - SC/Xspread 試算表 - - - - - - - shell archive - أرشيف شِل - qabıq arxivi - archiŭ abałonki - Архив на обвивката - arxiu d'intèrpret d'ordres - Archiv shellu - archif plisgyn - skalarkiv - Shell-Archiv - αρχείο φλοιού (SHAR) - shell archive - ŝel-arkivo - archivador shell - shell artxiboa - komentotulkkiarkisto - skel savn - archive shell - cartlann bhlaoisce - ficheiro shell - ארכיון מעטפת - arhiva ljuske - héjarchívum - arsip shell - Archivio shell - シェルアーカイブ - қоршам архиві - 셸 압축 파일 - shell archyvas - čaulas arhīvs - Arkib shell - skallarkiv - shell-archief - skal-arkiv - Archiwum powłoki - arquivo de consola - Pacote shell - arhivă shell - архив оболочки UNIX - Archív shellu - lupinski arhiv - Arkiv shell - Архива љуске (SHAR) - skalarkiv - архів оболонки - kho trình bao - shell 归档文件 - shell 封存檔 - - - - - libtool shared library - مكتبة libtool المشتركة - supolnaja biblijateka libtool - Споделена библиотека — libtool - biblioteca compartida libtool - Sdílená knihovna libtool - libtool delt bibliotek - Gemeinsame libtool-Bibliothek - κοινόχρηστη βιβλιοθήκη libtool - libtool shared library - biblioteca compartida de libtool - libtool partekatutako liburutegia - jaettu libtool-kirjasto - libtool felagssavn - bibliothèque partagée libtool - comhleabharlann libtool - biblioteca compartida de libtool - ספריה משותפת של libtool - libtool dijeljena biblioteka - libtool osztott programkönyvtár - pustaka bersama libtool - Libreria condivisa libtool - libtool 共有ライブラリ - libtool ортақ жинағы - libtool 공유 라이브러리 - libtool bendroji biblioteka - libtool koplietotā bibliotēka - libtool delt bibliotek - gedeelde libtool-bibliotheek - libtool delt bibliotek - Biblioteka współdzielona libtool - Biblioteca compartilhada libtool - bibliotecă partajată libtool - разделяемая библиотека libtool - Zdieľaná knižnica libtool - Souporabna knjižnica libtool - Librari e përbashkët libtool - delat libtool-bibliotek - спільна бібліотека libtool - thư viện dùng chung libtool - libtool 共享库 - libtool 共享函式庫 - - - - - - shared library - مكتبة مشتركة - bölüşülmüş kitabxana - supolnaja biblijateka - Споделена библиотека - biblioteca compartida - Sdílená knihovna - llyfrgell wedi ei rhannu - delt bibliotek - Gemeinsame Bibliothek - αρχείο κοινόχρηστης βιβλιοθήκης - shared library - dinamike bindebla biblioteko - biblioteca compartida - partekatutako liburutegia - jaettu kirjasto - felagssavn - bibliothèque partagée - comhleabharlann - biblioteca compartida - ספרייה משותפת - dijeljena biblioteka - osztott programkönyvtár - pustaka bersama - Libreria condivisa - 共有ライブラリ - бөлісетін библиотека - 공유 라이브러리 - bendroji biblioteka - koplietotā bibliotēka - Pustaka terkongsi - delt bibliotek - gedeelde bibliotheek - delt bibliotek - Biblioteka współdzielona - biblioteca partilhada - Biblioteca compartilhada - bibliotecă partajată - разделяемая библиотека - Zdieľaná knižnica - souporabljena knjižnica - Librari e përbashkët - дељена библиотека - delat bibliotek - спільна бібліотека - thư viện dùng chung - 共享库 - 共享函式庫 - - - - - - - - - - - - - - - - - - - - shell script - سكربت شِل - qabıq skripti - skrypt abałonki - Скрипт на обвивката - script d'intèrpret d'ordres - Skript shellu - sgript plisgyn - skalprogram - Shell-Skript - αρχείο εντολών φλοιού - shell script - ŝelskripto - script en shell - shell script-a - komentotulkin komentotiedosto - skel boðrøð - script shell - script bhlaoisce - script de shell - תסריט מעטפת - skripta ljuske - héj-parancsfájl - skrip shell - Script shell - シェルスクリプト - қоршам сценарийі - 셸 스크립트 - shell scenarijus - čaulas skripts - Skrip shell - skallskript - shellscript - skalskript - Skrypt powłoki - 'script' de consola - Script shell - script shell - сценарий оболочки UNIX - Skript shellu - lupinski skript - Script shell - скрипта љуске - skalskript - скрипт оболонки - văn lệnh trình bao - shell 脚本 - shell 指令稿 - - - - - - - - - - - - - - - - - - - - - Shockwave Flash file - ملف Shockwave Flash - Fajł Shockwave Flash - Файл — Shockwave Flash - fitxer Shockwave Flash - Soubor Shockwave Flash - Shockwave Flash-fil - Shockwave-Flash-Datei - αρχείο Shockwave Flash - Shockwave Flash file - dosiero de Shockwave Flash - archivo Shockwave Flash - Shockwave Flash fitxategia - Shockwave Flash -tiedosto - Shockwave Flash fíla - fichier Shockwave Flash - comhad Shockwave Flash - ficheiro sockwave Flash - קובץ של Shockwave Flash - Shockwave Flash datoteka - Shockwave Flash-fájl - Berkas Shockwave Flash - File Shockwave Flash - Shockwave Flash ファイル - Shockwave Flash файлы - Shockwave 플래시 파일 - Shockwave Flash failas - Shockwave Flash datne - Fail Shockwave Flash - Shockwave Flash-fil - Shockwave Flash-bestand - Shockwave Flash-fil - Plik Shockwave Flash - ficheiro Shockwave Flash - Arquivo Shockwave Flash - Fișier Shockwave Flash - файл Shockwave Flash - Súbor Shockwave Flash - Datoteka Shockwave Flash - File Flash Shockwave - Шоквејв Флеш датотека - Shockwave Flash-fil - файл Shockwave Flash - Tập tin Flash Shockwave - Shockwave Flash 文件 - Shockwave Flash 檔 - - - - - - - - - - - - - Shorten audio - Shorten سمعي - Aŭdyjo Shorten - Аудио — Shorten - àudio Shorten - Zvuk Shorten - Shortenlyd - Shorten-Audio - ήχος Shorten - Shorten audio - Shorten-sondosiero - sonido Shorten - Shorten audioa - Shorten-ääni - Shorten ljóður - audio Shorten - fuaim Shorten - son Shorten - שמע של Shorten - Shorten audio - Shorten hang - Audio Shorten - Audio Shorten - Shorten オーディオ - Shorten аудиосы - Shorten 오디오 - Shorten garso įrašas - Shorten audio - Shorten lyd - Shorten-audio - Shorten-lyd - Plik dźwiękowy Shorten - Áudio Shorten - Audio Shorten - аудио Shorten - Zvuk Shorten - Zvočna datoteka Shorten - Audio Shorten - Shorten-ljud - звук Shorten - Âm thanh Shorten - Shorten 音频 - Shorten 音訊 - - - - - - - - Siag spreadsheet - جدول Siag - Raźlikovy arkuš Siag - Таблица — Siag - full de càlcul Siag - Sešit Siag - Siagregneark - Siag-Tabelle - λογιστικό φύλλο Siag - Siag spreadsheet - Siag-kalkultabelo - hoja de cálculo de Siag - Siag kalkulu-orria - Siag-taulukko - Siag rokniark - feuille de calcul Siag - scarbhileog Siag - folla de cálculo de Siag - גליון נתונים של Siag - Siag proračunska tablica - Siag-munkafüzet - Lembar sebar Siag - Foglio di calcolo Siag - Siag スプレッドシート - Siag электрондық кестесі - Siag 스프레드시트 - Siag skaičialentė - Siag izklājlapa - Hamparan Siag - Siag-regneark - Siag-rekenblad - Siag-rekneark - Arkusz Siag - folha de cálculo Siag - Planilha do Siag - Foaie de calcul Siag - электронная таблица Siag - Zošit Siag - Preglednica Siag - Fletë llogaritjesh Siag - Siag табеларни прорачун - Siag-kalkylblad - ел. таблиця Siag - Bảng tính Slag - Siag 工作簿 - Siag 試算表 - - - - - Skencil document - مستند Skencil - Dakument Skencil - Документ — Skencil - document Skencil - Dokument Skencil - Skencildokument - Skencil-Dokument - έγγραφο Skencil - Skencil document - Skencil-dokumento - documento Skencil - Skencil dokumentua - Skencil-asiakirja - Skencil skjal - document Skencil - cáipéis Skencil - documento Skencil - מסמך Skencil - Skencil dokument - Skencil-dokumentum - Dokumen Skencil - Documento Skencil - Skencil ドキュメント - Skencil құжаты - Skencil 문서 - Skencil dokumentas - Skencil dokuments - Skencil-document - Skencil-dokument - Dokument Skencil - Documento do Skencil - Document Skencil - документ Skencil - Dokument Skencil - Dokument Skencil - Dokument Skencil - Skencil-dokument - Skencil belgesi - документ Skencil - Tài liệu Skencil - Skencil 文档 - Skencil 文件 - - - - - - - - Stampede package - حزمة Stampede - Stampede paketi - Pakunak Stampede - Пакет — Stampede - paquet Stampede - Balíček Stampede - Pecyn Stampede - Stampedepakke - Stampede-Paket - πακέτο Stampede - Stampede package - Stampede-pakaĵo - paquete Stampede - Stampede paketea - Stampede-paketti - Stampede pakki - paquet Stampede - pacáiste Stampede - paquete Stampede - חבילה של Stampede - Stampede paket - Stampede-csomag - Paket Stampede - Pacchetto Stampede - Stampede パッケージ - Stampede дестесі - Stampete 패키지 - Stampede paketas - Stampede pakotne - Pakej Stampede - Stampede-pakke - Stampede-pakket - Stampede-pakke - Pakiet Stampede - pacote Stampede - Pacote Stampede - Pachet Stampede - пакет Stampede - Balíček Stampede - Datoteka paketa Stampede - Paketë Stampede - Stampede пакет - Stampede-paket - Stampede paketi - пакунок Stampede - Gói Stampede - Stampede 软件包 - Stampede 套件 - - - - Sega Master System/Game Gear ROM - ROM الخاص بدولاب لعبة/نظام سيجا ماستر - Sega Master System/Game Gear ROM - ROM — Sega Master System/Game Gear - ROM de Sega Master System/Game Gear - ROM pro Sega Master System/Game Gear - Sega Master System/Game Gear-rom - Sega-Master-System/Game-Gear-ROM - Εικόνα μνήμης ROM Sega Master System/Game Gear - Sega Master System/Game Gear ROM - ROM de Sega Master System/Game Gear - Sega Master System/Game Gear-eko ROMa - Sega Master System/Game Gear -ROM - Sega Master System/Game Gear ROM - ROM Sega Master System/Game Gear - ROM Sega Master System/Game Gear - ROM de Sega Master System/Game Gear - Sega Master System/Game Gear של ROM - Sega Master System/Game Gear ROM - Sega Master System/Game Gear ROM - Memori baca-saja Sega Master System/Game Gear - ROM Sega Master System/Game Gear - セガ マスターシステム/ゲームギア ROM - Sega Master System/Game Gear ROM - 세가 마스터 시스템/게임 기어 롬 - Sega Master System/Game Gear ROM - Sega Master System/Game Gear ROM - Sega Master System/Game Gear-ROM - Sega Master System/Game Gear-ROM - Sega Master System/Game Gear-ROM - Plik ROM konsoli SMS/Game Gear - ROM do Sega Master System/Game Gear - ROM Sega Master System/Game Gear - Sega Master System/Game Gear ROM - ROM pre Sega Master System/Game Gear - Bralni pomnilnik Sega Master System/Game Gear - ROM Sega Master System/Game Gear - Sega Master System/Game Gear-rom - ППП Sega Master System/Game Gear - ROM Sega Master System/Game Gear - Sega Master System/Game Gear ROM - Sega Master System/Game Gear ROM - - - - - - - Super NES ROM - Super NES ROM - Super Nintendo ROM - ROM — Super NES - ROM de Super NES - ROM pro Super Nintendo - Super NES-rom - Super-NES-ROM - εικόνα μνήημης ROM Super NES - Super NES ROM - ROM de Super NES - Super Nintendo-ko ROMa - Super Nintendo -ROM - Super NES ROM - ROM Super Nintendo - ROM Super NES - ROM de Super NES - ROM של Super NES - Super NES ROM - Super NES ROM - Memori baca-saja Super Nintendo - ROM Super Nintendo - スーパーファミコン ROM - Super NES ROM - 수퍼 NES 롬 - Super NES ROM - Super NES ROM - Super Nintendo ROM - Super Nintendo - Super NES-ROM - Plik ROM konsoli SNES - ROM do Super Nintendo - ROM Super Nintendo - Super NES ROM - ROM pre Super Nintendo - Bralni pomnilnik Super NES - ROM Super NES - Super NES-rom - ППП Super NES - ROM Super Nintendo - Super NES ROM - 超級任天堂 ROM - - - - - - - StuffIt archive - أرشيف StuffIt - Archiŭ StuffIt - Архив — StuffIt - arxiu StuffIt - Archiv StuffIt - StuffIt-arkiv - StuffIt-Archiv - συμπιεσμένο αρχείο StuffIt - StuffIt archive - StuffIt-arkivo - archivador StuffIt - StuffIt artxiboa - StuffIt-arkisto - StuffIt skjalasavn - archive StuffIt - cartlann StuffIt - arquivo StuffIt - ארכיון של Sאוככןא - StuffIt arhiva - StuffIt-archívum - Arsip StuffIt - Archivio StuffIt - StuffIt アーカイブ - StuffIt архиві - StuffIt 압축 파일 - StuffIt archyvas - StuffIt arhīvs - StuffIt arkiv - StuffIt-archief - StuffIt-arkiv - Archiwum StuffIt - Pacote StuffIt - Arhivă StuffIt - архив StuffIt - Archív StuffIt - Datoteka arhiva StuffIt - Arkiv StuffIt - StuffIt архива - StuffIt-arkiv - StuffIt arşivi - архів StuffIt - Kho nén Stuffit - Macintosh StuffIt 归档文件 - StuffIt 封存檔 - - - - - - - - - - - SubRip subtitles - ترجمات SubRip - Subtytry SubRip - Субтитри — SubRip - subtítols SubRip - Titulky SubRip - SubRip-undertekster - SubRip-Untertitel - υπότιτλοι SubRip - SubRip subtitles - SubRip-subtekstoj - subtítulos SubRip - SubRip azpitituluak - SubRip-tekstitykset - SubRip undirtekstir - sous-titres SubRip - fotheidil SubRip - subtítulos SubRip - כתוביות של SubRip - SubRip titlovi - SubRip feliratok - Subjudul SubRip - Sottotitoli SubRip - SubRip 字幕 - SubRip субтитрлары - SubRip 자막 파일 - SubRip subtitrai - SubRip subtitri - SubRip undertekst - SubRip-ondertitels - SubRip-teksting - Napisy SubRip - Legendas SubRip - Subtitrare SubRip - субтитры SubRip - Titulky SubRip - Datoteka podnapisov SubRip - Nëntituj SubRip - SubRip-undertexter - SubRip altyazıları - субтитри SubRip - Phụ đề SubRip - SubRip 字幕 - SubRip 字幕 - - - - - - - - - - - - WebVTT subtitles - Субтитри — WebVTT - subtítols WebVTT - Titulky WebVTT - WebVTT-undertekster - WebVTT-Untertitel - υπότιτλοι WebVTT - WebVTT subtitles - Subtítulos WebVTT - WebVTT-tekstitykset - sous-titres WebVTT - subtítulos WebVTT - כתוביות WebVTT - WebVTT titlovi - WebVTT feliratok - Subtitel WebVTT - Sottotitoli WebVTT - WebVTT サブタイトル - WebVTT ქვეტიტრები - WebVTT субтитрлары - WebVTT 자막 - WebVTT subtitri - WebVTT ondertitels - Napisy WebVTT - Legendas WebVTT - субтитры WebVTT - Podnapisi WebVTT - WebVTT-undertexter - субтитри WebVTT - WebVTT 字幕 - WebVTT 字幕 - VTT - Video Text Tracks - - - - - - - - - SAMI subtitles - ترجمات SAMI - Subtytry SAMI - Субтитри — SAMI - subtítols SAMI - Titulky SAMI - SAMI-undertekster - SAMI-Untertitel - υπότιτλοι SAMI - SAMI subtitles - SAMI-subtekstoj - subtítulos SAMI - SAMI azpitituluak - SAMI-tekstitykset - SAMI undirtekstir - sous-titres SAMI - fotheidil SAMI - subtítulos SAMI - כתוביות SAMI - SAMI titlovi - SAMI feliratok - Subjudul SAMI - Sottotitoli SAMI - SAMI 字幕 - SAMI субтитрлары - SAMI 자막 파일 - SAMI subtitrai - SAMI subtitri - SAMI undertekst - SAMI-ondertitels - SAMI teksting - Napisy SAMI - Legendas SAMI - Subtitrări SAMI - субтитры SAMI - Titulky SAMI - Datoteka podnapisov SAMI - Nëntituj SAMI - SAMI-undertexter - SAMI altyazıları - субтитри SAMI - Phụ đề SAMI - SAMI 字幕 - SAMI 字幕 - SAMI - Synchronized Accessible Media Interchange - - - - - - - - - - MicroDVD subtitles - ترجمات MicroDVD - Subtytry MicroDVD - Субтитри — MicroDVD - subtítols MicroDVD - Titulky MicroDVD - MicroDVD-undertekster - MicroDVD-Untertitel - υπότιτλοι MicroDVD - MicroDVD subtitles - MicroDVD-subtekstoj - subtítulos MicroDVD - MicroDVD azpitituluak - MicroDVD-tekstitykset - MicroDVD undirtekstir - sous-titres MicroDVD - fotheidil MicroDVD - subtítulos de MicroDVD - כתוביות של MicroDVD - MicroDVD titlovi - MicroDVD feliratok - Subjudul MicroDVD - Sottotitoli MicroDVD - MicroDVD 字幕 - MicroDVD-ის ქვეტიტრები - MicroDVD субтитрлары - MicroDVD 자막 파일 - MicroDVD subtitrai - MicroDVD subtitri - MicroDVD undertekst - MicroDVD-ondertitels - MicroDVD-teksting - Napisy MicroDVD - Legendas MicroDVD - Subtitrări MicroDVD - субтитры MicroDVD - Titulky MicroDVD - Datoteka podnapisov MicroDVD - Nëntituj MicroDVD - MicroDVD-undertexter - MicroDVD altyazısı - субтитри MicroDVD - Phụ đề MicroDVD - MicroDVD 字幕 - MicroDVD 字幕 - - - - - - - - - - MPSub subtitles - ترجمات MPSub - Subtytry MPSub - Субтитри — MPSub - subtítols MPSub - Titulky MPSub - MPSub-undertekster - MPSub-Untertitel - υπότιτλοι MPSub - MPSub subtitles - MPSub-subtekstoj - subtítulos MPSub - MPSub azpitituluak - MPSub-tekstitykset - MPSub undirtekstir - sous-titres MPSub - fotheidil MPSub - subtítulos MPSub - כתוביות MPSub - MPSub titlovi - MPSub feliratok - Subjudul MPSub - Sottotitoli MPSub - MPSub サブタイトル - MPSub ქვეტიტრები - MPSub субтитрлары - MPSub 자막 파일 - MPSub subtitrai - MPSub subtitri - MPSub undertekst - MPSub-ondertitels - MPSub-undertekstar - Napisy MPSub - Legendas MPSub - Subtitrări MPSub - субтитры MPSub - Titulky MPSub - Datoteka podnapisov MPSub - Nëntituj MPSub - MPSub-undertexter - субтитри MPSub - Phụ đề MPSub - MPSub 字幕 - MPSub 字幕 - MPSub - MPlayer Subtitle - - - - - - - - SSA subtitles - ترجمات SSA - Subtytry SSA - Субтитри — SSA - subtítols SSA - Titulky SSA - SSA-undertekster - SSA-Untertitel - υπότιτλοι SSA - SSA subtitles - SSA-subtekstoj - subtítulos SSA - SSA azpitituluak - SSA-tekstitykset - SSA undirtekstir - sous-titres SSA - fotheidil SSA - Subtitulos SSA - כתובית SSA - SSA titlovi - SSA feliratok - Subjudul SSA - Sottotitoli SSA - SSA 字幕 - SSA субтитрлары - SSA 자막 파일 - SSA subtitrai - SSA subtitri - SSA undertekst - SSA-ondertitels - SSA-teksting - Napisy SSA - Legendas SSA - Subtitrări SSA - субтитры SSA - Titulky SSA - Datoteka podnapisov SSA - Nëntituj SSA - SSA-undertexter - SSA altyazıları - субтитри SSA - Phụ đề SSA - SSA 字幕 - SSA 字幕 - SSA - SubStation Alpha - - - - - - - - - - SubViewer subtitles - ترجمات SubViewer - Subtytry SubViewer - Субтитри — SubViewer - subtítols SubViewer - Titulky SubViewer - SubViewer-undertekster - SubViewer-Untertitel - υπότιτλοι SubViewer - SubViewer subtitles - SubViewer-subtekstoj - subtítulos SubViewer - SubViewer azpitituluak - SubViewer-tekstitykset - SubViewer undirtekstir - sous-titres SubViewer - fotheidil SubViewer - subtítulos SubViewer - כתוביות של SubViewe - SubViewer titlovi - SubViewer feliratok - Subjudul SubViewer - Sottotitoli SubViewer - SubViewer 字幕 - SubViewer субтитрлары - SubViewer 자막 파일 - SubViewer subtitrai - SubViewer subtitri - SubViewer undertekst - SubViewer-ondertitels - SubViewer-teksting - Napisy SubViewer - Legendas SubViewer - Subtitrare SubViewer - субтитры SubViewer - Titulky SubViewer - Datoteka podnapisov SubViewer - Nëntituj SubViewer - SubViewer-undertexter - субтитри SubViewer - Phụ đề SubViewer - SubViewer 字幕 - SubViewer 字幕 - - - - - - - - iMelody ringtone - نغمة iMelody - Rington iMelody - Аудио — iMelody - to de trucada iMelody - Vyzváněcí melodie iMelody - iMelody-ringetone - iMelody-Klingelton - ringtone iMelody - iMelody ringtone - tono de llamada iMelody - iMelody doinua - iMelody-soittoääni - iMelody ringitóni - sonnerie iMelody - ton buailte iMelody - Melodía de iMelody - רינגטון של iMelody - iMelody ton zvonjenja - iMelody csengőhang - nada dering iMelody - Suoneria iMelody - iMelody リングトーン - iMelody әуені - iMelody 벨소리 - iMelody skambučio melodija - iMelody melodija - iMelody ringetone - iMelody-beltoon - iMelody-ringetone - Dzwonek iMelody - Toque de celular do iMelody - Sonerie iMelody - мелодия iMelody - Vyzváňacie melódie iMelody - Zvonjenje iMelody - Zile iMelody - iMelody-ringsignal - рінгтон iMelody - tiếng réo iMelody - iMelody 铃声 - iMelody 鈴聲 - - - - - - - - - - SMAF audio - SMAF سمعي - Aŭdyjo SMAF - Аудио — SMAF - àudio SMAF - Zvuk SMAF - SMAF-lyd - SMAF-Audio - ήχος SMAF - SMAF audio - SMAF-sondosiero - sonido SMAF - SMAF audioa - SMAF-ääni - SMAF ljóður - audio SMAF - fuaim SMAF - son SMAF - שמע SMAF - SMAF audio - SMAF hang - Audio SMAF - Audio SMAF - SMAF オーディオ - SMAF аудиосы - SMAF 오디오 - SMAF garso įrašas - SMAF audio - SMAF-lyd - SMAF-audio - SMAF-lyd - Plik dźwiękowy SMAF - Áudio SMAF - Audio SMAF - аудио SMAF - Zvuk SMAF - Zvočna datoteka SMAF - Audio SMAF - SMAF-ljud - звук SMAF - Âm thanh SMAF - SMAF 音频 - SMAF 音訊 - SMAF - Synthetic music Mobile Application Format - - - - - - - - - - MRML playlist - قائمة تشغيل MRML - Śpis piesień MRML - Списък за изпълнение — MRML - llista de reproducció MRML - Seznam skladeb MRML - MRML-afspilningsliste - MRML-Wiedergabeliste - λίστα αναπαραγωγής MRML - MRML playlist - MRML-ludlisto - lista de reproducción MRML - MRML erreprodukzio-zerrenda - MRML-soittolista - MRML avspælingarlisti - liste de lecture MRML - seinmliosta MRML - lista de reprodución MRML - רשימת השמעה MRML - MRML popis za reprodukciju - MRML-lejátszólista - Senarai putar MRML - Scaletta MRML - MPML 再生リスト - MRML რეპერტუარი - MRML ойнау тізімі - MRML 재생 목록 - MRML grojaraštis - MRML repertuārs - MRML-spilleliste - MRML-afspeellijst - MRML-speleliste - Lista odtwarzania MRML - Lista de reprodução do MRML - Listă redare MRML - список воспроизведения MRML - Zoznam skladieb MRML - Seznam predvajanja MRML - Listë titujsh MRML - MRML-spellista - список відтворення MRML - Danh mục nhạc MRML - MRML 播放列表 - MRML 播放清單 - MRML - Multimedia Retrieval Markup Language - - - - - - - - XMF audio - XMF سمعي - Aŭdyjo XMF - Аудио — XMF - àudio XMF - Zvuk XMF - XMF-lyd - XMF-Audio - ήχος XMF - XMF audio - XMF-sondosiero - sonido XMF - XMF audioa - XMF-ääni - XMF ljóður - audio XMF - fuaim XMF - son XMF - שמע XMF - XMF audio - XMF hang - Audio XMF - Audio XMF - XMF オーディオ - XMF аудиосы - XMF 오디오 - XMF garso įrašas - XMF audio - XMF-lyd - XMF-audio - XMF-lyd - Plik dźwiękowy XMF - Áudio XMF - Audio XMF - аудио XMF - Zvuk XMF - Zvočna datoteka XMF - Audio XMF - XMF-ljud - звук XMF - Âm thanh XMF - XMF 音频 - XMF 音訊 - XMF - eXtensible Music Format - - - - - - - - - - SV4 CPIO archive - أرشيف SV4 CPIO - SV4 CPIO arxivi - Archiŭ SV4 CPIO - Архив — SV4 CPIO - arxiu CPIO SV4 - Archiv SV4 CPIO - Archif CPIO SV4 - SV4 CPIO-arkiv - SV4-CPIO-Archiv - αρχείο SV4 CPIO - SV4 CPIO archive - SV4-CPIO-arkivo - archivador SV4 CPIO - SV4 CPIO artxiboa - SV4 CPIO -arkisto - SV4 CPIO skjalasavn - archive SV4 CPIO - cartlann SV4 CPIO - arquivo SV4 CPIO - ארכיון של SV4 SPIO - SV4 CPIO arhiva - SV4 CPIO-archívum - Arsip SV4 CPIO - Archivio SV4 CPIO - SV4 CPIO アーカイブ - SV4 CPIO архиві - SV4 CPIO 묶음 파일 - SV4 CPIO archyvas - SV4 CPIO arhīvs - Arkib CPIO SV4 - SV4 CPIO-arkiv - SV4 CPIO-archief - SV4 CPIO-arkiv - Archiwum SV4 CPIO - ficheiro SV4 CPIO - Pacote SV4 CPIO - Arhivă SV4 CPIO - архив SV4 CPIO - Archív SV4 CPIO - Datoteka arhiva SV4 CPIO - Arkiv SV4 CPIO - SV4 CPIO архива - SV4 CPIO-arkiv - SV4 CPIO arşivi - архів SV4 CPIO - Kho nén CPIO SV4 - SV4 CPIO 归档文件 - SV4 CPIO 封存檔 - - - - - SV4 CPIO archive (with CRC) - أرشيف SV4 CPIO (مع CRC) - Archiŭ SV4 CPIO (z CRC) - Архив — SV4 CPIO, проверка за грешки CRC - arxiu CPIO SV4 (amb CRC) - Archiv SV4 CPIO (s CRC) - SV4 CPIO-arkiv (med CRC) - SV4-CPIO-Archiv (mit CRC) - αρχείο SV4 CPIO (με CRC) - SV4 CPIO archive (with CRC) - SV4-CPIO-arkivo (kun CRC) - archivador SV4 CPIO (con CRC) - SV4 CPIO artxiboa (CRC-rekin) - SV4 CPIO -arkisto (CRC:llä) - SV4 CPIO skjalasavn (við CRC) - archive SV4 CPIO (avec CRC) - cartlann SV4 CPIO (le CRC) - Arquivador SV4 CPIO (con CRC) - ארכיון של SV4 SPIO (עם CRC) - SV4 CPIO arhiva (s CRC-om) - SV4 CPIO-archívum (CRC-vel) - Arsip SV4 CPIO (dengan CRC) - Archivio SV4 CPIO (con CRC) - SV4 CPIO アーカイブ (CRC 有り) - SV4 CPIO архиві (CRC бар) - SV4 CPIO 묶음 파일 (CRC 포함) - SV4 CPII archyvas (su CRC) - SV4 CPIO arhīvs (ar CRC) - Arkib CPIO SV4 (dengan CRC) - SV4 CPIO-arkiv (med CRC) - SV4 CPIO-archief (met CRC) - SV4 CPIO arkiv (med CRC) - Archiwum SV4 CPIO (z sumą kontrolną) - Pacote SV4 CPIO (com CRC) - Arhivă SV4 CPIO (cu CRC) - архив SV4 CPIP (с CRC) - Archív SV4 CPIO (s CRC) - Datoteka arhiva SV4 CPIO (z razpršilom CRC) - Arkiv SV4 CPIO (me CRC) - SV4 CPIO-arkiv (med CRC) - SV4 CPIO arşivi (CRC ile) - архів SV4 CPIO (з CRC) - Kho nén CPIO SV4 (với CRC) - SV4 CPIP 归档文件(带有 CRC) - SV4 CPIO 封存檔 (具有 CRC) - - - - - Tar archive - أرشيف Tar - Tar arxivi - Archiŭ tar - Архив — tar - arxiu tar - Archiv tar - Archif tar - Tar-arkiv - Tar-Archiv - συμπιεσμένο αρχείο Tar - Tar archive - archivador Tar - Tar artxiboa - Tar-arkisto - Tar skjalasavn - archive tar - cartlann Tar - arquivo Tar - ארכיון Tar - Tar arhiva - Tar archívum - Arsip Tar - Archivio tar - Tar アーカイブ - Tar архиві - TAR 묶음 파일 - Tar archyvas - Tar arhīvs - Arkib Tar - Tar-arkiv - Tar-archief - Tar-arkiv - Archiwum tar - Pacote tar - Arhivă Tar - архив TAR - Archív tar - Datoteka arhiva Tar - Arkiv tar - Тар архива - Tar-arkiv - архів tar - Kho nén tar - Tar 归档文件 - Tar 封存檔 - - - - - - - - - - - - Tar archive (compressed) - أرشيف Tar (مضغوط) - Archiŭ tar (skampresavany) - Архив — tar, компресиран - arxiu tar (comprimit) - Archiv tar (komprimovaný) - Tar-arkiv (komprimeret) - Tar-Archiv (komprimiert) - αρχείο Tar (συμπιεσμένο) - Tar archive (compressed) - archivador Tar (comprimido) - Tar artxiboa (konprimitua) - Tar-arkisto (pakattu) - Tar skjalasavn (stappað) - archive tar (compressée) - cartlann Tar (comhbhrúite) - arquivo Tar (comprimido) - ארכיון Tar (מכווץ) - Tar arhiva (komprimirana) - Tar archívum (tömörített) - Arsip Tar (terkompresi) - Archivio tar (compresso) - Tar アーカイブ (compress 圧縮) - Tar архиві (сығылған) - TAR 묶음 파일 (압축) - Tar archyvas (suglaudintas) - Tar arhīvs (saspiests) - Tar-arkiv (komprimert) - Tar-archief (ingepakt) - Tar-arkiv (pakka) - Archiwum tar (skompresowane) - Pacote tar (compactado) - Arhivă Tar (comprimată) - архив TAR (сжатый) - Archív tar (komprimovaný) - Datoteka arhiva Tar (stisnjen) - Arkiv tar (i kompresuar) - Tar-arkiv (komprimerat) - архів tar (стиснений) - Kho nén tar (đã nén) - Tar 归档文件(压缩) - Tar 封存檔 (UNIX 格式壓縮) - - - - - - - generic font file - ملف الخط العام - zvyčajny fajł šryftu - Шрифт - fitxer genèric de tipus de lletra - Obecný soubor písma - general skrifttypefil - Allgemeine Schriftdatei - γενικό αρχείο γραμματοσειράς - generic font file - genera tipara dosiero - tipografía genérico - letra-tipo orokorra - yleinen kirjasintiedosto - felagsstavasniðsfíla - fichier de polices générique - comhad cló ginearálta - ficheiro de tipo de fonte xenérica - קובץ גופן גנרי - općenita datoteka fonta - általános betűkészletfájl - berkas fonta generik - File tipo carattere generico - 一般フォントファイル - қаріп файлы - 일반 글꼴 파일 - bendras šrifto failas - vispārēja fonta datne - Fail font generik - vanlig skriftfil - algemeen lettertypebestand - vanleg skrifttypefil - Zwykły plik czcionki - ficheiro genérico de tipo de letra - Arquivo de fonte genérico - fișier de font generic - файл шрифта - Obyčajný súbor písma - izvorna datoteka pisave - File lloj gërme i përgjithshëm - општа датотека фонта - allmän typsnittsfil - загальний файл шрифту - tập tin phông giống loài - 通用字体文件 - 通用字型檔 - - - - - packed font file - ملف الخط المرزم - zapakavany fajł šryftu - Шрифт — компресиран - fitxer empaquetat de tipus de lletra - Komprimovaný soubor písma - pakket skrifttypefil - Gepackte Schriftdatei - αρχείο συμπιεσμένης γραμματοσειράς - packed font file - pakigita tipara dosiero - archivo de tipografía empaquetada - Letra-tipo fitxategi paketatua - pakattu kirjasintiedosto - pakkað stavasniðsfíla - fichier de polices empaquetées - comhad cló pacáilte - ficheiro de fonte empaquetada - קובץ גופן ארוז - pakirana datoteka fonta - packed font-fájl - berkas fonta terkemas - File tipo carattere condensato - パックされたフォントファイル - қаріп файлы (дестеленген) - 글꼴 묶음 파일 - supakuotas šrifto failas - sapakota fonta datne - Fail font dipek - pakket skriftfil - ingepakt lettertypebestand - pakka skrifttypefil - Plik ze spakowaną czcionką - ficheiro de fontes empacotadas - Arquivo de fonte empacotado - fișier font împachetat - сжатый файл шрифта - Komprimovaný súbor písma - pakirana datoteka pisave - File lloj gërmash i kondensuar - пакована датотека са фонтом - packad typsnittsfil - запакований файл шрифту - tập tin phông chữ đã đóng gói - 打包的字体文件 - 包裝字型檔 - - - - - TGIF document - مستند TGIF - Dakument TGIF - Документ — TGIF - document TGIF - Dokument TGIF - TGIF-dokument - TGIF-Dokument - Σχέδιο TGIF - TGIF document - TGIF-dokumento - documento TGIF - TGIF dokumentua - TGIF-asiakirja - TGIF skjal - document TGIF - cáipéis TGIF - documento TGIF - מסמך TGIF - TGIF dokument - TGIF-dokumentum - Dokumen TGIF - Documento TGIF - TGIF ドキュメント - TGIF құжаты - TGIF 문서 - TGIF dokumentas - TGIF dokuments - Dokumen TGIF - TGIF-dokument - TGIF-document - TGIF-dokument - Dokument TGIF - documento TGIF - Documento TGIF - Document TGIF - документ TGIF - Dokument TGIF - Dokument TGIF - Dokument TGIF - TGIF документ - TGIF-dokument - документ TGIF - Tài liệu TGIF - TGIF 文档 - TGIF 文件 - - - - - - - - theme - سمة - örtük - matyŭ - Тема - tema - Motiv - thema - tema - Thema - Θέμα - theme - etoso - tema - gaia - teema - tema - thème - téama - tema - ערכת נושא - tema - téma - tema - Tema - テーマ - თემა - тема - 테마 - tema - motīvs - Tema - tema - thema - drakt - Motyw - tema - Tema - temă - тема - Motív - tema - Temë - тема - tema - тема - sắc thái - 主题 - 佈景主題 - - - - - - ToutDoux document - مستند ToutDoux - ToutDoux sənədi - Dakument ToutDoux - Документ — ToutDoux - document ToutDoux - Dokument ToutDoux - Dogfen ToutDoux - ToutDoux-dokument - ToutDoux-Dokument - έγγραφο ToutDoux - ToutDoux document - ToutDoux-dokumento - documento de ToutDoux - ToutDoux dokumentua - ToutDoux-asiakirja - ToutDoux skjal - document ToutDoux - cáipéis ToutDoux - documento de ToutDoux - משמך של ToutDoux - ToutDoux dokument - ToutDoux-dokumentum - Dokumen ToutDoux - Documento ToutDoux - ToutDoux ドキュメント - ToutDoux құжаты - ToutDoux 문서 - ToutDoux dokumentas - ToutDoux dokuments - Dokumen ToutDoux - ToutDoux-dokument - ToutDoux-document - ToutDoux-dokument - Dokument ToutDoux - documento ToutDoux - Documento do ToutDoux - Document ToutDoux - документ ToutDoux - Dokument ToutDoux - Dokument ToutDoux - Dokument ToutDoux - ToutDoux документ - ToutDoux-dokument - ToutDoux belgesi - документ ToutDoux - Tài liệu ToutDoux - ToutDoux 文档 - ToutDoux 文件 - - - - backup file - ملف النسخ الاحتياطي - zapasny fajł - Резервно копие - fitxer de còpia de seguretat - Záložní soubor - sikkerhedskopi - Sicherungsdatei - αντίγραφο ασφαλείας - backup file - restaŭrkopio - archivo de respaldo - babes-kopiako fitxategia - varmuuskopio - trygdarritsfíla - fichier de sauvegarde - comhad cúltaca - ficheiro de copia de seguridade - קובץ גיבוי - biztonsági mentés - berkas cadangan - File di backup - バックアップファイル - резервті көшірмесі - 백업 파일 - atsarginis failas - dublējuma datne - Fail backup - sikkerhetskopi - reservekopiebestand - tryggleikskopi - Plik zapasowy - cópia de segurança - Arquivo de backup - fișier de backup - резервная копия - Záložný súbor - varnostna kopija datoteke - File backup - резервна копија - säkerhetskopia - yedek dosyası - резервна копія - tập tin sao lưu - 备份文件 - 備份檔 - - - - - - - - Troff document - مستند Troff - Troff sənədi - Dakument Troff - Документ — Troff - document Troff - Dokument troff - Dogfen troff - Troffdokument - Troff-Dokument - έγγραφο troff - Troff document - Troff-dokumento - documento troff - Troff dokumentua - Troff-asiakirja - Troff skjal - document Troff - cáipéis Troff - documento Troff - מסמך Troff - Troff dokument - Troff-dokumentum - Dokumen Troff - Documento Troff - Troff 入力ドキュメント - Troff құжаты - Troff 문서 - Troff dokumentas - Troff dokuments - Dokumen Troff - Troff-dokument - Troff-document - Troff-dokument - Dokument Troff - documento Troff - Documento troff - Document Troff - документ Troff - Dokument troff - Dokument Troff - Dokument Troff - Troff документ - Troff-dokument - Troff belgesi - документ Troff - Tài liệu Troff - Troff 文档 - Troff 文件 - - - - - - - - - - - - - - - Troff document (with manpage macros) - مستند Troff (مع اختصارات صفحة المساعدة) - Dakument Troff (z makrasam man-staronak) - Документ — Troff, с макроси за справочни страници - document Troff (amb macros de pàgines de manual) - Dokument troff (s makry pro manuálové stránky) - Troffdokument (med manualsidemakroer) - Troff-Dokument (mit man-Seitenmakros) - έγγραφο troff (με μακροεντολές manpage) - Troff document (with manpage macros) - Troff-dokumento (kun manpaĝaj makrooj) - documento troff (con macros de páginas de manual) - Troff dokumentua (manpage makroekin) - Troff-asiakirja (man-sivu-makroilla) - Troff skjal (við manpage fjølvi) - document Troff (avec macros manpage) - cáipéis Troff (le macraí manpage) - documento Troff (con macros de páxinas de manual) - מסמך של Troff (עם מאקרו בmanpage) - Troff dokument (s makro naredbama priručnika) - Troff-dokumentum (manpage-makrókkal) - Dokumen Troff (dengan makro halaman manual) - Documento Troff (con macro per manpage) - Troff 入力ドキュメント (man ページマクロ有り) - Troff құжаты (әдістемелік парақтар макростарымен) - Troff 문서 (man 페이지 매크로 포함) - Troff dokumentas (su žin. puslapių makrokomandomis) - Troff dokuments (ar manpage makrosiem) - Dokumen Troff (dengan macros halaman man) - Troff-dokument (med manualsidemakroer) - Troff-document (met man-macro's) - Troff-dokument med manualside-makroar - Dokument Troff (z makrami stron pomocy) - documento Troff (com macros manpage) - Documento troff (com macros de páginas de manual) - Document Troff (cu macro-uri manpage) - документ Troff (с макросами страниц руководства) - Dokument troff (s makrami pre manuálové stránky) - Dokument Troff (z makroji manpage) - Dokumet Troff (me makro për manpage) - Troff документ (са макроима за ман странице) - Troff-dokument (med manualsidemakron) - документ Troff (з макросами manpage) - Tài liệu Troff (có vĩ lệnh trang hướng dẫn) - Troff 文档(带 Man 手册宏) - Troff 文件 (含有手冊頁面巨集) - - - - - - manual page (compressed) - صفحة المساعدة (مضغوطة) - man səhifəsi (sıxışdırılmış) - staronka dapamohi (skampresavanaja) - Страница от справочника, компресирана - pàgina de manual (comprimida) - Manuálová stránka (komprimovaná) - tudalen llawlyfr (wedi ei gywasgu) - manualside (komprimeret) - Handbuchseite (komprimiert) - σελίδα οδηγιών (συμπιεσμένη) - manual page (compressed) - manpaĝo (kunpremita) - página de manual (comprimida) - eskuliburu orria (konprimitua) - manuaalisivu (pakattu) - handbókasíða (stappað) - page de manuel (compressée) - leathanach lámhleabhair (comhbhrúite) - páxina de manual (comprimida) - דף עזר (מכווץ) - stranica priručnika (komprimirana) - kézikönyvoldal (tömörített) - halaman manual (terkompresi) - Pagina di manuale (compressa) - (圧縮) man ページ - әдістемелік парағы (сығылған) - man 페이지 (압축) - žinyno puslapis (suglaudintas) - rokasgrāmatas lapa (saspiesta) - Halaman manual (termampat) - manualside (komprimert) - handleidingspagina (ingepakt) - manualside (pakka) - Strona podręcznika (skompresowana) - página de manual (comprimida) - Página de manual (compactada) - pagină de manual (comprimată) - страница руководства (сжатая) - Manuálová stránka (komprimovaná) - stran priročnika (stisnjena) - Faqe manuali (e kompresuar) - страна упутства (компресована) - manualsida (komprimerad) - сторінка посібника (стиснена) - trang hướng dẫn (đã nén) - 手册页 (压缩) - 手冊頁面 (壓縮版) - - - - Tar archive (LZO-compressed) - أرشيف Tar (مضغوط-LZO) - Archiŭ tar (LZO-skampresavany) - Архив — tar, компресиран с LZO - arxiu tar (comprimit amb LZO) - Archiv tar (komprimovaný pomocí LZO) - Tar-arkiv (LZO-komprimeret) - Tar-Archiv (LZO-komprimiert) - αρχείο Tar (συμπιεσμένο με LZO) - Tar archive (LZO-compressed) - archivador Tar (comprimido con LZO) - Tar artxiboa (LZO-rekin konprimitua) - Tar-arkisto (LZO-pakattu) - Tar skjalasavn (LZO-stappað) - archive tar (compression LZO) - cartlann Tar (comhbhrúite le LZO) - arquivo Tar (comprimido con LZO) - ארכיון Tar (מכווץ ע"י LZO) - Tar arhiva (komprimirana LZO-om) - Tar archívum (LZO-val tömörítve) - Arsip Tar (terkompresi LZO) - Archivio tar (compresso con LZO) - Tar アーカイブ (LZO 圧縮) - Tar архиві (LZO-мен сығылған) - TAR 묶음 파일 (LZO 압축) - Tar archyvas (suglaudintas su LZO) - Tar arhīvs (saspiests ar LZO) - Tar-arkiv (LZO-komprimert) - Tar-archief (ingepakt met LZO) - Tar-arkiv (pakka med LZO) - Archiwum tar (kompresja LZO) - Pacote tar (compactado com LZO) - Arhivă Tar (comprimată LZO) - архив TAR (сжатый LZO) - Archív tar (komprimovaný pomocou LZO) - Datoteka arhiva Tar (stisnjen z LZO) - Arkiv tar (i kompresuar me LZO) - Tar-arkiv (LZO-komprimerat) - архів tar (стиснений LZO) - Kho nén tar (đã nén LZO) - Tar 归档文件(LZO 压缩) - Tar 封存檔 (LZO 格式壓縮) - - - - - - - XZ archive - أرشيف XZ - Архив — XZ - arxiu XZ - Archiv XZ - XZ-arkiv - XZ-Archiv - συμπιεσμένο αρχείο XZ - XZ archive - XZ-arkivo - archivador XZ - XZ artxiboa - XZ-arkisto - XZ skjalasavn - archive XZ - cartlann XZ - ficheiro XZ - ארכיון XZ - XZ-archívum - Arsip XZ - Archivio XZ - XZ アーカイブ - XZ архиві - XZ 압축 파일 - XZ archyvas - XZ arhīvs - XZ archief - Archiwum XZ - Pacote XZ - Arhivă XZ - архив XZ - Archív XZ - Datoteka arhiva XZ - XZ-arkiv - XZ arşivi - архів XZ - XZ 归档文件 - XZ 封存檔 - - - - - - - - Tar archive (XZ-compressed) - أرشيف Tar (مضغوط-XZ) - Архив — tar, компресиран с XZ - arxiu tar (comprimit amb XZ) - Archiv tar (komprimovaný pomocí XZ) - Tar-arkiv (XZ-komprimeret) - Tar-Archiv (XZ-komprimiert) - αρχείο Tar (συμπιεσμένο με XZ) - Tar archive (XZ-compressed) - archivador Tar (comprimido con XZ) - Tar artxiboa (XZ-rekin konprimitua) - Tar-arkisto (XZ-pakattu) - Tar skjalasavn(XZ-stappað) - archive tar (compression XZ) - cartlann Tar (comhbhrúite le XZ) - arquivo Tar (comprimido con XZ) - ארכיון Tar (מכווץ ע"י XZ) - Tar arhiva (komprimirana XZ-om) - Tar archívum (XZ-vel tömörítve) - Arsip Tar (terkompresi XZ) - Archivio tar (compresso con XZ) - Tar アーカイブ (XZ 圧縮) - Tar архиві (XZ-мен сығылған) - TAR 묶음 파일 (XZ 압축) - Tar archyvas (suglaudintas su XZ) - Tar arhīvs (saspiests ar XZ) - Tar archief (XZ-compressed) - Archiwum tar (kompresja XZ) - Pacote tar (compactado com XZ) - Arhivă Tar (comprimată XZ) - архив TAR (сжатый XZ) - Archív tar (komprimovaný pomocou XZ) - Datoteka arhiva Tar (stisnjen z XZ) - Tar-arkiv (XZ-komprimerat) - архів tar (стиснений XZ) - Tar 归档文件(XZ 压缩) - Tar 封存檔 (XZ 格式壓縮) - - - - - - - PDF document (XZ-compressed) - Документ — PDF, компресиран с XZ - document PDF (comprimit amb XZ) - Dokument PDF (komprimovaný pomocí XZ) - PDF-dokument (XZ-komprimeret) - PDF-Dokument (XZ-komprimiert) - έγγραφο PDF (συμπιεσμένο με XZ) - PDF document (XZ-compressed) - Documento PDF (comprimido en XZ) - PDF-asiakirja (XZ-pakattu) - document PDF (compressé XZ) - documento PDF (comprimido en XZ) - מסמך PDF (בדחיסת XZ) - PDF dokument (komprimiran XZ-om) - PDF dokumentum (XZ-vel tömörített) - Dokumen PDF (terkompresi XZ) - Documento PDF (compresso con XZ) - PDF 文書(XZ 圧縮) - PDF დოკუმენტი (XZ-ით შეკუმშული) - PDF құжаты (XZ-мен сығылған) - PDF 문서 (XZ 압축) - PDF dokuments (saspiests ar XZ) - PDF document (XZ-compressed) - Dokument PDF (kompresja XZ) - Documento PDF (compactado com XZ) - документ PDF (сжатый XZ) - Dokument PDF (XZ-stisnjen) - PDF-dokument (XZ-komprimerad) - документ PDF (стиснений xz) - PDF 文档(XZ) - PDF 文件 (XZ 格式壓縮) - - - - - - Ustar archive - أرشيف Ustar - Archiŭ ustar - Архив — ustar - arxiu ustar - Archiv ustar - Ustararkiv - Ustar-Archiv - συμπιεσμένο αρχείο Ustar - Ustar archive - Ustar-arkivo - archivador Ustar - Ustar artxiboa - Ustar-arkisto - Ustar skjalasavn - archive Ustar - cartlann Ustar - arquivo Ustar - ארכיון Ustar - Ustar arhiva - Ustar archívum - Arsip Ustar - Archivio ustar - Ustar アーカイブ - Ustar архиві - Ustar 압축 파일 - Ustar archyvas - Ustar arhīvs - Ustar-arkiv - Ustar-archief - Ustar-arkiv - Archiwum ustar - Pacote Ustar - Arhivă Ustar - архив Ustar - Archív ustar - Datoteka arhiva Ustar - Arkiv Ustar - Ustar-arkiv - Ustar arşivi - архів ustar - Kho nén ustar - Ustar 归档文件 - Ustar 封存檔 - - - - - WAIS source code - شفرة مصدر WAIS - WAIS mənbə faylı - Kryničny kod WAIS - Изходен код — WAIS - codi font en WAIS - Zdrojový kód WAIS - Ffynhonnell Rhaglen WAIS - WAIS-kildekode - WAIS-Quelltext - πηγαίος κώδικας WAIS - WAIS source code - WAIS-fontkodo - código fuente WAIS - WAIS iturburu-kodea - WAIS-lähdekoodi - WAIS keldukota - code source WAIS - cód foinseach WAIS - código fonte WAIS - קוד מקור של WAIS - WAIS izvorni kod - WAIS-forráskód - Kode program WAIS - Codice sorgente WAIS - WAIS ソースコード - WAIS бастапқы коды - WAIS 소스 코드 - WAIS pradinis kodas - WAIS pirmkods - Kod sumber WAIS - WAIS-kildekode - WAIS-broncode - WAIS-kjeldekode - Plik źródłowy WAIS - código fonte WAIS - Código-fonte WAIS - Cod sursă WAIS - исходный код WAIS - Zdrojový kód WAIS - Datoteka izvorne kode WAIS - Kod burues WAIS - WAIS изворни ко̂д - WAIS-källkod - WAIS kaynak kodu - вихідний код мовою WAIS - Mã nguồn WAIS - WAIS 源代码 - WAIS 源碼 - - - - - WordPerfect/Drawperfect image - صورة WordPerfect/Drawperfect - Vyjava WordPerfect/Drawperfect - Изображение — WordPerfect/Drawperfect - imatge de WordPerfect/Drawperfect - Obrázek WordPerfect/Drawperfect - WordPerfect/Drawperfect-billede - WordPerfect/DrawPerfect-Bild - εικόνα WordPerfect/Drawperfect - WordPerfect/Drawperfect image - WordPerfect/Drawperfect-bildo - imagen de WordPerfect/Drawperfect - WordPerfect/Drawperfect irudia - WordPerfect/Drawperfect-kuva - WordPerfect/Drawperfect mynd - image WordPerfect/DrawPerfect - íomhá WordPerfect/Drawperfect - imaxe de WordPerfect/DrawPerfect - תמונה של WordPerfect/Drawperfect - WordPerfect/Drawperfect slika - WordPerfect/Drawperfect-kép - Gambar WordPerfect/Drawperfect - Immagine WordPerfect/Drawperfect - WordPerfect/Drawperfect 画像 - WordPerfect/Drawperfect суреті - 워드퍼펙트/드로퍼펙트 그림 - WordPerfect/Drawperfect paveikslėlis - WordPerfect/Drawperfect attēls - Imej WordPerfect/Drawperfect - WordPerfect-/Drawperfect-bilde - WordPerfect/Drawperfect-afbeelding - WordPerfect/DrawPerfect-bilete - Obraz WordPerfect/DrawPerfect - imagem do WordPerfect/Drawperfect - Imagem do WordPerfect/Drawperfect - Imagine WordPerfect/Drawperfect - изображение WordPerfect/Drawperfect - Obrázok WordPerfect/Drawperfect - Slikovna datoteka Drawperfect - Figurë WordPerfect/Drawperfect - WordPerfect/Drawperfect слика - WordPerfect/Drawperfect-bild - зображення WordPerfect/Drawperfect - Ảnh WordPerfect/Drawperfect - WordPerfect/Drawperfect 图像 - WordPerfect/Drawperfect 影像 - - - - - DER/PEM/Netscape-encoded X.509 certificate - شهادة DER/PEM/Netscape-encoded X.509 - Sertyfikat X.509, zakadavany ŭ DER/PEM/Netscape - Сертификат — DER/PEM/Netscape X.509 - certificat X.509 codificat com DER/PEM/Netscape - Certifikát X.509 kódovaný jako DER/PEM/Netscape - DER-/PEM-/Netscapekodet X.509-certifikat - DER/PEM/Netscape-kodiertes X.509-Zertifikat - ψηφιακό πιστοποιητικό X.509 κωδικοποιημένο κατά DER/PEM/Netscape - DER/PEM/Netscape-encoded X.509 certificate - DER/PEM/Netscape-kodigita X.509-atestilo - certificado X.509 codificado con DER/PEM/Netscape - X.509rekin kodetutako DER, PEM edo Netscape zertifikatua - DER/PEM/Netscape-koodattu X.509-varmenne - DER/PEM/Netscape-encoded X.509 váttan - certificat X.509 codé DER/PEM/Netscape - teastas X.509 ionchódaithe le DER/PEM/Netscape - certificado X.509 codificado con DER/PEM/Netscape - אישור מסוג X.509 של DER/PEM/Netscape-encoded - DER/PEM/Netscape-kodiran X.509 certifikat - DER/PEM/Netscape formátumú X.509-tanúsítvány - Sertifikat DER/PEM/Netscape-tersandi X.509 - Certificato DER/PEM/Netscape-encoded X.509 - DER/PEM/Netscape エンコード X.509 証明書 - DER/PEM/Netscape კოდირებული X.509 სერტიფიკატი - X.509 сертификаты (DER/PEM/Netscape кодталған) - DER/PEM/넷스케이프로 인코딩된 X.509 인증서 - DER/PEM/Netscape-encoded X.509 liudijimas - DER/PEM/Netscape-encoded X.509 sertifikāts - Sijil X.509 dienkod /DER/PEM/Netscape - DER/PEM/Netscape-kodet X.509-sertifikat - DER/PEM/Netscape-gecodeerd X.509-certificaat - DER/PEM/Netscape-koda X.509-sertifikat - Zakodowany w DER/PEM/Netscape certyfikat X.509 - certificado X.509 codificado com DER/PEM/Netscape - Certificado X.509 codificado com DER/PEM/Netscape - Certificat DER/PEM/Netscape-codat X.509 - сертификат X.509 (DER/PEM/Netscape-закодированный) - Certifikát X.509 kódovaný ako DER/PEM/Netscape - Datoteka potrdila DER/PEM/Netscape X.509 - Çertifikatë DER/PEM/Netscape-encoded X.509 - DER, PEM или Нетскејп кодирани сертификат X.509 - DER/PEM/Netscape-kodat X.509-certifikat - сертифікат X.509 у форматі DER/PEM/Netscape - Chứng nhận X.509 mã hoá bằng Netscape/PEM/DER - DER/PEM/Netscape-encoded X.509 证书 - DER/PEM/Netscape 編碼的 X.509 憑證 - - - - - - - - empty document - مستند فارغ - pusty dakument - Празен документ - document buit - Prázdný dokument - tomt dokument - Leeres Dokument - κενό έγγραφο - empty document - malplena dokumento - documento vacío - dokumentu hutsa - tyhjä asiakirja - tómt skjal - document vide - cáipéis fholamh - documeto baleiro - מסמך ריק - prazan dokument - üres dokumentum - dokumen kosong - Documento vuoto - 空のドキュメント - бос құжат - 빈 문서 - tuščias dokumentas - tukšs dokuments - Dokumen kosong - tomt dokument - leeg document - tomt dokument - Pusty dokument - documento vazio - Documento vazio - document gol - пустой документ - Prázdny dokument - prazen dokument - Dokument bosh - празан документ - tomt dokument - boş belge - порожній документ - tài liệu rỗng - 空文档 - 空白文件 - - - Zoo archive - أرشيف Zoo - Zoo arxivi - Archiŭ zoo - Архив — zoo - arxiu zoo - Archiv zoo - Archif zoo - Zooarkiv - Zoo-Archiv - συμπιεσμένο αρχείο Zoo - Zoo archive - Zoo-arkivo - archivador Zoo - Zoo artxiboa - Zoo-arkisto - Zoo skjalasavn - archive zoo - cartlann Zoo - ficheiro Zoo - ארכיון Zoo - Zoo archívum - Arsip Zoo - Archivio zoo - Zoo アーカイブ - Zoo архиві - ZOO 압축 파일 - Zoo archyvas - Zoo arhīvs - Zoo-arkiv - Zoo-archief - Zoo-arkiv - Archiwum zoo - Pacote Zoo - Arhivă Zoo - архив ZOO - Archív zoo - Datoteka arhiva ZOO - Arkiv zoo - Zoo-arkiv - Zoo arşivi - архів zoo - Kho nén zoo - Zoo 归档文件 - Zoo 封存檔 - - - - - - - - XHTML page - صفحة XHTML - Staronka XHTML - Страница — XHTML - pàgina XHTML - Stránka XHTML - XHTML-side - XHTML-Seite - σελίδα XHTML - XHTML page - XHTML-paĝo - página XHTML - XHTML orria - XHTML-sivu - XHTML síða - page XHTML - leathanach XHTML - Páxina XHTML - דף XHTML - XHTML stranica - XHTML-oldal - Halaman XHTML - Pagina XHTML - XHTML ページ - XHTML парағы - XHTML 페이지 - XHTML puslapis - XHTML lapa - Laman XHTML - XHTML-side - XHTML-pagina - XHTML-side - Strona XHTML - página XHTML - Página XHTML - Pagină XHTML - страница XHTML - Stránka XHTML - Datoteka spletne strani XHTML - Faqe XHTML - XHTML страна - XHTML-sida - сторінка XHTML - Trang XHTML - XHTML 页面 - XHTML 網頁 - XHTML - Extensible HyperText Markup Language - - - - - - - Zip archive - أرشيف Zip - Zip arxivi - Archiŭ zip - Архив — zip - arxiu zip - Archiv ZIP - Archif ZIP - Ziparkiv - Zip-Archiv - συμπιεσμένο αρχείο Zip - Zip archive - Zip-arkivo - archivador Zip - Zip artxiboa - Zip-arkisto - Zip skjalasavn - archive zip - cartlann Zip - ficheiro Zip - ארכיון Zip - Zip archívum - Arsip Zip - Archivio zip - Zip アーカイブ - Zip архиві - ZIP 압축 파일 - Zip archyvas - Zip arhīvs - Zip-arkiv - Zip-archief - Zip-arkiv - Archiwum ZIP - Pacote Zip - Arhivă zip - архив ZIP - Archív ZIP - Datoteka arhiva ZIP - Arkiv zip - Zip-arkiv - Zip arşivi - архів zip - Kho nén zip - Zip 归档文件 - Zip 封存檔 - - - - - - - - - - Windows Imaging Format Disk Image - Диск — Windows Imaging - imatge de disc «Windows Imaging Format» - Windows Imaging Format Disk Image - Windows Imaging Format-diskaftryk - Windows-Imaging-Format-Datenträgerabbild - εικόνα δίσκου Windows Image Format - Windows Imaging Format Disk Image - imagen de disco de Windows Imaging Format - image disque Windows Imaging Format - imaxe de disco de Windows Imaging Format - מבנה תמונת כונן של Windows Imaging - Windows Imaging Format lemezkép - Image Disk Windows Imaging Format - Immagine disco formato Windows Imaging - Windows イメージング形式 ディスクイメージ - Windows Imaging Format Disk бейнесі - Windows 이미지 포맷 디스크 이미지 - Windows Imaging Format diska attēls - Windows Imaging Format Disk Image - Obraz dysku Windows Imaging Format - Imagem de Disco de Formato Windows Imaging - Imagine de disc „Windows Imaging Format” - образ диска Windows - Odtis slike Windows Imaging - Windows Imaging Format Disk-avbild - формат образів дисків Windows Imaging - Windows Imaging 格式磁盘镜像 - Windows Imaging Format Disk 映像 - - - - - - - - Dolby Digital audio - Dolby Digital سمعي - Dolby Digital audio - Aŭdyjo Dolby Digital - Аудио — Dolby Digital - àudio Dolby Digital - Zvuk Dolby Digital - Sain Dolby Digital - Dolby Ditital-lyd - Dolby-Digital-Audio - ψηφιακός Ήχος Dolby - Dolby Digital audio - Sondosiero en Dolby Digital - sonido Dolby Digital - Dolby audio digitala - Dolby Digital -ääni - Dolby Digital ljóður - audio Dolby Digital - fuaim Dolby Digital - son Dolby Digital - שמע Dolby Digital - Dolby Digital audio - Dolby Digital hang - Audio Dolby Digital - Audio Dolby Digital - ドルビーデジタルオーディオ - Dolby Digital-ის აუდიო - Dolby Digital аудиосы - 돌비 디지털 오디오 - Dolby Digital garso įrašas - Dolby Digital audio - Audio Digital Dolby - Dolby digital lyd - Dolby Digital-audio - Dolby Digital lyd - Plik dźwiękowy Dolby Digital - áudio Dolby Digital - Áudio Dolby Digital - Audio Dolby Digital - аудио Dolby Digital - Zvuk Dolby Digital - Zvočna datoteka Dolby Digital - Audio Dolby Digital - Дигитални Dolby звучни запис - Dolby Digital-ljud - звук Dolby Digital - Âm thanh Dolby Digital - 杜比数字音频 - 杜比數位音訊 - - - - - - - DTS audio - - - - - - - - - - - DTSHD audio - - - - - - - - - AMR audio - AMR سمعي - Aŭdyjo AMR - Аудио — AMR - àudio AMR - Zvuk AMR - AMR-lyd - AMR-Audio - ήχος AMR - AMR audio - AMR-sondosiero - sonido AMR - AMR audioa - AMR-ääni - AMR ljóður - audio AMR - fuaim AMR - son AMR - שמע AMR - AMR audio - AMR hang - Audio AMR - Audio AMR - AMR オーディオ - AMR აუდიო - AMR аудиосы - AMR 오디오 - AMR garso įrašas - AMR audio - AMR-lyd - AMR-audio - AMR-lyd - Plik dźwiękowy AMR - Áudio AMR - Audio AMR - аудио AMR - Zvuk AMR - Zvočna datoteka AMR - Audio AMR - AMR-ljud - звук AMR - Âm thanh AMR - AMR 音频 - AMR 音訊 - AMR - Adaptive Multi-Rate - - - - - - - - AMR-WB audio - AMR-WB سمعي - Aŭdyjo AMR-WB - Аудио — AMR-WB - àudio AMR-WB - Zvuk AMR-WB - AMR-WB-lyd - AMR-WB-Audio - ήχος AMR-WB - AMR-WB audio - AMR-WB-sondosiero - sonido AMR-WB - AMR-WB audioa - AMR-WB-ääni - AMR-WB ljóður - audio AMR-WB - fuaim AMR-WB - son AMR-WB - שמע AMR-WN - AMR-WB audio - AMR-WB hang - Audio AMR-WB - Audio AMR-WB - AMR-WB オーディオ - AMR-WB აუდიო - AMR-WB аудиосы - AMR-WB 오디오 - AMR-WB garso įrašas - AMR-WB audio - AMR-WB-lyd - AMR-WB-audio - AMR-WB-lyd - Plik dźwiękowy AMR-WB - Áudio AMR-WB - Audio AMR-WB - аудио AMR-WB - Zvuk AMR-WB - Zvočna datoteka AMR-WB - Audio AMR-WB - AMR-WB-ljud - звук AMR-WB - Âm thanh AMR-WB - AMR-WB 音频 - AMR-WB 音訊 - AMR-WB - Adaptive Multi-Rate Wideband - - - - - - - - ULAW (Sun) audio - ULAW (صن) سمعي - ULAW (Sun) audio faylı - Aŭdyjo ULAW (Sun) - Аудио — ULAW, Sun - àudio ULAW (Sun) - Zvuk ULAW (Sun) - Sain ULAW (Sun) - ULAW-lyd (Sun) - ULAW-Audio (Sun) - ήχος ULAW (Sun) - ULAW (Sun) audio - ULAW-sondosiero (Sun) - sonido ULAW (Sun) - ULAW (sun) audioa - ULAW (Sun) -ääni - ULAW (Sun) ljóður - audio ULAW (Sun) - fuaim ULAW (Sun) - son ULAW (Sun) - שמע ULAW (של Sun) - ULAW (Sun) hang - Audio ULAW (Sun) - Audio ULAW (Sun) - ULAW (Sun) オーディオ - ULAW (Sun) аудиосы - ULAW (Sun) 오디오 - ULAW (Sun) garso įrašas - ULAW (Sun) audio - Audio ULAW (Sun) - ULAW-lyd (Sun) - (Sun) ULAW-audio - ULAW (Sun)-lyd - Plik dźwiękowy ULAW (Sun) - áudio ULAW (Sun) - Áudio ULAW (Sun) - Fișier audio ULAW (Sun) - аудио ULAW (Sun) - Zvuk ULAW (Sun) - Zvočna datoteka ULAW (Sun) - Audio ULAW (Sun) - ULAW (Sun) звучни запис - ULAW-ljud (Sun) - звук ULAW (Sun) - Âm thanh ULAW (Sun) - ULAW (Sun) 音频 - ULAW (Sun) 音訊 - - - - - - - - Commodore 64 audio - Commodore 64 سمعي - Aŭdyjo Commodore 64 - Аудио — Commodore 64 - àudio Commodore 64 - Zvuk Commodore 64 - Commodore 64-lyd - Commodore-64-Audio - ήχος Commodore 64 - Commodore 64 audio - Sondosiero de Commodore 64 - sonido de Commodore 64 - Commodore 64 Audioa - Commodore 64 -ääni - Commodore 64 ljóð - audio Commodore 64 - fuaim Commodore 64 - son de Commodore 64 - שמע של Commodore 64 - Commodore 64 audio - Commodore 64 hang - Audio Commodore 64 - Audio Commodore 64 - Commodore 64 オーディオ - Commodore 64-ის აუდიო - Commodore 64 аудиосы - Commodore 64 오디오 - Commodore 64 garso įrašas - Commodore 64 audio - Audio Commodore 64 - Commodore 64-lyd - Commodore 64-audio - Commodore 64-lyd - Plik dźwiękowy Commodore 64 - áudio Commodore 64 - Áudio Commodore 64 - Audio Commodore 64 - аудио Commodore 64 - Zvuk Commodore 64 - Zvočna datoteka Commodore 64 - Audio Commodore 64 - Комодор 64 звучни запис - Commodore 64-ljud - звук Commodore 64 - Âm thanh Commodore 64 - Commodore 64 音频 - Commodore 64 音訊 - - - - - - - - PCM audio - سمعي PCM - PCM audio faylı - Aŭdyjo PCM - Аудио — PCM - àudio PCM - Zvuk PCM - Sain PCM - PCM-lyd - PCM-Audio - ήχος PCM - PCM audio - PCM-sondosiero - sonido PCM - PCM audioa - PCM-ääni - PCM ljóður - audio PCM - fuaim PCM - son PCM - שמע PCM - PCM hang - Audio PCM - Audio PCM - PCM オーディオ - PCM аудиосы - PCM 오디오 - PCM garso įrašas - PCM audio - Audio PCM - PCM-lyd - PCM-audio - PCM-lyd - Plik dźwiękowy PCM - áudio PCM - Áudio PCM - Audio PCM - аудио PCM - Zvuk PCM - Zvočna datoteka PCM - Audio PCM - PCM звучни запис - PCM-ljud - звук PCM - Âm thanh PCM - PCM 音频 - PCM 音訊 - - - - - - - - - - - - - - - - - - AIFC audio - AIFC سمعي - AIFC audio faylı - Aŭdyjo AIFC - Аудио — AIFC - àudio AIFC - Zvuk AIFC - Sain AIFC - AIFC-lyd - AIFC-Audio - ήχος AIFC - AIFC audio - AIFC-sondosiero - sonido AIFC - AIFC audioa - AIFC-ääni - AIFC ljóður - audio AIFC - fuaim AIFC - son AIFC - שמע AIFC - AIFC audio - AIFC hang - Audio AIFC - Audio AIFC - AIFC オーディオ - AIFC აუდიო - AIFC аудиосы - AIFC 오디오 - AIFC garso įrašas - AIFC audio - Audio AIFC - AIFC-lyd - AIFC-audio - AIFC-lyd - Plik dźwiękowy AIFC - áudio AIFC - Áudio AIFC - Fișier audio AIFC - аудио AIFC - Zvuk AIFC - Zvočna datoteka AIFC - Audio AIFC - AIFC звучни запис - AIFC-ljud - звук AIFC - Âm thanh AIFC - AIFC 音频 - AIFC 音訊 - AIFC - Audio Interchange File format Compressed - - - - - - - - - - AIFF/Amiga/Mac audio - AIFF/Amiga/Mac سمعي - AIFF/Amiga/Mac audio faylı - Aŭdyjo AIFF/Amiga/Mac - Аудио — AIFF/Amiga/Mac - àudio AIFF/Amiga/Mac - Zvuk AIFF/Amiga/Mac - Sain AIFF/Amiga/Mac - AIFF-/Amiga-/Maclyd - AIFF/Amiga/Mac-Audio - ήχος AIFF/Amiga/Mac - AIFF/Amiga/Mac audio - AIFF/Amiga/Mac-sondosiero - sonido AIFF/Amiga/Mac - AIFF/Amiga/Mac audioa - AIFF/Amiga/Mac-ääni - AIFF/Amiga/Mac ljóður - audio AIFF/Amiga/Mac - fuaim AIFF/Amiga/Mac - son AIFF/Amiga/Mac - שמע AIFF/Amiga/Mac - AIFF/Amiga/Mac audio - AIFF/Amiga/Mac hang - Audio AIFF/Amiga/Mac - Audio AIFF/Amiga/Mac - AIFF/Amiga/Mac オーディオ - AIFF/Amiga/Mac აუდიო - AIFF/Amiga/Mac аудиосы - AIFF/Amiga/Mac 오디오 - AIFF/Amiga/Mac garso įrašas - AIFF/Amiga/Mac audio - Audio AIFF/Amiga/Mac - AIFF/Amiga/Mac-lyd - AIFF/Amiga/Mac-audio - AIFF/Amiga/Mac-lyd - Plik dźwiękowy AIFF/Amiga/Mac - áudio AIFF/Amiga/Mac - Áudio AIFF/Amiga/Mac - Audio AIFF/Amiga/Mac - аудио AIFF/Amiga/Mac - Zvuk AIFF/Amiga/Mac - Zvočna datoteka AIFF/Amiga/Mac - Audio AIFF/Amiga/Mac - AIFF/Амига/Мекинтош звучни запис - AIFF/Amiga/Mac-ljud - звук AIFF/Amiga/Mac - Âm thanh AIFF/Amiga/Mac - AIFF/Amiga/Mac 音频 - AIFF/Amiga/Mac 音訊 - AIFF - Audio Interchange File Format - - - - - - - - - - Monkey's audio - Monkey سمعي - Aŭdyjo Monkey's - Аудио — Monkey - àudio Monkey - Zvuk Monkey's - Monkeys lyd - Monkey's-Audio - ήχος Monkey's - Monkey's audio - sonido Monkey - Monkey audioa - Monkey's Audio -ääni - Monkey's ljóður - audio Monkey - fuaim Monkey's - son de Monkey - שמע של Monkey's - Monkey hang - Audio Monkey - Audio Monkey's - Monkey's オーディオ - Monkey аудиосы - Monkey's 오디오 - Monkey garso įrašas - Monkey's audio - Monkey's-lyd - Monkey's-audio - Monkey's Audio-lyd - Plik dźwiękowy Monkey's Audio - Áudio Monkey's - Audio Monkey's - аудио Monkey's - Zvuk Monkey's - Zvočna datoteka Monkey - Audio Monkey's - Monkey's audio - звук Monkey's - Âm thanh cua Monkey - Monkey's audio 音频 - Monkey's 音訊 - - - - - - - Impulse Tracker audio - Impulse Tracker سمعي - Impulse Tracker audio faylı - Aŭdyjo Impulse Tracker - Аудио — Impulse Tracker - àudio d'Impulse Tracker - Zvuk Impulse Tracker - Sain Impulse Tracker - Impulse Tracker-lyd - Impulse-Tracker-Audio - ήχος Impulse Tracker - Impulse Tracker audio - Sondosiero de Impulse Tracker - sonido Impulse Tracker - Impulse Tracker audioa - Impulse Tracker -ääni - Impulse Tracker ljóður - audio Impulse Tracker - fuaim Impulse Tracker - son de Impulse Tracker - שמע של Impulse Tracker - Impulse Tracker audio - Impulse Tracker hang - Audio Impulse Tracker - Audio Impulse Tracker - Impulse Tracker オーディオ - Impulse Tracker аудиосы - Impulse Tracker 오디오 - Impulse Tracker garso įrašas - Impulse Tracker audio - Audio Impulse Tracker - Impulse Tracker-lyd - Impulse Tracker-audio - Impulse Tracker lyd - Plik dźwiękowy Impulse Tracker - áudio Impulse Tracker - Áudio Impulse Tracker - Audio Impulse Tracker - аудио Impulse Tracker - Zvuk Impulse Tracker - Zvočna datoteka Impulse Tracker - Audio Impulse Tracker - Impulse Tracker звучни запис - Impulse Tracker-ljud - звук Impulse Tracker - Âm thanh Impulse Tracker - Impulse Tracker 音频 - Impulse Tracker 音訊 - - - - - - - FLAC audio - FLAC سمعي - Aŭdyjo FLAC - Аудио — FLAC - àudio FLAC - Zvuk FLAC - FLAC-lyd - FLAC-Audio - Ήχος FLAC - FLAC audio - FLAC-sondosiero - sonido FLAC - FLAC audioa - FLAC-ääni - FLAC ljóður - audio FLAC - fuaim FLAC - son FLAC - קובץ שמע מסוג FLAC - FLAC audio - FLAC hang - Audio FLAC - Audio FLAC - FLAC オーディオ - FLAC აუდიო - FLAC аудиосы - FLAC 오디오 - FLAC garso įrašas - FLAC audio - Audio FLAC - FLAC-lyd - FLAC-audio - FLAC-lyd - Plik dźwiękowy FLAC - áudio FLAC - Áudio FLAC - Audio FLAC - аудио FLAC - Zvuk FLAC - Zvočna datoteka Flac - Audio FLAC - FLAC звучни запис - FLAC-ljud - звук FLAC - Âm thanh FLAC - FLAC 音频 - FLAC 音訊 - - - - - - - - WavPack audio - WavPack سمعي - Aŭdyjo WavPack - Аудио — WavPack - àudio WavPack - Zvuk WavPack - WavPack-lyd - WavPack-Audio - ήχος WavePack - WavPack audio - WavPack-sondosiero - sonido WavPack - WavPack audioa - WavPack-ääni - WavPack ljóður - audio WavPack - fuaim WavPack - son WavPack - שמע WavPack - WavPack audio - WavPack hang - Audio WavPack - Audio WavPack - WavPack オーディオ - WavPack аудиосы - WavPack 오디오 - WavPack garso įrašas - WavPack audio - WavPack-lyd - WavPack-audio - WavPack-lyd - Plik dźwiękowy WavPack - Áudio WavPack - Audio WavPack - аудио WavPack - Zvuk WavPack - Zvočna datoteka WavPack - Audio WavPack - WavPack-ljud - звук WavPack - Âm thanh WavPack - WavPack 音频 - WavPack 音訊 - - - - - - - - WavPack audio correction file - ملف تصحيح WavPack السمعي - Fajł aŭdyjokarekcyi WavPack - Файл за корекции на аудио — WavPack - fitxer de correcció d'àudio WavPack - Opravný zvukový soubor WavPack - WavPack-lydkorrektionsfil - WavPack-Audiokorrekturdatei - αρχείο διόρθωσης ήχου WavePack - WavPack audio correction file - archivo de corrección de sonido WavPack - WavPack audio-zuzenketaren fitxategia - WavPack-äänikorjaustiedosto - WavPack ljóðrættingarfíla - fichier de correction audio WavPack - comhad cheartú fhuaim WavPack - ficheiro de corrección de son WavPack - קובץ תיקון שמע של WavPack - WavPack hangjavítási fájl - Berkas koreksi audio WavPack - File correzione audio WavPack - WavPack オーディオコレクションファイル - WavPack аудио түзету файлы - WavPack 오디오 교정 파일 - WavPack garso korekcijos failas - WavPack audio korekciju datne - WavPack lydkorrigeringsfil - WavPack-audio-correctiebestand - WawPack lydopprettingsfil - Plik korekcji dźwięku WavPack - Arquivo de correção de áudio WavPack - Fișier audio de corecție WavPack - файл коррекции аудио WavPack - Opravný zvukový súbor WavPack - popravljalna zvočna datoteka WavPack - File korrigjgimi audio WavPack - WavPack-ljudkorrigeringsfil - файл корекції звуку WavPack - Tập tin sửa chữa âm thanh WavPack - WavPack 音频校正文档 - WavPack 音訊校正檔 - - - - - - - MIDI audio - MIDI سمعي - MIDI audio faylı - Aŭdyjo MIDI - Аудио — MIDI - àudio MIDI - Zvuk MIDI - Sain MIDI - MIDI-lyd - MIDI-Audio - ήχος MIDI - MIDI audio - MIDI-sondosiero - sonido MIDI - MIDI audioa - MIDI-ääni - MIDI ljóður - audio MIDI - fuaim MIDI - son MIDI - שמע MIDI - MIDI audio - MIDI hang - Audio MIDI - Audio MIDI - MIDI オーディオ - MIDI аудиосы - 미디 오디오 - MIDI garso įrašas - MIDI audio - Audio MIDI - MIDI-lyd - MIDI-audio - MIDI-lyd - Plik dźwiękowy MIDI - áudio MIDI - Áudio MIDI - Audio MIDI - аудио MIDI - Zvuk MIDI - Zvočna datoteka MIDI - Audio MIDI - MIDI звучни запис - MIDI-ljud - звук MIDI - Âm thanh MIDI - MIDI 音频 - MIDI 音訊 - - - - - - - - - - compressed Tracker audio - Tracker سمعي مضغوط - aŭdyjo skampresavanaha Trackera - Аудио — Tracker, компресирано - àudio Tracker comprimit - Komprimovaný zvuk Tracker - Trackerkomprimeret lyd - Komprimiertes Tracker-Audio - συμπιεσμένος ήχος Tracker - compressed Tracker audio - tracker de sonido comprimido - konprimitutako Tracker audioa - pakattu Tracker-ääni - stappað Tracker ljóður - audio Tracker compressé - fuaim chomhbhrúite Tracker - son comprimido de Tracker - שמע גשש מכווץ - komprimirani Tracker audio - tömörített Tracker hang - audio Tracker terkompresi - Audio compresso Tracker - 圧縮 Tracker オーディオ - сығылған Tracker аудиосы - 압축된 Tracker 오디오 - suglaudintas Tracker garso įrašas - saspiests Tracker audio - ingepakte Tracker-audio - komprimert Tracker-lyd - Skompresowany plik dźwiękowy Tracker - Áudio Tracker compactado - Tracker audio comprimat - аудио Tracker (сжатое) - Komprimovaný zvuk Tracker - Skrčena zvočna datoteka Tracker - Audio Tracker e kompresuar - komprimerat Tracker-ljud - стиснутий звук Tracker - âm thanh Tracker đã nén - 压缩的 Tracker 音频 - 壓縮版 Tracker 音訊 - - - - - - - AAC audio - AAC - Advanced Audio Coding - - - - - - - - MPEG-4 audio - MPEG-4 سمعي - Aŭdyjo MPEG-4 - Аудио — MPEG-4 - àudio MPEG-4 - Zvuk MPEG-4 - MPEG4-lyd - MPEG-4-Audio - ήχος MPEG-4 - MPEG-4 audio - MPEG4-sondosiero - sonido MPEG-4 - MPEG-4 audioa - MPEG-4-ääni - MPEG-4 ljóður - audio MPEG-4 - fuaim MPEG-4 - son MPEG-4 - שמע MPEG-4 - MPEG-4 audio - MPEG-4 hang - Audio MPEG-4 - Audio MPEG-4 - MPEG-4 オーディオ - MPEG-4 აუდიო - MPEG-4 аудиосы - MPEG-4 오디오 - MPEG-4 garso įrašas - MPEG-4 audio - MPEG-4-lyd - MPEG4-audio - MPEG-4-lyd - Plik dźwiękowy MPEG-4 - Áudio MPEG-4 - Audio MPEG-4 - аудио MPEG-4 - Zvuk MPEG-4 - Zvočna datoteka MPEG-4 - Audio MPEG-4 - MPEG-4-ljud - звук MPEG-4 - Âm thanh MPEG-4 - MPEG-4 音频 - MPEG-4 音訊 - - - - - - - - - MPEG-4 video - MPEG-4 مرئي - Videa MPEG-4 - Видео — MPEG-4 - vídeo MPEG-4 - Video MPEG-4 - MPEG4-video - MPEG-4-Video - βίντεο MPEG-4 - MPEG-4 video - MPEG-4-video - vídeo MPEG-4 - MPEG-4 bideoa - MPEG-4-video - MPEG-4 video - vidéo MPEG-4 - físeán MPEG-4 - vídeo MPEG-4 - וידאו MPEG-4 - MPEG-4 video - MPEG-4 videó - Video MPEG-4 - Video MPEG-4 - MPEG-4 動画 - MPEG-4 ვიდეო - MPEG-4 видеосы - MPEG-4 비디오 - MPEG-4 vaizdo įrašas - MPEG-4 video - MPEG-4-film - MPEG4-video - MPEG-4-video - Plik wideo MPEG-4 - Vídeo MPEG-4 - Video MPEG-4 - видео MPEG-4 - Video MPEG-4 - Video datoteka MPEG-4 - Video MPEG-4 - MPEG-4-video - відеокліп MPEG-4 - Ảnh động MPEG-4 - MPEG-4 视频 - MPEG-4 視訊 - - - - - - - - - - - - - - - MPEG-4 audio book - كتاب MPEG-4 السمعي - Aŭdyjokniha MPEG-4 - Аудио книга — MPEG-4 - llibre d'àudio MPEG-4 - Zvuková kniha MPEG-4 - MPEG4-lydbog - MPEG-4-Hörbuch - ηχητικό βιβλίο MPEG-4 - MPEG-4 audio book - MPEG-4-sonlibro - audiolibro en MPEG-4 - MPEG-4 audio-liburua - MPEG-4-äänikirja - MPEG-4 ljóðbók - livre audio MPEG-4 - leabhar fhuaim MPEG-4 - sonlibro de MPEG-4 - ספר דיגיטלי MPEG-4 - MPEG-4 audio knjiga - MPEG-4 hangoskönyv - Buku audio MPEG-4 - Audiolibro MPEG-4 - MPEG-4 オーディオブック - MPEG-4 აუდიოწიგნი - MPEG-4 аудио кітабы - MPEG-4 오디오북 - MPEG-4 garso knyga - MPEG-4 audio grāmata - MPEG-4-lydbok - MPEG4-audioboek - MPEG-4-lydbok - Książka dźwiękowa MPEG-4 - Áudio livro MPEG-4 - Carte audio MPEG-4 - аудиокнига MPEG-4 - Zvuková kniha MPEG-4 - Zvočna knjiga MPEG-4 - Audiolibër MPEG-4 - MPEG-4-ljudbok - аудіокнига MPEG-4 - Sách âm thanh MPEG-4 - MPEG-4 有声书 - MPEG-4 音訊書 - - - - - - - - - 3GPP multimedia file - ملف وسائط متعددة 3GPP - Multymedyjny fajł 3GPP - Мултимедия — 3GPP - fitxer multimèdia 3GPP - Soubor multimédií 3GPP - 3GPP multimedie-fil - 3GPP-Multimediadatei - αρχείο πολυμέσων 3GPP - 3GPP multimedia file - archivo multimedia 3GPP - 3GPP multimediako fitxategia - 3GPP-multimediatiedosto - 3GGP margmiðlafíla - fichier multimédia 3GPP - comhad ilmheán 3GPP - ficheiro multimedia 3GPP - קובץ מולטימדיה מסוג 3GPP - 3GPP multimedijska datoteka - 3GPP multimédiafájl - Berkas multimedia 3GPP - File multimediale 3GPP - 3GPP マルチメディアファイル - 3GPP მულტიმედიური ფაილი - 3GPP мультимедиялық файлы - 3GPP 멀티미디어 파일 - 3GPP multimedijos failas - 3GPP multimediju datne - 3GPP-multimediafil - 3GPP-multimediabestand - 3GPP-multimediafil - Plik multimedialny 3GPP - Arquivo multimídia 3GPP - Fișier multimedia 3GPP - мультимедийный файл 3GPP - Súbor multimédií 3GPP - Večpredstavnostna datoteka 3GPP - File multimedial 3GPP - 3GPP-multimediafil - 3GPP multimedya dosyası - файл мультимедійних даних 3GPP - Tập tin đa phương tiện 3GPP - 3GPP 多媒体文件 - 3GPP 多媒體檔案 - 3GPP - 3rd Generation Partnership Project - - - - - - - - - - - - - - - - - - - - - - - - - 3GPP2 multimedia file - Мултимедия — 3GPP2 - fitxer multimèdia 3GPP2 - Soubor multimédií 3GPP2 - 3GPP2 multimedie-fil - 3GPP2-Multimediadatei - αρχείο πολυμέσων 3GPP2 - 3GPP2 multimedia file - archivo multimedia 3GPP2 - 3GPP2-multimediatiedosto - 3GGP2 margmiðlafíla - fichier multimédia 3GPP2 - comhad ilmheán 3GPP2 - ficheiro multimedia 3GPP2 - קובץ מולטימדיה 3GPP2 - 3GPP2 multimedijska datoteka - 3GPP2 multimédiafájl - Berkas multimedia 3GPP2 - File multimediale 3GPP2 - 3GPP2 マルチメディアファイル - 3GPP2 მულტიმედიური ფაილი - 3GPP2 мультимедиялық файлы - 3GPP2 멀티미디어 파일 - 3GPP2 multimediju datne - 3GPP2 multimedia bestand - Plik multimedialny 3GPP2 - Arquivo multimídia 3GPP2 - Fișier multimedia 3GPP2 - мультимедийный файл 3GPP2 - Súbor multimédií 3GPP2 - Večpredstavnostna datoteka 3GPP2 - 3GPP2-multimediafil - 3GPP2 multimedya dosyası - файл мультимедійних даних 3GPP2 - 3GPP2 多媒体文件 - 3GPP2 多媒體檔案 - 3GPP2 - 3rd Generation Partnership Project 2 - - - - - - - - - - - Amiga SoundTracker audio - مقتفي صوت Amiga السمعي - Aŭdyjo Amiga SoundTracker - Аудио — Amiga SoundTracker - àudio Amiga SoundTracker - Zvuk Amiga SoundTracker - Amiga SoundTracker-lyd - Amiga-SoundTracker-Audio - ήχος Amiga SoundTracker - Amiga SoundTracker audio - Sondosiero de Amiga SoundTracker - sonido de Amiga SoundTracker - Amiga soundtracker audioa - Amiga SoundTracker -ääni - Amiga SoundTracker ljóður - audio SoundTracker Amiga - fuaim Amiga SoundTracker - son de Amiga SoundTracker - קובץ שמע של Amiga SoundTracker - Amiga SoundTracker audio - Amiga SoundTracker hang - Audio Amida SoundTracker - Audio Amiga SoundTracker - Amiga SoundTracker オーディオ - Amiga SoundTracker-ის აუდიო - Amiga SoundTracker аудиосы - Amiga SoundTracker 오디오 - Amiga SoundTracker garso įrašas - Amiga SoundTracker audio - Audio Amiga Soundtracker - Amiga SoundTracker-lyd - Amiga SoundTracker-audio - Amiga soundtracker-lyd - Plik dźwiękowy Amiga SoundTracker - áudio SoundTracker do Amiga - Áudio Amiga SoundTracker - Audio Amiga SoundTracker - аудио Amiga SoundTracker - Zvuk Amiga SoundTracker - Zvočna datoteka Amiga SoundTracker - Audio Amiga SoundTracker - Амига soundtracker звук - Amiga SoundTracker-ljud - звук Amiga SoundTracker - Âm thanh Amiga SoundTracker - Amiga SoundTracker 音频 - Amiga SoundTracker 音訊 - - - - - - - - - - MP2 audio - MP2 سمعي - Aŭdyjo MP2 - Аудио — MP2 - àudio MP2 - Zvuk MP2 - MP2-lyd - MP2-Audio - ήχος MP2 - MP2 audio - MP2-sondosiero - sonido MP2 - MP2 audioa - MP2-ääni - MP2 ljóður - audio MP2 - fuaim MP2 - son MP2 - שמע MP2 - MP2 audio - MP2 hang - Audio MP2 - Audio MP2 - MP2 オーディオ - MP2 аудиосы - MP2 오디오 - MP2 garso įrašas - MP2 audio - MP2-lyd - MP2-audio - MP2-lyd - Plik dźwiękowy MP2 - Áudio MP2 - Audio MP2 - аудио MP2 - Zvuk MP2 - Zvočna datoteka MP2 - Audio MP2 - MP2-ljud - звук MP2 - Âm thanh MP2 - MP2 音频 - MP2 音訊 - - - - - MP3 audio - MP3 سمعي - MP3 audio faylı - Aŭdyjo MP3 - Аудио — MP3 - àudio MP3 - Zvuk MP3 - Sain MP3 - MP3-lyd - MP3-Audio - ήχος MP3 - MP3 audio - MP3-sondosiero - sonido MP3 - MP3 audioa - MP3-ääni - MP3 ljóður - audio MP3 - fuaim MP3 - son MP3 - שמע MP3 - MP3 audio - MP3 hang - Audio MP3 - Audio MP3 - MP3 オーディオ - MP3 აუდიო - MP3 аудиосы - MP3 오디오 - MP3 garso įrašas - MP3 audio - Audio MP3 - MP3-lyd - MP3-audio - MP3-lyd - Plik dźwiękowy MP3 - áudio MP3 - Áudio MP3 - Audio MP3 - аудио MP3 - Zvuk MP3 - Zvočna datoteka MP3 - Audio MP3 - MP3 звучни запис - MP3-ljud - звук MP3 - Âm thanh MP3 - MP3 音频 - MP3 音訊 - - - - - - - - - - - - MP3 audio (streamed) - MP3 سمعي (تدفق) - Aŭdyjo MP3 (płyń) - Аудио — MP3, поточно - àudio MP3 (flux) - Zvuk MP3 (proud) - MP3-lyd (strøm) - MP3-Audio (Stream) - ήχος MP3 (εκπεμπόμενος) - MP3 audio (streamed) - MP3-sondosiero (fluigate) - sonido MP3 (en flujo) - MP3 audioa (korrontea) - MP3-ääni (virtaus) - MP3 ljóður (streymað) - audio MP3 (flux) - fuaim MP3 (sruthaithe) - son MP3 (en stream) - שמע MP3 (מוזרם) - MP3 hang (sugárzott) - Audio MP3 (stream) - Audio MP3 (in streaming) - MP3 オーディオ (ストリーム) - MP3 აუდიო (ნაკადი) - MP3 аудиосы (ағымдық) - MP3 오디오 (스트림) - MP3 garso įrašas (transliuojamas) - MP3 audio (straumēts) - Audio MP3 (aliran) - MP3-lyd (streaming) - MP3-audio (gestreamd) - Strauma MP3-lyd - Dźwięk MP3 (strumień) - áudio MP3 (em fluxo) - Áudio MP3 (em fluxo) - Audio MP3 (flux) - аудио MP3 (потоковое) - Zvuk MP3 (streamovaný) - Zvočna datoteka MP3 (pretočna) - Audio MP3 (streamed) - MP3 звучни запис (непрекидан) - MP3-ljud (flöde) - звук MP3 (потоковий) - Âm thanh MP3 (chạy luồng) - MP3 流音频 - MP3 音訊 (串流) - - - - - - - - - - - - - - - HTTP Live Streaming playlist - قائمة بث HTTP حية - Списък за изпълнение — поток по HTTP - llista de reproducció en temps real HTTP - Seznam skladeb HTTP Live Streaming - Afspilningsliste til HTTP-livestrøm - HTTP Live-Streaming-Wiedergabeliste - HTTP Live Streaming playlist - lista de reproducción de flujo en directo HTTP - HTTP zuzeneko korrontearen erreprodukzio-zerrenda - HTTP beinleiðis streymaður avspælingarlisti - liste de lecture de flux HTTP Live - seinmliosta sruthaithe bheo HTTP - lista de reprodución de fluxo HTTP - רשימת השמעה הזרימה של HTTP - HTTP élő lejátszólista - Daftar putar HTTP Live Streaming - Scaletta Live Steaming HTTP - HTTP ライブストリーミング再生リスト - HTTP тірі ағым ойнау тізімі - HTTP 라이브 스트리밍 재생 목록 - HTTP tiesioginio transliavimo grojaraštis - HTTP dzīvās straumēšanas repertuārs - HTTP Live Streaming afspeellijst - Lista odtwarzania strumieniowego na żywo HTTP - Lista de Reprodução Streaming ao Vivo de HTTP - Listă de redare difuzată ca flux HTTP - список воспроизведения HTTP-потока - Seznam predvajanja živega pretoka HTTP - HTTP Live Streaming-spellista - список відтворення HTTP Live Streaming - HTTP 直播流播放列表 - HTTP 即時串流播放清單 - - - - - - - - - - - Microsoft ASX playlist - قائمة تشغيل مايكروسوفت ASX - Śpis Microsoft ASX - Списък за изпълнение — Microsoft ASX - llista de reproducció ASX de Microsoft - Seznam skladeb Microsoft ASX - Microsoft ASX-afspilningsliste - Microsoft-ASX-Wiedergabeliste - λίστα αναπαραγωγής Microsoft ASX - Microsoft ASX playlist - lista de reproducción ASX de Microsoft - Microsoft ASX erreprodukzio-zerrenda - Microsoft ASX -soittolista - Microsoft ASX avspælingarlisti - liste de lecture Microsoft ASX - seinmliosta Microsoft ASX - lista de reprodución Microsoft ASX - רשימת השמעה ASX (מיקרוסופט) - Microsoft ASX popis za reprodukciju - Microsoft ASX lejátszólista - Senarai putar Microsoft ASX - Scaletta Microsoft ASX - Microsoft ASX 再生リスト - Microsoft-ის ASX რეპერტუარი - Microsoft ASX ойнау тізімі - 마이크로소프트 ASX 재생 목록 - Microsoft ASX grojaraštis - Microsoft ASX repertuārs - Microsoft ASX-spilleliste - Microsoft ASX-afspeellijst - Microsoft ASX-speleliste - Lista odtwarzania Microsoft ASX - Lista de reprodução do Microsoft ASX - Listă redare Microsoft ASX - список воспроизведения Microsoft ASX - Zoznam skladieb Microsoft ASX - Seznam predvajanja Microsoft ASX - Listë titujsh Microsoft ASF - Microsoft ASX-spellista - список відтворення ASX Microsoft - Danh mục nhạc Microsoft ASX - Microsoft ASX 播放列表 - 微軟 ASX 播放清單 - - - - - - - - - - - - - - - - - PSF audio - PSF سمعي - Aŭdyjo PSF - Аудио — PSF - àudio PSF - Zvuk PSF - PSF-lyd - PSF-Audio - ήχος PSF - PSF audio - PSF-sondosiero - sonido PSF - PSF audioa - PSF-ääni - PSF ljóður - audio PSF - fuaim PSF - son PSF - שמע PSF - PSF hang - Audio PSF - Audio PSF - PSF オーディオ - PSF аудиосы - PSF 오디오 - PSF garso įrašas - PSF audio - PSF-lyd - PSF-audio - PSF-lyd - Plik dźwiękowy PSF - Áudio PSF - Audio PSF - аудио PSF - Zvuk PSF - Zvočna datoteka PSF - Audio PSF - PSF-ljud - звук PSF - Âm thanh PSF - PSF 音频 - PSF 音訊 - PSF - Portable Sound Format - - - - - - - MiniPSF audio - MiniPSF سمعي - Aŭdyjo MiniPSF - Аудио — MiniPSF - àudio MiniPSF - Zvuk MiniPSF - MiniPSF-lyd - MiniPSF-Audio - ήχος MiniPSF - MiniPSF audio - MiniPSF-sondosiero - sonido MiniPSF - MiniPSF audioa - MiniPSF-ääni - MiniPSF ljóður - audio MiniPSF - fuaim MiniPSF - son MiniPSF - שמע של MiniPSP - MiniPSF audio - MiniPSF hang - Audio MiniPSF - Audio MiniPSF - MiniPSF オーディオ - MiniPSF-ის აუდიო - MiniPSF аудиосы - MiniPSF 오디오 - MiniPSF garso įrašas - MiniPSF audio - MiniPSF-lyd - MiniPSF-audio - MiniPSF-lyd - Plik dźwiękowy MiniPSF - Áudio MiniPSF - Audio MiniPSF - аудио MiniPSF - Zvuk MiniPSF - Zvočna datoteka MiniPSF - Audio MiniPSF - MiniPSF-ljud - звук MiniPSF - Âm thanh MiniPSF - MiniPSF 音频 - MiniPSF 音訊 - MiniPSF - Miniature Portable Sound Format - - - - - PSFlib audio library - مكتبة PSFlib السمعية - Aŭdyjobiblijateka PSFlib - Аудио библиотека — PSFlib - biblioteca d'àudio PSFlib - Zvuková knihovna PSFlib - PSFlib-lydbibliotek - PSFlib-Audiobibliothek - βιβλιοθήκη ήχου PSFlib - PSFlib audio library - biblioteca de sonido PSFlib - PSFlib audioaren liburutegia - PSFlib-äänikirjasto - PSFlib ljóðsavn - bibliothèque audio PSFlib - leabharlann fhuaim PSFlib - Biblioteca de son PSFlib - ספריית שמע PSFlib - PSFlib hanggyűjtemény - Pustaka audio PSFlib - Libreria audio PSFlib - PSFlib オーディオライブラリ - PSFlib аудио жинағы - PSFlib 오디오 라이브러리 - PSFlib garso biblioteka - PSFlib fonotēka - PSFlib-lydbibliotek - PSFlib-audiobibliotheek - PSFlib lydbibliotek - Biblioteka dźwiękowa PSFlib - Biblioteca de áudio PSFlib - Bibliotecă audio PSFlib - фонотека PSFlib - Zvuková knižnica PSFlib - Zvočna knjižnica PSFlib - Librari audio PSFlib - PSFlib-ljudbibliotek - аудіобібліотека PSFlib - Thư viện âm thanh PSFlib - PSFlib 音频库文件 - PSFlib 音訊庫 - PSFlib - Portable Sound Format Library - - - - - Windows Media audio - Windows Media سمعي - Aŭdyjo Windows Media - Аудио — Windows Media - àudio Windows Media - Zvuk Windows Media - Windows Media-lyd - Windows-Media-Audio - ήχος Windows Media - Windows Media audio - sonido de Windows Media - Windows Media audioa - Windows Media -ääni - Windows Media ljóður - audio Windows Media - fuaim Windows Media - son de Windows Media - שמע של Windows Media - Windows Media audio - Windows Media hang - Audio Windows Media - Audio Windows Media - Windows Media オーディオ - Windows Media аудиосы - Windows 미디어 오디오 - Windows Media garso įrašas - Windows Media audio - Windows Media lyd - Windows Media-audio - Windows Media-lyd - Plik dźwiękowy Windows Media - Áudio do Windows Media - Audio Windows Media - аудио Windows Media - Zvuk Windows Media - Zvočna datoteka Windows Media - Audio Windows Media - Windows Media-ljud - звук Windows Media - Âm thanh Windows Media - Windows Media 音频 - Windows Media 音訊 - - - - - - Musepack audio - Musepack سمعي - Aŭdyjo Musepack - Аудио — Musepack - àudio Musepack - Zvuk Musepack - Musepacklyd - Musepack-Audio - ήχος Musepack - Musepack audio - sonido Musepack - Musepack audioa - Musepack-ääni - Musepack ljóður - audio Musepack - fuaim Musepack - son de Musepack - שמע של Musepack - Musepack audio - Musepack hang - Audio Musepack - Audio Musepack - Musepack オーディオ - Musepack аудиосы - Musepack 오디오 - Musepack garso įrašas - Musepack audio - Musepack-lyd - Musepack-audio - Musepack-lyd - Plik dźwiękowy Musepack - Áudio Musepack - Audio Musepack - аудио Musepack - Zvuk Musepack - Zvočna datoteka Musepack - Audio Musepack - Musepack-ljud - звук Musepack - Âm thanh Musepack - Musepack 音频 - Musepack 音訊 - - - - - - - - - RealAudio document - مستند RealAudio - Dakument RealAudio - Документ — RealAudio - document RealAudio - Dokument RealAudio - RealAudio-dokument - RealAudio-Dokument - έγγραφο RealAudio - RealAudio document - RealAudio-dokumento - documento RealAudio - RealAudio dokumentua - RealAudio-asiakirja - RealAudio skjal - document RealAudio - cáipéis RealAudio - documento Realson - מסמך של RealAudio - RealAudio dokument - RealAudio dokumentum - Dokumen RealAudio - Documento RealAudio - RealAudio ドキュメント - RealAudio құжаты - RealAudio 문서 - RealAudio dokumentas - RealAudio dokuments - RealAudio-dokument - RealAudio-document - RealAudio-dokument - Dokument RealAudio - Documento RealAudio - Document RealAudio - документ RealAudio - Dokument RealAudio - Dokument RealAudio - Dokument RealAudio - RealAudio-dokument - документ RealAudio - Tài liệu âm thanh RealAudio - RealAudio 文档 - RealAudio 文件 - - - - - - - RealMedia Metafile - ملف تعريف RealMedia - Metafajł RealMedia - Метафайл — RealMedia - metafitxer RealMedia - RealMedia Metafile - RealMedia-metafil - RealMedia-Metadatei - Metafile RealMedia - RealMedia Metafile - metarchivo RealMedia - RealMedia metafitxategia - RealMedia-metatiedosto - RealMedia metafíla - métafichier RealMedia - meiteachomhad RealMedia - Metaficheiro RealMedia - קובץ מטא של RealMedia - RealMedia metafájl - RealMedia Metafile - Metafile RealMedia - RealMedia メタファイル - RealMedia метафайлы - RealMedia 메타파일 - RealMedia metafailas - RealMedia metadatne - RealMedia-metafil - RealMedia-metabestand - RealMedia-metafil - Metaplik RealMedia - Meta arquivo do RealMedia - Metafișier RealMedia - мета-файл RealMedia - RealMedia Metafile - Metadatoteka RealMedia - Metafile RealMedia - RealMedia-metafil - метафайл RealMedia - Siêu tập tin RealMedia - RealMedia 元文件 - RealMedia 中介檔 - - - - RealVideo document - مستند RealVideo - Dakument RealVideo - Документ — RealVideo - document RealVideo - Dokument RealVideo - RealAudio-dokument - RealVideo-Dokument - έγγραφο RealVideo - RealVideo document - RealVideo-dokumento - documento RealVideo - RealVideo dokumentua - RealVideo-asiakirja - RealVideo skjal - document RealVideo - cáipéis RealVideo - documento RealVideo - מסמך של RealVideo - RealVideo dokument - RealVideo dokumentum - Dokumen RealVideo - Documento RealVideo - RealVideo ドキュメント - RealVideo құжаты - RealVideo 문서 - RealVideo dokumentas - RealVideo dokuments - RealAudio-dokument - RealVideo-document - RealVideo-dokument - Dokument RealVideo - Documento RealVideo - Document RealVideo - документ RealVideo - Dokument RealVideo - Video datoteka RealVideo - Dokument RealVideo - RealVideo-dokument - документ RealVideo - Tài liệu ảnh động RealVideo - RealAudio 文档 - RealVideo 文件 - - - - - - RealMedia document - مستند RealMedia - Dakument RealMedia - Документ — RealMedia - document RealMedia - Dokument RealMedia - RealMedia-dokument - RealMedia-Dokument - έγγραφο RealMedia - RealMedia document - RealMedia-dokumento - documento RealMedia - RealMedia dokumentua - RealMedia-asiakirja - RealMedia skjal - document RealMedia - cáipéis RealMedia - documento RealMedia - מסמך של RealMedia - RealMedia dokument - RealMedia dokumentum - Dokumen RealMedia - Documento RealMedia - RealMedia ドキュメント - RealMedia құжаты - RealMedia 문서 - RealMedia dokumentas - RealMedia dokuments - RealMedia-dokument - RealMedia-document - RealMedia-dokument - Dokument RealMedia - Documento RealMedia - Document RealMedia - документ RealMedia - Dokument RealMedia - Dokument RealMedia - Dokument RealMedia - RealMedia-dokument - документ RealMedia - Tài liệu RealMedia - RealMedia 文档 - RealMedia 文件 - - - - - - - - - - - - - RealPix document - مستند RealPix - Dakument RealPix - Документ — RealPix - document RealPix - Dokument RealPix - RealPix-dokument - RealPix-Dokument - έγγραφο RealPix - RealPix document - RealPix-dokumento - documento RealPix - RealPix dokumentua - RealPix-asiakirja - RealPix skjal - document RealPix - cáipéis RealPix - documento RealPix - מסמך של RealPix - RealPix dokument - RealPix dokumentum - Dokumen RealPix - Documento RealPix - RealPix ドキュメント - RealPix құжаты - RealPix 문서 - RealPix dokumentas - RealPix dokuments - RealPix-dokument - RealPix-document - RealPix-dokument - Dokument RealPix - Documento RealPix - Document RealPix - документ RealPix - Dokument RealPix - Dokument RealPix - Dokument RealPix - RealPix-dokument - документ RealPix - Tài liệu ảnh RealPix - RealPix 文档 - RealPix 文件 - - - - RealText document - مستند RealText - Dakument RealText - Документ — RealText - document RealText - Dokument RealText - RealText-dokument - RealText-Dokument - έγγραφο RealText - RealText document - RealText-dokumento - documento RealText - RealText dokumentua - RealText-asiakirja - RealText skjal - document RealText - cáipéis RealText - documento RealText - מסמך של RealText - RealText dokument - RealText dokumentum - Dokumen RealText - Documento RealText - RealText ドキュメント - RealText құжаты - RealText 문서 - RealText dokumentas - RealText dokuments - RealText-dokument - RealText-document - RealText-dokument - Dokument RealText - Documento RealText - Document RealText - документ RealText - Dokument RealText - Dokument RealText - Dokument RealText - RealText-dokument - документ RealText - Tài liệu văn bản RealText - RealText 文档 - RealText 文件 - - - - RIFF audio - RIFF سمعي - RIFF audio faylı - Aŭdyjo RIFF - Аудио — RIFF - àudio RIFF - Zvuk RIFF - Sain RIFF - RIFF-lyd - RIFF-Audio - ήχος RIFF - RIFF audio - RIFF-sondosiero - sonido RIFF - RIFF audioa - RIFF-ääni - RIFF ljóð - audio RIFF - fuaim RIFF - son RIFF - שמע RIFF - RIFF audio - RIFF-kép - Audio RIFF - Audio RIFF - RIFF オーディオ - RIFF аудиосы - RIFF 오디오 - RIFF garso įrašas - RIFF audio - Audio RIFF - RIFF-lyd - RIFF-audio - RIFF-lyd - Plik dźwiękowy RIFF - áudio RIFF - Áudio RIFF - Audio RIFF - аудио RIFF - Zvuk RIFF - Zvočna datoteka RIFF - Audio RIFF - RIFF звучни запис - RIFF-ljud - звук RIFF - Âm thanh RIFF - RIFF 音频 - RIFF 音訊 - - - - - - - Scream Tracker 3 audio - Scream Tracker 3 سمعي - Scream Tracker 3 audio faylı - Aŭdyjo Scream Tracker 3 - Аудио — Scream Tracker 3 - àudio de Scream Tracker 3 - Skladba Scream Tracker 3 - Sain Scream Tracker 3 - Scream Tracker 3-lyd - Scream-Tracker-3-Audio - ήχος Scream Tracker 3 - Scream Tracker 3 audio - Sondosiero de Scream Tracker 3 - sonido Scream Tracker 3 - Scream Tracker 3 audioa - Scream Tracker 3 -ääni - Scream Tracker 3 ljóður - audio Scream Tracker 3 - fuaim Scream Tracker 3 - son Scream Tracker 3 - שמע של Scream Tracker 3 - Scream Tracker 3 audio - Scream Tracker 3 hang - Audio Scream Tracker 3 - Audio Scream Tracker 3 - Scream Tracker 3 オーディオ - Scream Tracker 3 аудиосы - Scream Tracker 3 오디오 - Scream Tracker 3 garso įrašas - Scream Tracker 3 audio - Audio Scream Tracker 3 - Scream Tracker 3-lyd - Scream Tracker 3-audio - Sream Tracker 3 lyd - Plik dźwiękowy Scream Tracker 3 - áudio Scream Tracker 3 - Áudio Scream Tracker 3 - Audio Scream Tracker 3 - аудио Scream Tracker 3 - Skladba Scream Tracker 3 - Zvočna datoteka Scream Tracker 3 - Audio Scream Tracker 3 - Scream Tracker 3 звучни запис - Scream Tracker 3-ljud - звук Scream Tracker 3 - Âm thanh Scream Tracker 3 - Scheme Tracker 3 音频 - Scream Tracker 3 音訊 - - - - - - - MP3 ShoutCast playlist - قائمة تشغيل MP3 ShoutCast - Śpis piesień dla tranślacyi MP3 - Списък за изпълнение — MP3 ShoutCast - llista de reproducció MP3 ShoutCast - Seznam skladeb MP3 ShoutCast - MP3 ShoutCast-afspilningsliste - MP3-ShoutCast-Wiedergabeliste - Λίστα αναπαραγωγής MP3 ShoutCast - MP3 ShoutCast playlist - MP3-ludlisto de ShoutCast - lista de reproducción MP3 ShoutCast - MP3 ShoutCast erreprodukzio-zerrenda - MP3 ShoutCast -soittolista - MP3 ShoutCast avspælingarlisti - liste de lecture MP3 ShoutCast - seinmliosta MP3 ShoutCast - lista de reprodución MP3 de ShoutCast - רשימת השמעה MP3 של ShoutCast - MP3 ShoutCast popis za reprodukciju - MP3 ShoutCast-lejátszólista - Senarai putar MP3 ShoutCast - Scaletta MP3 ShoutCast - MP3 ShoutCast 再生リスト - MP3 ShoutCast ойнау тізімі - MP3 ShoutCast 재생 목록 - MP3 ShoutCast grojaraštis - MP3 ShoutCast repertuārs - Senaraimain ShoutCast MP3 - MP3 ShoutCast-spilleliste - MP3 ShoutCast-afspeellijst - MP3 ShoutCast-speleliste - Lista odtwarzania MP3 ShoutCast - lista de reprodução MP3 ShoutCast - Lista de reprodução MP3 ShoutCast - Listă MP3 ShoutCast - список воспроизведения MP3 ShoutCast - Zoznam skladieb MP3 ShoutCast - Seznam predvajanja MP3 ShoutCast - Listë titujsh MP3 ShoutCast - MP3 ShoutCast списак песама - MP3 ShoutCast-spellista - список програвання MP3 ShoutCast - Danh mục nhạc MP3 ShoutCast - MP3 ShoutCast 播放列表 - MP3 ShoutCast 播放清單 - - - - - - - - - - Scream Tracker audio - Scream Tracker سمعي - Scream Tracker audio faylı - Aŭdyjo Scream Tracker - Аудио — Scream Tracker - àudio de Scream Tracker - Skladba Scream Tracker - Sain Scream Tracker - Scream Tracker-lyd - Scream-Tracker-Audio - ήχος Scream Tracker - Scream Tracker audio - Sondosiero de Scream Tracker - sonido Scream Tracker - Scream Tracker audioa - Scream Tracker -ääni - Scream Tracker ljóður - audio Scream Tracker - fuaim Scream Tracker - son Scream Tracker - שמע של Scream Tracker - Scream Tracker audio - Scream Tracker hang - Audio Scream Tracker - Audio Scream Tracker - Scream Tracker オーディオ - Scream Tracker аудиосы - Scream Tracker 오디오 - Scream Tracker garso įrašas - Scream Tracker audio - Audio Scream Tracker - Scream Tracker-lyd - Scream Tracker-audio - Scream Tracker lyd - Plik dźwiękowy Scream Tracker - áudio Scream Tracker - Áudio Scream Tracker - Audio Scream Tracker - аудио Scream Tracker - Skladba Scream Tracker - Zvočna datoteka Scream Tracker - Audio Scream Tracker - Scream Tracker звучни запис - Scream Tracker-ljud - звук Scream Tracker - Âm thanh Scream Tracker - Scream Tracker 音频 - Scream Tracker 音訊 - - - - - - - - - VOC audio - VOC سمعي - VOC audio faylı - Aŭdyjo VOC - Аудио — VOC - àudio VOC - Zvuk VOC - Sain VOC - VOC-lyd - VOC-Audio - ήχος VOC - VOC audio - VOC-sondosiero - sonido VOC - VOC audioa - VOC-ääni - VOC ljóður - audio VOC - fuaim VOC - son VOC - שמע VOC - VOC audio - VOC hang - Audio VOC - Audio VOC - VOC オーディオ - VOC аудиосы - VOC 오디오 - VOC garso įrašas - VOC audio - Audio VOC - VOC-lyd - VOC-audio - VOC-lyd - Plik dźwiękowy VOC - áudio VOC - Áudio VOC - Audio VOC - аудио VOC - Zvuk VOC - Zvočna datoteka VOC - Audio VOC - VOC звучни запис - VOC-ljud - звук VOC - Âm thanh VOC - VOC 音频 - VOC 音訊 - - - - WAV audio - WAV سمعي - WAV audio faylı - Aŭdyjo WAV - Аудио — WAV - àudio WAV - Zvuk WAV - Sain WAV - WAV-lyd - WAV-Audio - ήχος WAV - WAV audio - WAV-sonkodo - sonido WAV - WAV audioa - WAV-ääni - WAV ljóður - audio WAV - fuaim WAV - son WAV - שמע WAV - WAV audio - WAV hang - Audio WAV - Audio WAV - WAV オーディオ - WAV аудиосы - WAV 오디오 - WAV garso įrašas - WAV audio - Audio VOC - WAV-lyd - WAV-audio - WAV-lyd - Plik dźwiękowy WAV - áudio WAV - Áudio WAV - Audio WAV - аудио WAV - Zvuk WAV - Zvočna datoteka WAV - Audio WAV - WAV звучни запис - WAV-ljud - звук WAV - Âm thanh WAV - WAV 音频 - WAV 音訊 - - - - - - - - - - Scream Tracker instrument - آلة Scream Tracker - Scream Tracker instrumenti - Instrument Scream Tracker - Инструмент — Scream Tracker - instrument de Scream Tracker - Nástroj pro Scream Tracker - Offeryn Scream Tracker - Scream Tracker-instrument - Scream-Tracker-Instrument - μουσικό όργανο Scream Tracker - Scream Tracker instrument - instrumento de Scream Tracker - instrumento Scream Tracker - Scream Tracker instrumentua - Scream Tracker -soitin - Scream Tracker ljóðføri - instrument Scream Tracker - ionstraim Scream Tracker - Instrumento Scream Tracker - כלי של Scream Tracker - Scream Tracker instrument - Scream Tracker hangszer - Instrumen Scream Tracker - Strumento Scream Tracker - Scream Tracker インストゥルメント - Scream Tracker сайманы - Scream Tracker 악기 - Scream Tracker instrumentas - Scream Tracker instrumenti - Instrumen Scream Tracker - Scream Tracker-instrument - Scream Tracker-instrument - Scream Tracker instrument - Instrument Scream Tracker - instrumento Scream Tracker - Instrumento Scream Tracker - Instrument Scream Tracker - инструмент Scream Tracker - Nástroj pre Scream Tracker - Datoteka zvoka glasbila Scream Tracker - Instrument Scream Tracker - Scream Tracker инструмент - Scream Tracker-instrument - інструмент Scream Tracker - Nhạc khí Scream Tracker - Scream Tracker 乐器 - Scream Tracker 樂器檔 - - - - - - - FastTracker II audio - FastTracker II سمعي - FastTracker II audio faylı - Aŭdyjo FastTracker II - Аудио — FastTracker II - àudio de FastTracker II - Zvuk FastTracker II - Sain FastTracker II - FastTracker II-lyd - FastTracker-II-Audio - ήχος FastTracker II - FastTracker II audio - Sondosiero de FastTracker II - sonido FastTracker II - FastTracker II.ren audioa - FastTracker II -ääni - FastTracker II ljóður - audio FastTracker II - fuaim FastTracker II - son de FastTracker II - שמע FastTracker II - FastTracker II audio - FastTracker II hang - Audio FastTracker II - Audio FastTracker II - FastTracker II オーディオ - FastTracker II-ის აუდიო - FastTracker II аудиосы - FastTracker II 오디오 - FastTracker II garso įrašas - FastTracker II audio - Audio FastTracker II - FastTracker II-lyd - FastTracker II-audio - FastTracker II lyd - Plik dźwiękowy FastTracker II - áudio FastTracker II - Áudio FastTracker II - Audio FastTracker II - аудио FastTracker II - Zvuk FastTracker II - Zvočna datoteka FastTracker II - Audio FastTracker II - FastTracker II аудио запис - FastTracker II-ljud - звук FastTracker II - Âm thanh FastTracker II - FastTracker II 音频 - FastTracker II 音訊 - - - - - - - TrueAudio audio - TrueAudio سمعي - Aŭdyjo TrueAudio - Аудио — TrueAudio - àudio TrueAudio - Zvuk TrueAudio - TrueAudio-lyd - TrueAudio-Audio - ήχος TrueAudio - TrueAudio audio - TrueAudio-sondosiero - sonido TrueAudio - TrueAudio audioa - TrueAudio-ääni - TrueAudio ljóður - audio TrueAudio - fuaim TrueAudio - son Trueson - שמע TrueAudio - TrueAudio audio - TrueAudio hang - Audio TrueAudio - Audio TrueAudio - TrueAudio オーディオ - TrueAudio аудиосы - TrueAudio 오디오 - TrueAudio garso įrašas - TrueAudio audio - TrueAudio-lyd - TrueAudio-audio - TrueAudio-lyd - Plik dźwiękowy TrueAudio - Áudio TrueAudio - Audio TrueAudio - аудио TrueAudio - Zvuk TrueAudio - Zvočna datoteka TrueAudio - Audio TrueAudio - TrueAudio-ljud - звук TrueAudio - Âm thanh TrueAudio - TrueAudio 音频 - TrueAudio 音訊 - - - - - - - - Windows BMP image - صورة Windows BMP - Windows BMP rəsmi - Vyjava Windows BMP - Изображение — Windows BMP - imatge BMP de Windows - Obrázek Windows BMP - Delwedd BMP Windows - Windows BMP-billede - Windows-BMP-Bild - εικόνα Windows BMP - Windows BMP image - BMP-bildo de Vindozo - imagen BMP de Windows - Windows BMP irudia - Windows BMP -kuva - Windows BMP mynd - image Windows BMP - íomhá BMP Windows - imaxe BMP de Windows - תמונת BMP של Windows - Windows BMP slika - Windows BMP-kép - Citra Windows BMP - Immagine Windows BMP - Windows BMP 画像 - Windows BMP суреті - Windows BMP 그림 - Windows BMP paveikslėlis - Windows BMP attēls - Imej BMP Windows - Windows BMP-bilde - Windows BMP-afbeelding - Windows BMP-bilete - Obraz BMP Windows - imagem BMP Windows - Imagem BMP do Windows - Imagine Windows BMP - изображение Windows BMP - Obrázok Windows BMP - Slikovna datoteka Windows BMP - Figurë Windows BMP - Windows BMP слика - Windows BMP-bild - Windows BMP görüntüsü - зображення Windows BMP - Ảnh BMP Windows - Windows BMP 图像 - Windows BMP 影像 - - - - - - - - - - - - - - WBMP image - صورة WBMP - Vyjava WBMP - Изображение — WBMP - imatge WBMP - Obrázek WBMP - WBMP-billede - WBMP-Bild - εικόνα WBMP - WBMP image - WBMP-bildo - imagen WBMP - WBMP irudia - WBMP-kuva - WBMP mynd - image WBMP - íomhá WBMP - imaxe WBMP - תמונת WBMP - WBMP slika - WBMP kép - Citra WBMP - Immagine WBMP - WBMP 画像 - WBMP суреті - WBMP 그림 - WBMP paveikslėlis - WBMP attēls - WBMP-bilde - WBMP-afbeelding - WBMP-bilete - Obraz WBMP - Imagem WBMP - Imagine WBMP - изображение WBMP - Obrázok WBMP - Slikovna datoteka WBMP - Figurë WBMP - WBMP-bild - зображення WBMP - Ảnh WBMP - WBMP 图像 - WBMP 影像 - WBMP - WAP bitmap - - - - Computer Graphics Metafile - ملف تعريف رسوميات الحاسوب - Kompüter Qrafikası Meta Faylı - Metafajł Computer Graphics - Метафайл — Computer Graphics - metafitxer de Computer Graphics - Computer Graphics Metafile - Delwedd ffurf CGM - Computer Graphics-metafil - CGM-Datei - αρχείο Computer Graphics Metafile - Computer Graphics Metafile - metaarchivo de Computer Graphics - Ordenagailuko grafikoen meta-fitxategia - Computer Graphics -metatiedosto - Teldugrafikk metafíla - métafichier Computer Graphics - meiteachomhad Grafaicí Ríomhaire - metaficheiro de Computer Graphics - קובץ-מטה מסוג Computer Graphics - Computer Graphics-metafájl - Computer Graphics Metafile - Computer Graphics Metafile - コンピューターグラフィックメタファイル - компьютерлік графика метафайлы - 컴퓨터 그래픽스 메타파일 - Computer Graphics metafailas - Datorgrafikas metadatne - Failmeta Grafik Komputer - Computer Graphics Metafile - Computer Graphics-metabestand - Computer Graphics Metafile - Metaplik grafiki komputerowej (CGM) - Computer Graphics Metafile - Meta-arquivo do Computer Graphics - Metafișier Computer Graphics - метафайл компьютерной графики - Computer Graphics Metafile - Metadatoteka računalniške grafike (CGM) - Metafile Computer Graphics - Метадатотека са рачунарском графиком (CGM) - Computer Graphics Metafil - метафайл комп'ютерної графіки - Siêu tập tin đồ họa máy tính (CMF) - CGM 计算机图像元文件 - CGM 影像 - - - - CCITT G3 fax - فاكس CCITT G3 - Faks CCITT G3 - Факс — CCITT G3 - fax CCITT G3 - Fax CCITT G3 - CCITT G3-fax - CCITT-G3-Fax - φαξ σε μορφή CCITT G3 - CCITT G3 fax - G3-fakso de CCITT - fax de CCITT G3 - CCITT G3 faxa - CCITT G3 -faksi - CCITT G3 telefaks - télécopie G3 CCITT - facs CCITT G3 - fax de CCITT G3 - פקס של CCITT G3 - CCITT G3 faks - CCITT G3-fax - Faks CCITT G3 - Fax CCITT G3 - CCITT G3 FAX - CCITT G3 ფაქსი - CCITT G3 факсі - CCITT G3 팩스 - CCITT G3 faksas - CCITT G3 fakss - Faks g3 CCITT - CCITT G3-faks - CCITT G3-fax - CCITT G3-fax - Faks CCITT G3 - fax CCITT G3 - Fax do CCITT G3 - Fax CCITT G3 - факс CCITT G3 - Fax CCITT G3 - Datoteka faksimila CCITT G3 - Fax CCITT G3 - CCITT g3 факс - CCITT G3-fax - факс CCITT G3 - Điện thư G3 CCITT - CCITT G3 传真 - CCITT G3 傳真檔 - - - - G3 fax image - صورة فاكس G3 - G3 faks rəsmi - Faksavaja vyjava G3 - Изображение — факс G3 - imatge de fax G3 - Obrázek fax G3 - Delwedd Ffacs G3 - G3-faxbillede - G3-Faxbild - εικόνα φαξ G3 - G3 fax image - G3-faksbildo - imagen de fax G3 - G3 fax-irudia - G3-faksikuva - G3 fax mynd - image de télécopie G3 - íomhá fhacs G3 - imaxe de fax G3 - תמונת פקס של G3 - G3-faxkép - Citra faks G3 - Immagine fax G3 - G3 FAX 画像 - G3 fax გამოსახულება - G3 факс суреті - G3 팩스 그림 - G3 fax paveikslėlis - G3 faksa attēls - Imej fax G3 - G3-faksbilde - G3 faxafbeelding - G3 faksbilete - Obraz faksowy G3 - imagem de fax G3 - Imagem de fax G3 - Imagine fax G3 - факсовое изображение G3 - Obrázok fax G3 - Slikovna datoteka G3 fax - Figurë Fax G3 - G3 факс слика - G3-faxbild - G3 fax görüntüsü - факс G3 - Ảnh điện thư G3 - G3 传真文档 - G3 傳真圖 - - - GIF image - صورة GIF - GIF rəsmi - Vyjava GIF - Изображение — GIF - imatge GIF - Obrázek GIF - Delwedd GIF - GIF-billede - GIF-Bild - εικόνα GIF - GIF image - GIF-bildo - imagen GIF - GIF irudia - GIF-kuva - GIF mynd - image GIF - íomhá GIF - imaxe GIF - תמונת GIF - GIF slika - GIF-kép - Citra GIF - Immagine GIF - GIF 画像 - GIF გამოსახულება - GIF суреті - GIF 그림 - GIF paveikslėlis - GIF attēls - Imej GIF - GIF-bilde - GIF-afbeelding - GIF-bilete - Obraz GIF - imagem GIF - Imagem GIF - Imagine GIF - изображение GIF - Obrázok GIF - Slikovna datoteka GIF - Figurë GIF - GIF слика - GIF-bild - GIF görüntüsü - зображення GIF - Ảnh GIF - GIF 图像 - GIF 影像 - - - - - - - IEF image - صورة IEF - IEF rəsmi - Vyjava IEF - Изображение — IEF - imatge IEF - Obrázek IEF - Delwedd IEF - IEF-billede - IEF-Bild - εικόνα IEF - IEF image - IEF-bildo - imagen IEF - IEF irudia - IEF-kuva - IEF mynd - image IEF - íomhá IEF - imaxe IEF - תמונת IEF - IEF slika - IEF-kép - Citra IEF - Immagine IEF - IEF 画像 - IEF суреті - IEF 그림 - IEF paveikslėlis - IEF attēls - Imej IEF - IEF-bilde - IEF-afbeelding - IEF-bilete - Obraz IEF - imagem IEF - Imagem IEF - Imagine IEF - изображение IEF - Obrázok IEF - Slikovna datoteka IEF - Figurë IEF - IEF слика - IEF-bild - зображення IEF - Ảnh IEF - IEF 图像 - IEF 影像 - - - - JPEG image - صورة JPEG - JPEG rəsmi - Vyjava JPEG - Изображение — JPEG - imatge JPEG - Obrázek JPEG - Delwedd JPEG - JPEG-billede - JPEG-Bild - εικόνα JPEG - JPEG image - JPEG-bildo - imagen JPEG - JPEG irudia - JPEG-kuva - JPEG mynd - image JPEG - íomhá JPEG - imaxe JPEG - תמונת JPEG - JPEG slika - JPEG-kép - Citra JPEG - Immagine JPEG - JPEG 画像 - JPEG суреті - JPEG 그림 - JPEG paveikslėlis - JPEG attēls - Imej JPEG - JPEG-bilde - JPEG-afbeelding - JPEG-bilete - Obraz JPEG - imagem JPEG - Imagem JPEG - Imagine JPEG - изображение JPEG - Obrázok JPEG - Slikovna datoteka JPEG - Figurë JPEG - JPEG слика - JPEG-bild - JPEG görüntüsü - зображення JPEG - Ảnh JPEG - JPEG 图像 - JPEG 影像 - - - - - - - - - - - JPEG-2000 image - صورة JPEG-2000 - Vyjava JPEG-2000 - Изображение — JPEG-2000 - imatge JPEG-2000 - Obrázek JPEG-2000 - JPEG2000-billede - JPEG-2000-Bild - εικόνα JPEG-2000 - JPEG-2000 image - JPEG-2000-bildo - imagen JPEG-2000 - JPEG-2000 irudia - JPEG-2000-kuva - JPEG-2000 mynd - image JPEG-2000 - íomhá JPEG-2000 - imaxe JPEG-2000 - תמונת JPEG-2000 - JPEG-2000 slika - JPEG-2000 kép - Citra JPEG-2000 - Immagine JPEG-2000 - JPEG-2000 画像 - JPEG-2000 суреті - JPEG-2000 그림 - JPEG-2000 paveikslėlis - JPEG-2000 attēls - Imej JPEG-2000 - JPEG-2000-bilde - JPEG-2000-afbeelding - JPEG-2000-bilete - Obraz JPEG-2000 - imagem JPEG-2000 - Imagem JPEG-2000 - Imagine JPEG-2000 - изображение JPEG-2000 - Obrázok JPEG-2000 - Slikovna datoteka JPEG-2000 - Figurë JPEG-2000 - JPEG-2000 слика - JPEG-2000-bild - JPEG-2000 görüntüsü - зображення JPEG-2000 - Ảnh JPEG-2000 - JPEG-2000 图像 - JPEG-2000 影像 - - - - - - - - - - - - - - - - OpenRaster archiving image - صورة أرشيف OpenRaster - Изображение — OpenRaster - imatge d'arxivat OpenRaster - Archivační obraz OpenRaster - OpenRaster-arkivaftryk - OpenRaster-Archivierungsbild - εικόνα αρχειοθέτησης OpenRaster - OpenRaster archiving image - imagen de archivado de OpenRaster - OpenRaster artxiboaren irudia - OpenRaster goymslumynd - image d'archive OpenRaster - íomhá chartlannaithe OpenRaster - imaxe arquivada de OpenRaster - תמונת ארכיון של OpenRaster - OpenRaster archiválási kép - Gambar pengarsipan OpenRaster - Immagine archiviazione OpenRaster - OpenRaster アーカイブイメージ - OpenRaster-ის საარქივო გამოსახულება - OpenRaster архивтеу суреті - OpenRaster 압축 이미지 - OpenRaster archyvavimo paveikslėlis - OpenRaster arhivēšanas attēls - OpenRaster archiverings-image - Archiwalny obraz OpenRaster - Imagem de arquivamento OpenRaster - Arhivă imagine OpenRaster - архивное изображение OpenRaster - Odtis arhiva OpenRaster - OpenRaster-arkivbild - архівоване зображення OpenRaster - OpenRaster 归档映像 - OpenRaster 封存影像 - - - - - - - - - - - WebP image - صورة WebP - WebP rəsmi - Vyjava WebP - Изображение — WebP - imatge WebP - Obrázek WebP - Delwedd WebP - WebP-billede - WebP-Bild - εικόνα WebP - WebP image - WebP-bildo - imagen WebP - WebP irudia - WebP-kuva - WebP mynd - image WebP - íomhá WebP - imaxe WebP - תמונת WebP - WebP slika - WebP-kép - Citra WebP - Immagine WebP - WebP 画像 - WebP суреті - WebP 그림 - WebP paveikslėlis - WebP attēls - Imej WebP - WebP-bilde - WebP-afbeelding - WebP-bilete - Obraz WebP - imagem WebP - Imagem WebP - Imagine WebP - изображение WebP - Obrázok WebP - Slikovna datoteka WebP - Figurë WebP - WebP слика - WebP-bild - WebP görüntüsü - зображення WebP - Ảnh WebP - WebP 图像 - WebP 影像 - - - - - - - - - DirectDraw surface - مساحة DirectDraw - Pavierchnia DirectDraw - Изображение — повърхност на DirectDraw - superfície DirectDraw - Plocha DirectDraw - DirectDraw-overflade - DirectDraw-Oberfläche - επιφάνεια DirectDraw - DirectDraw surface - superficie DirectDraw - DirectDraw gainazala - DirectDraw-piirtoalue - DirectDraw yvirflata - surface DirectDraw - dromchla DirectDraw - superficie de DirectDraw - משטח של DirectDraw - DirectDraw ploha - DirectDraw felület - Permukaan DirectDraw - Superficie DirectDraw - DirectDraw サーフェイス - DirectDraw-ის ზედაპირი - DirectDraw жазықтығы - DirectDraw 서피스 - DirectDraw paviršius - DirectDraw virsma - DirectDraw-overflate - DirectDraw-oppervlak - DirectDraw-overflate - Powierzchnia DirectDraw - Superfície do DirectDraw - Suprafață DirectDraw - плоскость DirectDraw - Plocha DirectDraw - Datoteka predmeta DirectDraw - Superfaqe DirectDraw - DirectDraw-yta - поверхня DirectDraw - Mặt DirectDraw - DirectDraw 表面 - DirectDraw 表面 - - - - - - - X11 cursor - مؤشر X11 - Kursor X11 - Курсор — X11 - cursor X11 - Kurzor X11 - X11-markør - X11-Zeiger - δείκτης X11 - X11 cursor - cursor X11 - X11 kurtsorea - X11-osoitin - X11 vísi - curseur X11 - cúrsóir X11 - Cursor X11 - סמן של X11 - X11 kursor - X11 kurzor - Kursor X11 - Cursore X11 - X11 カーソル - X11 курсоры - X11 커서 - X11 žymiklis - X11 kursors - X11-markør - X11-muisaanwijzer - X11-peikar - Kursor X11 - Cursor do X11 - Cursor X11 - курсор X11 - Kurzor X11 - Datoteka kazalke X11 - Kursor X11 - X11-muspekare - курсор X11 - Con chạy X11 - X11 指针 - X11 滑鼠游標 - - - - - - EXR image - صورة EXR - Vyjava EXR - Изображение — EXR - imatge EXR - Obrázek EXR - EXR-billede - EXR-Bild - εικόνα EXR - EXR image - EXR-bildo - imagen EXR - EXR irudia - EXR-kuva - EXR mynd - image EXR - íomhá EXR - imaxe EXR - תמונת EXR - EXR slika - EXR kép - Citra EXR - Immagine EXR - EXR 画像 - EXR გამოსახულება - EXR суреті - EXR 그림 - EXR paveikslėlis - EXR attēls - EXR-bilde - EXR-afbeelding - EXR-bilete - Obraz EXR - Imagem EXR - Imagine EXR - изображение EXR - Obrázok EXR - Slikovna datoteka EXR - Figurë EXR - EXR-bild - EXR görüntüsü - зображення EXR - Ảnh EXR - EXR 图像 - EXR 影像 - - - - - - - Macintosh Quickdraw/PICT drawing - رسمة ماكنتوش Quickdraw/PICT - Rysunak Macintosh Quickdraw/PICT - Чертеж — Macintosh Quickdraw/PICT - dibuix Quickdraw/PICT de Macintosh - Kresba Macintosh Quickdraw/PICT - Macintosh Quickdraw/PICT-tegning - Macintosh-Quickdraw/PICT-Zeichnung - σχέδιο Macintosh Quickdraw/PICT - Macintosh Quickdraw/PICT drawing - Quickdraw/PICT-grafikaĵo de Macintosh - dibujo de Macintosh Quickdraw/PICT - Macintosh Quickdraw/PICT marrazkia - Macintosh Quickdraw/PICT -piirros - Macintosh Quickdraw/PICT tekning - dessin Macintosh Quickdraw/PICT - líníocht Macintosh Quickdraw/PICT - debuxo de Macintosh Quickdraw/PICT - ציור של Macintosh Quickdraw/PICT - Macintosh Quickdraw/PICT crtež - Macintosh Quickdraw/PICT-rajz - Gambar Macintosh Quickdraw/PICT - Disegno Macintosh Quickdraw/PICT - Macintosh Quickdraw/PICT ドロー - Macintosh Quickdraw/PICT суреті - 매킨토시 Quickdraw/PICT 그림 - Macintosh Quickdraw/PICT piešinys - Macintosh Quickdraw/PICT zīmējums - Lukisan Macintosh Quickdraw/PICT - Macintosh Quickdraw/PICT-tegning - Macintosh Quickdraw/PICT-tekening - Macintosh Quickdraw/PICT-teikning - Rysunek Quickdraw/PICT Macintosh - desenho Quickdraw/PICT de Macintosh - Desenho do Macintosh Quickdraw/PICT - Desen Macintosh Quickdraw/PICT - рисунок Macintosh Quickdraw/PICT - Kresba Macintosh QuickDraw/PICT - Datoteka risbe Macintosh Quickdraw/PICT - Vizatim Macintosh Quickdraw/PICT - Мекинтош Quickdraw/PICT цртеж - Macintosh Quickdraw/PICT-teckning - малюнок Macintosh Quickdraw/PICT - Bản vẽ Quickdraw/PICT của Macintosh - Macintosh Quickdraw/PICT 绘图 - Macintosh Quickdraw/PICT 繪圖 - - - - - - - - - - - - - - - - - - - - - - - - - UFRaw ID image - صورة UFRaw ID - Vyjava UFRaw ID - Изображение — UFRaw ID - imatge ID UFRaw - Obrázek ID UFRaw - UFRaw ID-billede - UFRaw-Bildbeschreibungsdatei - ταυτότητα UFRaw - UFRaw ID image - imagen de identificación UFRaw - UFRaw ID irudia - UFRaw ID -kuva - UFRaw ID mynd - image ID UFRaw - íomhá aitheantais UFRaw - imaxe de identificación UFRaw - תמונה של UFRaw ID - UFRaw azonosítófájl - Citra UFRaw ID - Immagine UFRaw ID - UFRaw ID イメージ - UFRaw ID суреті - UFRaw ID 그림 - UFRaw ID paveikslėlis - UFRaw ID attēls - UFRaw ID-bilde - UFRaw ID-afbeelding - UFRaw ID-bilete - Obraz UFRaw ID - Imagem ID do UFRaw - ID imagine UFRaw - изображение UFRaw ID - Obrázok ID UFRaw - Slikovna datoteka UFRaw ID - Figurë UFRaw ID - UFRaw ID-bild - зображення UFRaw ID - Ảnh ID UFRaw - UFRaw ID 图像 - UFRaw ID 影像 - UFRaw - Unidentified Flying Raw - - - - - - digital raw image - صورة رقمية خامة - suvoraja ličbavaja vyjava - Изображение — digital raw - imatge digital en cru - Digitální surový obrázek - digitalt råbillede - Digitales Rohbild - ανεπεξέργαστη ψηφιακή εικόνα - digital raw image - imagen digital en bruto - irudi gordin digitala - digitaalinen raakakuva - talgild rámynd - image brute numérique - amhíomhá digiteach - imaxe en bruto dixital - תמונה דיגטלית גולמית - digitális nyers kép - citra mentah digital - Immagine raw digitale - デジタル raw 画像 - өңделмеген сандық суреттер - 디지털 원본 이미지 - skaitmeninis neapdorotas paveikslėlis - digitāls jēlattēls - digitalt raw-bilde - onbewerkt digitaal beeld - digitalt råbilete - Surowy obraz cyfrowy - Imagem digital bruta - imagine digitală brută - необработанные цифровые изображения - Digitálny surový obrázok - surova digitalna slika - Figurë raw dixhitale - digital råbild - зображення цифрового негатива - ảnh thô số - 数字化原始图像 - 數位原生影像 - - - Adobe DNG negative - Adobe DNG negative - Adobe DNG Negative - Изображение — Adobe DNG negative - negatiu DNG d'Adobe - Adobe Digital Negative (DNG) - Adobe DNG-negativ - Adobe Digitales Negativ - αρνητικό Adobe DNG - Adobe DNG negative - negativo digital de Adobe (ADN) - Adobe DNG negatiboa - Adobe-DNG-negatiivi - Adobe DNG negativ - négatif DNG Adobe - claonchló DNG Adobe - negativo DNG de Adobe - תשליל Adobe DNG - Adobe DNG negativ - Adobe DNG negatív - Negatif Adobe DNG - Negativo Adobe DNG - Adobe DNG ネガ - Adobe DNG-ის ნეგატივი - Adobe DNG негативі - 어도비 DNG 네거티브 - Adobe DNG negatyvas - Adobe DNG negatīvs - Adobe DNG-negativ - Adobe DNG-negatief - Adobe DNG-negativ - Negatyw DNG Adobe - Negativo DNG da Adobe - Negativ Adobe DNG - негатив Adobe DNG - Adobe Digital Negative (DNG) - Datoteka negativa Adobe DNG - Negativ Adobe DNG - Adobe DNG-negativ - цифровий негатив DNG Adobe - Âm bản Adobe DNG - Adobe DNG 负片 - Adobe DNG 負片 - DNG - Digital Negative - - - - - - - - Canon CRW raw image - صورة Canon CRW خامة - Suvoraja vyjava Canon CRW - Изображение — Canon CRW raw - imatge en cru de Canon CRW - Surový obrázek Canon CRW - Canon CRW-råbillede - Canon-CRW-Rohbild - ανεπεξέργαστη εικόνα Canon CRW - Canon CRW raw image - imagen en bruto CRW de Canon - Canon CRW irudi gordina - Canon-CRW-raakakuva - Canon CRW rámynd - image brute CRW Canon - amhíomhá Canon CRW - imaxe en bruto de Canon CRW - תמונה גולמית של Canon CRW - Canon CRW nyers kép - Citra mentah Canon CRW - Immagine raw Canon CRW - Canon CRW raw 画像 - Canon CRW raw გამოსახულება - Canon CRW өңделмеген суреті - 캐논 CRW 원본 이미지 - Canon CRW neapdorotas paveikslėlis - Canon CRW jēlattēls - Canon CRW raw-bilde - onbewerkt Canon CRW-beeld - Canon CRW råbilete - Surowy obraz CRW Canon - Imagem bruta CRW da Canon - Imagine brută Canon CRW - необработанное изображение Canon CRW - Surový obrázok Canon CRW - Surova slikovna datoteka Canon CRW - Figurë raw Canon CRW - Canon CRW-råbild - цифровий негатив CRW Canon - Ảnh thô Canon CRW - Canon CRW 原始图像 - Canon CRW 原生影像 - CRW - Canon RaW - - - - - - - - - Canon CR2 raw image - صورة Canon CR2 خامة - Suvoraja vyjava Canon CR2 - Изображение — Canon CR2 raw - imatge en cru de Canon CR2 - Surový obrázek Canon CR2 - Canon CR2-råbillede - Canon-CR2-Rohbild - ανεπεξέργαστη εικόνα Canon CR2 - Canon CR2 raw image - imagen en bruto CR2 de Canon - Canon CR2 irudi gordina - Canon-CR2-raakakuva - Canon CR2 rámynd - image brute CR2 Canon - amhíomhá Canon CR2 - imaxe en bruto de Canon CR2 - תמונה גולמית של Canon CR2 - Canon CR2 nyers kép - Citra mentah Canon CR2 - Immagine raw Canon CR2 - Canon CR2 raw 画像 - Canon CR2 raw გამოსახულება - Canon CR2 өңделмеген суреті - 캐논 CR2 원본 이미지 - Canon CR2 neapdorotas paveikslėlis - Canon CR2 jēlattēls - Canon CR2 raw-bilde - onbewerkt Canon CR2-beeld - Canon CR2 råbilete - Surowy obraz CR2 Canon - Imagem bruta CR2 da Canon - Imagine brută Canon CR2 - необработанное изображение Canon CR2 - Surový obrázok Canon CR2 - Surova slikovna datoteka Canon CR2 - Figurë raw Canon CR2 - Canon CR2-råbild - цифровий негатив CR2 Canon - Ảnh thô Canon CR2 - Canon CR2 原始图像 - Canon CR2 原生影像 - CR2 - Canon Raw 2 - - - - - - Fuji RAF raw image - صورة Fuji RAF خامة - Suvoraja vyjava Fuji RAF - Изображение — Fuji RAF raw - imatge en cru de Fuji RAF - Surový obrázek Fuji RAF - Fuji RAF-råbillede - Fuji-RAF-Rohbild - ανεπεξέργαστη εικόνα Fuji RAF - Fuji RAF raw image - imagen en bruto RAF de Fuji - Fuji RAF irudi gordina - Fuji-RAF-raakakuva - Fuji RAF raw mynd - image brute RAF Fuji - amhíomhá Fuji RAF - imaxe en bruto de Fuji RAF - תמונה גולמית של Fuji RAF - Fuji RAF nyers kép - Citra mentah Fuji RAF - Immagine raw Fuji RAF - Fuji RAF raw 画像 - Fuji RAF-ის raw გამოსახულება - Fuji RAF өңделмеген суреті - 후지 RAF 원본 이미지 - Fuji RAF neapdorotas paveikslėlis - Fuji RAF jēlattēls - Fuji RAF raw-bilde - onbewerkt Fuji RAF-beeld - Fuji RAF rått bilete - Surowy obraz RAF Fuji - Imagem bruta RAF da Fuji - Imagine brută Fuji RAF - необработанное изображение Fuji RAF - Surový obrázok Fuji RAF - Surova slikovna datoteka Fuji RAF - Figurë raw Fuji RAF - Fuji RAF-råbild - Цифровий негатив RAF Fuji - Ảnh thô Fuji RAF - 富士RAF 原始图像 - Fuji RAF 原生影像 - RAF - RAw Format - - - - - - - - Kodak DCR raw image - صورة Kodak DCR خامة - Suvoraja vyjava Kodak DCR - Изображение — Kodak DCR raw - imatge en cru de Kodak DCR - Surový obrázek Kodak DCR - Kodak DCR-råbillede - Kodak-DCR-Rohbild - ανεπεξέργαστη εικόνα Kodak DCR - Kodak DCR raw image - imagen en bruto DCR de Kodak - Kodak DCR irudi gordina - Kodak-DCR-raakakuva - Kodak DCR rámynd - image brute DCR Kodak - amhíomhá Kodak DCR - imaxe en bruto de Kodad DCR - תמונה גולמית של Kodak DCR - Kodak DCR nyers kép - Citra mentah Kodak DCR - Immagine raw Kodak DCR - Kodak DCR raw 画像 - Kodak DCR өңделмеген суреті - 코닥 DCR 원본 이미지 - Kodak DCR neapdorotas paveikslėlis - Kodak DCR jēlattēls - Kodak DCR raw-bilde - onbewerkt Kodak DCR-beeld - Kodak DCR råbilete - Surowy obraz DCR Kodak - Imagem bruta DCR da Kodak - Imagine brută Kodak DCR - необработанное изображение Kodak DCR - Surový obrázok Kodak DCR - Surova slikovna datoteka Kodak DCR - Figurë raw Kodak DCR - Kodak DCR-råbild - цифровий негатив DCR Kodak - Ảnh thô Kodak DCR - Kodak DCR 原始图像 - Kodak DCR 原生影像 - DCR - Digital Camera Raw - - - - - - Kodak K25 raw image - صورة Kodak K25 خامة - Suvoraja vyjava Kodak K25 - Изображение — Kodak K25 raw - imatge en cru de Kodak K25 - Surový obrázek Kodak K25 - Kodak K25-råbillede - Kodak-K25-Rohbild - ανεπεξέργαστη εικόνα Kodak K25 - Kodak K25 raw image - imagen en bruto K25 de Kodak - Kodak K25 raw image - Kodak-K25-raakakuva - Kodak K25 rámynd - image brute K25 Kodak - amhíomhá Kodak K25 - imaxe en bruto de Kodad K25 - תמונה גולמית של Kodak K25 - Kodak K25 nyers kép - Citra mentah Kodak K25 - Immagine raw Kodak K25 - Kodak K25 raw 画像 - Kodak K25 өңделмеген суреті - 코닥 K25 원본 이미지 - Kodak K25 neapdorotas paveikslėlis - Kodak K25 jēlattēls - Kodak K25 raw-bilde - onbewerkt Kodak K25-beeld - Kodak K25 råbilete - Surowy obraz K25 Kodak - Imagem bruta K25 da Kodak - Imagine brută Kodak K25 - необработанное изображение Kodak K25 - Surový obrázok Kodak K25 - Surova slikovna datoteka Kodak K25 - Figurë raw Kodak K25 - Kodak K25-råbild - цифровий негатив K25 Kodak - Ảnh thô Kodak K25 - Kodak K25 原始图像 - Kodak K25 原生影像 - K25 - Kodak DC25 - - - - - - Kodak KDC raw image - صورة Kodak KDC خامة - Suvoraja vyjava Kodak KDC - Изображение — Kodak KDC raw - imatge en cru de Kodak KDC - Surový obrázek Kodak KDC - Kodak KDC-råbillede - Kodak-KDC-Rohbild - ανεπεξέργαστη εικόνα Kodak KDC - Kodak KDC raw image - imagen en bruto KDC de Kodak - Kodak KDC irudi gordina - Kodak-KDC-raakakuva - Kodak KDC rámynd - image brute KDC Kodak - amhíomhá Kodak KDC - imaxe en bruto de Kodad KDC - תמונה גולמית של Kodak KDC - Kodak KDC nyers kép - Citra mentah Kodak KDC - Immagine raw Kodak KDC - Kodak KDC raw 画像 - Kodak KDC өңделмеген суреті - 코닥 KDC 원본 이미지 - Kodak KDC neapdorotas paveikslėlis - Kodak KDC jēlattēls - Kodak KDC raw-bilde - onbewerkt Kodak KDC-beeld - Kodak KDC råbilete - Surowy obraz KDC Kodak - Imagem bruta KDC da Kodak - Imagine brută Kodak KDC - необработанное изображение Kodak KDC - Surový obrázok Kodak KDC - Surova slikovna datoteka Kodak KDC - Figurë raw Kodak KDC - Kodak KDC-råbild - цифровий негатив KDC Kodak - Ảnh thô Kodak KDC - Kodak KDC 原始图像 - Kodak KDC 原生影像 - KDC - Kodak Digital Camera - - - - - - - - - Minolta MRW raw image - صورة Minolta MRW خامة - Suvoraja vyjava Minolta MRW - Изображение — Minolta MRW raw - imatge en cru de Minolta MRW - Surový obrázek Minolta MRW - Minolta MRW-råbillede - Minolta-MRW-Rohbild - ανεπεξέργαστη εικόνα Minolta MRW - Minolta MRW raw image - imagen en bruto MRW de Minolta - Minolta MRW irudi gordina - Minolta-MRW-raakakuva - Minolta MRW rámynd - image brute MRW Minolta - amhíomhá Minolta MRW - imaxe RAW de Minolta MRW - תמונה גולמית של Minolta MRW - Minolta MRW nyers kép - Citra mentah Minolta MRW - Immagine raw Minolta MRW - Minolta MRW raw 画像 - Minolta MRW өңделмеген суреті - 미놀타 MRW 원본 이미지 - Minolta MRW neapdorotas paveikslėlis - Minolta MRW jēlattēls - Minolta MRW raw-bilde - onbewerkt Minolta MRW-beeld - Minolta MRW råbilete - Surowy obraz MRW Minolta - Imagem bruta MRW do Minolta - Imagine brută Minolta MRW - необработанное изображение Minolta MRW - Surový obrázok Minolta MRW - Surova slikovna datoteka Minolta MRW - Figurë raw Minolta MRW - Minolta MRW-råbild - цифровий негатив MRW Minolta - Ảnh thô Minolta MRW - Minolta MRW 原始图像 - Minolta MRW 原生影像 - MRW - Minolta RaW - - - - - - - - Nikon NEF raw image - صورة Nikon NEF خامة - Suvoraja vyjava Nikon NEF - Изображение — Nikon NEF raw - imatge en cru de Nikon NEF - Surový obrázek Nikon NEF - Nikon NEF-råbillede - Nikon-NEF-Rohbild - ανεπεξέργαστη εικόνα Nikon NEF - Nikon NEF raw image - imagen en bruto NEF de Nikon - Nikon NEF irudi gordina - Nikon-NEF-raakakuva - Nikon NEF rámynd - image brute NEF Nikon - amhíomhá Nikon NEF - imaxe RAW NEF Nikon - תמונה גולמית של Nikon NEF - Nikon NEF nyers kép - Citra mentah Nikon NEF - Immagine raw Nikon NEF - Nikon NEF raw イメージ - Nikon NEF өңделмеген суреті - 니콘 NEF 원본 이미지 - Nikon NEF neapdorotas paveikslėlis - Nikon NEF jēlattēls - Nikon NEF raw-bilde - onbewerkt Nikon NEF-beeld - Nikon NEF råbilete - Surowy obraz NEF Nikon - Imagem bruta NEF da Nikon - Imagine brută Nikon NEF - необработанное изображение Nikon NEF - Surový obrázok Nikon NEF - Surova slikovna datoteka Nikon NEF - Figurë raw Nikon NEF - Nikon NEF-råbild - цифровий негатив NEF Nikon - Ảnh thô Nikon NEF - Nikon NEF 原始图像 - Nikon NEF 原生影像 - NEF - Nikon Electronic Format - - - - - - Olympus ORF raw image - صورة Olympus ORF خامة - Suvoraja vyjava Olympus ORF - Изображение — Olympus ORF raw - imatge en cru d'Olympus ORF - Surový obrázek Olympus ORF - Olympus ORF-råbillede - Olympus-ORF-Rohbild - ανεπεξέργαστη εικόνα Olympus ORF - Olympus ORF raw image - imagen en bruto ORF de Olympus - Olympus ORF irudi gordina - Olympus-ORF-raakakuva - Olympus ORF rámynd - image brute ORF Olympus - amhíomhá Olympus ORF - imaxe en bruto de Olympus ORF - תמונה גולמית של Olympus ORF - Olympus ORF nyers kép - Citra mentah Olympus ORF - Immagine raw Olympus ORF - Olympus ORF raw 画像 - Olympus ORF-ის raw გამოსახულება - Olympus ORF өңделмеген суреті - 올림푸스 ORF 원본 이미지 - Olympus ORF neapdorotas paveikslėlis - Olympus ORF jēlattēls - Olympus ORF raw-bilde - onbewerkt Olympus ORF-beeld - Olympus ORF råbilete - Surowy obraz Olympus ORF - Imagem bruta ORF da Olympus - Imagine brută Olympus ORF - необработанное изображение Olympus ORF - Surový obrázok Olympus ORF - Surova slikovna datoteka Olympus ORF - Figurë raw Olympus ORF - Olympus ORF-råbild - цифровий негатив ORF Olympus - Ảnh thô Olympus ORF - Olympus ORF 原始图像 - Olympus ORF 原生影像 - ORF - Olympus Raw Format - - - - - - - - - - - - - Panasonic raw image - صورة Panasonic خامة - Suvoraja vyjava Panasonic - Изображение — Panasonic raw - imatge en cru de Panasonic - Surový obrázek Panasonic - Panasonicråbillede (raw) - Panasonic-Rohbild - Panasonic raw image - imagen en bruto de Panasonic - Panasonic irudi gordina - Panasonic-raakakuva - Panasonic rámynd - image brute Panasonic - amhíomhá Panasonic - imaxe en bruto de Panasonic - תמונה גולמית של Panasonic - Panasonic nyers kép - Citra mentah Panasonic - Immagine raw Panasonic - Panasonic raw 画像 - Panasonic өңделмеген суреті - 파나소닉 원본 이미지 - Panasonic neapdorotas paveikslėlis - Panasonic jēlattēls - Panasonic raw-bilde - onbewerkt Panasonic-beeld - Panasonic råbilete - Obraz raw Panasonic - Imagem bruta da Panasonic - Imagine brută Panasonic - необработанное изображение Panasonic - Surový obrázok Panasonic - Surova slikovna datoteka Panasonic - Figurë raw Panasonic - Panasonic-råbild - цифровий негатив Panasonic - Ảnh thô Panasonic - Panasonic 原始图像 - Panasonic 原生影像 - - - - - - - - - Panasonic raw2 image - Изображение — Panasonic raw2 - imatge «RAW2» de Panasonic - Surový obrázek Panasonic raw2 - Panasonic-rå2-billede (raw) - Panasonic raw2-Bild - Panasonic raw2 image - imagen en bruto raw2 de Panasonic - Panasonic raw2 -kuva - image raw2 Panasonic - imaxe en bruto raw2 de Panasonic - תמונת raw2 של Panasonic - Panasonic raw2 kép - Image Panasonic raw2 - Immagine raw2 Panasonic - Panasonic raw2 画像 - Panasonic raw2 суреті - 파나소닉 원본 이미지 2 - Panasonic raw2 jēlattēls - Panasonic raw2 image - Obraz raw2 Panasonic - Imagem raw2 da Panasonic - необработанное изображение Panasonic RAW 2 - Surový obrázok Panasonic raw2 - Slikovna datoteka Panasonic raw2 - Panasonic raw2-bild - Panasonic raw2 görüntüsü - зображення формату raw2 Panasonic - Panasonic raw2 图像 - Panasonic raw2 影像 - - - - - - - - - Pentax PEF raw image - صورة Pentax PEF خامة - Suvoraja vyjava Pentax PEF - Изображение — Pentax PEF raw - imatge en cru de Pentax PEF - Surový obrázek Pentax PEF - Pentax PEF-råbillede - Pentax-PEF-Rohbild - ανεπεξέργαστη εικόνα Pentax PEF - Pentax PEF raw image - imagen en bruto PEF de Pentax - Pentax PEF irudi gordina - Pentax-PEF-raakakuva - Pentax PEF rámynd - image brute PEF Pentax - amhíomhá Pentax PEF - imaxe en bruto PEF de Pentax - תמונה גולמית של Pentax PEF - Pentax PEF nyers kép - Citra mentah Pentax PEF - Immagine raw Pentax PEF - Pentax PEF raw 画像 - Pentax PEF өңделмеген суреті - 펜탁스 PEF 원본 이미지 - Pentax PEF neapdorotas paveikslėlis - Pentax PEF jēlattēls - Pentax PEF raw-bilde - onbewerkt Pentax PEF-beeld - Pentax PEF råbilete - Surowy obraz Pentax PEF - Imagem bruta PEF da Pentax - Imagine brută Pentax PEF - необработанное изображение Pentax PEF - Surový obrázok Pentax PEF - Surova slikovna datoteka Pentax PEF - Figurë raw Pentax PEF - Pentax PEF-råbild - цифровий негатив PEF Pentax - Ảnh thô Pentax PEF - Pentax PEF 原始图像 - Pentax PEF 原生影像 - PEF - Pentax Electronic Format - - - - - - Sigma X3F raw image - صورة Sigma X3F خامة - Suvoraja vyjava Sigma X3F - Изображение — Sigma X3F raw - imatge en cru de Sigma X3F - Surový obrázek Sigma X3F - Sigma X3F-råbillede - Sigma-X3F-Rohbild - ανεπεξέργαστη εικόνα Sigma X3F - Sigma X3F raw image - imagen en bruto X3F de Sigma - Sigma X3F irudi gordina - Sigma-X3F-raakakuva - Sigma X3F rámynd - image brute X3F Sigma - amhíomhá Sigma X3F - imaxe en bruto X3F de Sigma - תמונה גולמית של Sigma X3F - Sigma XF3 nyers kép - Citra mentah Sigma X3F - Immagine raw Sigma X3F - Sigma X3F raw 画像 - Sigma X3F өңделмеген суреті - 시그마 X3F 원본 이미지 - Sigma X3F neapdorotas paveikslėlis - Sigma X3F jēlattēls - Sigma X3F raw-bilde - onbewerkt Sigma X3F-beeld - Sigma X3F råbilete - Surowy obraz X3F Sigma - Imagem bruta X3F da Sigma - Imagine brută Sigma X3F - необработанное изображение Sigma X3F - Surový obrázok Sigma X3F - Surova slikovna datoteka Sigma X3F - Fifurë raw Sigma X3F - Sigma X3F-råbild - цифровий негатив X3F Sigma - Ảnh thô Sigma X3F - Sigma X3F 原始图像 - Sigma X3F 原生影像 - X3F - X3 Foveon - - - - - - - - - - - - Sony SRF raw image - صورة Sony SRF خامة - Suvoraja vyjava Sony SRF - Изображение — Sony SRF raw - imatge en cru de Sony SRF - Surový obrázek Sony SRF - Sony SRF-råbillede - Sony-SRF-Rohbild - ανεπεξέργαστη εικόνα Sony SRF - Sony SRF raw image - imagen en bruto SRF de Sony - Sony SRF irudi gordina - Sony-SRF-raakakuva - Sony SRF rámynd - image brute SRF Sony - amhíomhá Sony SRF - imaxe en bruto SRF de sony - תמונה גולמית של Sony SRF - Sony SRF nyers kép - Citra mentah Sony SRF - Immagine raw Sony SRF - Sony SRF raw 画像 - Sony SRF өңделмеген суреті - 소니 SRF 원본 이미지 - Sony SRF neapdorotas paveikslėlis - Sony SRF jēlattēls - Sony SRF raw-bilde - onbewerkt Sony SRF-beeld - Sony SRF råbilete - Surowy obraz SRF Sony - Imagem bruta SRF da Sony - Imagine brută Sony SRF - необработанное изображение Sony SRF - Surový obrázok Sony SRF - Surova slikovna datoteka Sony SRF - Figurë raw Sony SRF - Sony SRF-råbild - цифровий негатив SRF Sony - Ảnh thô Sony SRF - Sony SRF 原始映像 - Sony SRF 原生影像 - SRF - Sony Raw Format - - - - - - Sony SR2 raw image - صورة Sony SR2 خامة - Suvoraja vyjava Sony SR2 - Изображение — Sony SR2 raw - imatge en cru de Sony SR2 - Surový obrázek Sony SR2 - Sony SR2-råbillede - Sony-SR2-Rohbild - ανεπεξέργαστη εικόνα Sony SR2 - Sony SR2 raw image - imagen en bruto SR2 de Sony - Sony SR2 irudi gordina - Sony-SR2-raakakuva - Sony SR2 rámynd - image brute SR2 Sony - amhíomhá Sony SR2 - imaxe en bruto SR2 de sony - תמונה גולמית של Sony SR2 - Sony SR2 nyers kép - Citra mentah Sony SR2 - Immagine raw Sony SR2 - Sony SR2 raw 画像 - Sony SR2 өңделмеген суреті - 소니 SR2 원본 이미지 - Sony SR2 neapdorotas paveikslėlis - Sony SR2 jēlattēls - Sony SR2 raw-bilde - onbewerkt Sony SR2-beeld - Sony SR2 råbilete - Surowy obraz SR2 Sony - Imagem bruta SR2 da Sony - Imagine brută Sony SR2 - необработанное изображение Sony SR2 - Surový obrázok Sony SR2 - Surova slikovna datoteka Sony SR2 - Figurë raw Sony SR2 - Sony SR2-råbild - цифровий негатив SR2 Sony - Ảnh thô Sony SR2 - Sony SR2 原始映像 - Sony SR2 原生影像 - SR2 - Sony Raw format 2 - - - - - - Sony ARW raw image - صورة Sony ARW خامة - Suvoraja vyjava Sony ARW - Изображение — Sony ARW raw - imatge en cru de Sony ARW - Surový obrázek Sony ARW - Sony ARW-råbillede - Sony-ARW-Rohbild - ανεπεξέργαστη εικόνα Sony ARW - Sony ARW raw image - imagen en bruto ARW de Sony - Sony ARW irudi gordina - Sony-ARW-raakakuva - Sony ARW rámynd - image brute ARW Sony - amhíomhá Sony ARW - imaxe en bruto ARW de sony - תמונה גולמית של Sony ARW - Sony ARW nyers kép - Citra mentah Sony ARW - Immagine raw Sony ARW - Sony ARW raw 画像 - Sony ARW өңделмеген суреті - 소니 ARW 원본 이미지 - Sony ARW neapdorotas paveikslėlis - Sony ARW jēlattēls - Sony ARW raw-bilde - onbewerkt Sony ARW-beeld - Sony ARW råbilete - Surowy obraz ARW Sony - Imagem bruta ARW da Sony - Imagine brută Sony ARW - необработанное изображение Sony ARW - Surový obrázok Sony ARW - Surova slikovna datoteka Sony ARW - Figurë raw Sony ARW - Sony ARW-råbild - цифровий негатив ARW Sony - Ảnh thô Sony ARW - Sony ARW 原始映像 - Sony ARW 原生影像 - ARW - Alpha Raw format - - - - - - PNG image - صورة PNG - PNG rəsmi - Vyjava PNG - Изображение — PNG - imatge PNG - Obrázek PNG - Delwedd PNG - PNG-billede - PNG-Bild - εικόνα PNG - PNG image - PNG-bildo - imagen PNG - PNG irudia - PNG-kuva - PNG mynd - image PNG - íomhá PNG - imaxe PNG - תמונת PNG - PNG-kép - Citra PNG - Immagine PNG - PNG 画像 - PNG суреті - PNG 그림 - PNG paveikslėlis - PNG attēls - Imej PNG - PNG-bilde - PNG-afbeelding - PNG-bilete - Obraz PNG - imagem PNG - Imagem PNG - Imagine PNG - изображение PNG - Obrázok PNG - Slikovna datoteka PNG - Figurë PNG - PNG слика - PNG-bild - зображення PNG - Ảnh PNG - PNG 图像 - PNG 影像 - - - - - - - Apple optimised PNG image - - - - - - - - - Run Length Encoded bitmap image - تشغيل صورة نقطية طولية الترميز - Bitmapnaja vyjava, zakadavanaja ŭ Run Length - Изображение — RLE Bitmap - imatge de mapa de bits «Run Lenght Encoded» - Obrázek bitové mapy Run Length Encoded - Run Length Encoded-bitmapbillede - Lauflängenkodiertes Bitmap-Bild - Run Length Encoded bitmap image - mapa de bits con codificación del tamaño durante la ejecución - 'Run Lenght Encoded' bitmap irudia - RLE-koodattu bittikartta - image matricielle Run Length Encoded - íomhá mhapa giotáin Run Length Encoded - mapa de bits con codificación do tamaño durante a execución - מקודד מפת סיביות של Run Length - Run Length Encoded bitkép - Citra peta bit Run Length Encoded - Immagine bitmap RLE (Run Length Encoded) - ランレングス符号化ビットマップ画像 - RLE сығылған растрлік суреті - RLE 인코딩된 비트맵 그림 - Run Length Encoded rastrinis paveikslėlis - Secīgo atkārtojumu kodēts bitkartes attēls - Run Length Encoded bitmap bilde - RLE-gecodeerde bitmap-afbeelding - Run Length Encoded punktgrafikk - Obraz bitmapy RLE - Classe de comprimento imagem bitmap codificada - Imagine bitmap codată RLE - растровое изображение (сжатое RLE) - Bitmapový obrázok Run Length Encoded - Zaporedno kodirana bitna slika (RLE) - Figurë bitmap RLE (Run Length Encoded) - Körlängdskodad bitmappbild - растрове зображення RLE - Ảnh mảng mã hóa chiều dài chạy (RLE) - 游程编码位图 - Run Length Encoded 點陣影像 - - - - SVG image - صورة SVG - Vyjava SVG - Изображение — SVG - imatge SVG - Obrázek SVG - SVG-billede - SVG-Bild - εικόνα SVG - SVG image - SVG-bildo - imagen SVG - SVG irudia - SVG-kuva - SVG mynd - image SVG - íomhá SVG - imaxe SVG - תמונת SVG - SVG slika - SVG kép - Citra SVG - Immagine SVG - SVG 画像 - SVG суреті - SVG 그림 - SVG paveikslėlis - SVG attēls - SVG-bilde - SVG-afbeelding - SVG-bilete - Obraz SVG - Imagem SVG - Imagine SVG - изображение SVG - Obrázok SVG - Slikovna vektorska datoteka SVG - Figurë SVG - SVG-bild - SVG görüntüsü - зображення SVG - Ảnh SVG - SVG 图像 - SVG 影像 - SVG - Scalable Vector Graphics - - - - - - - - - - compressed SVG image - صورة SVG مضغوطة - skampresavanaja vyjava SVG - Изображение — SVG, компресирано - imatge SVG comprimida - Komprimovaný obrázek SVG - SVG-komprimeret billede - Komprimiertes SVG-Bild - συμπιεσμένη εικόνα SVG - compressed SVG image - imagen SVG comprimida - konprimitutako SVG irudia - pakattu SVG-kuva - stappað SVG mynd - image SVG compressée - íomhá SVG comhbhrúite - imaxe SVG comprimida - תמונת SVG מכוצת - komprimirana SVG slika - tömörített SVG kép - Citra SVG terkompresi - Immagine SVG compressa - 圧縮 SVG 画像 - сығылған SVG суреті - 압축된 SVG 그림 - suglaudintas SVG paveikslėlis - saspiests SVG attēls - komprimert SVG-bilde - ingepakte SVG-afbeelding - komprimert SVG-bilete - Skompresowany obraz SVG - Imagem compactada SVG - imagine comprimată SVG - сжатое изображение SVG - Komprimovaný obrázok SVG - Slikovna datoteka SVG (stisnjena) - Figurë SVG e kompresuar - komprimerad SVG-bild - стиснене зображення SVG - ảnh SVG đã nén - 压缩的 SVG 图像 - 壓縮版 SVG 影像 - SVG - Scalable Vector Graphics - - - - - TIFF image - صورة TIFF - Vyjava TIFF - Изображение — TIFF - imatge TIFF - Obrázek TIFF - TIFF-billede - TIFF-Bild - εικόνα TIFF - TIFF image - TIFF-bildo - imagen TIFF - TIFF irudia - TIFF-kuva - TIFF mynd - image TIFF - íomhá TIFF - imaxe TIFF - תמונת TIFF - TIFF slika - TIFF-kép - Citra TIFF - Immagine TIFF - TIFF 画像 - TIFF суреті - TIFF 그림 - TIFF paveikslėlis - TIFF attēls - Imej TIFF - TIFF-bilde - TIFF-afbeelding - TIFF-bilete - Obraz TIFF - imagem TIFF - Imagem TIFF - Imagine TIFF - изображение TIFF - Obrázok TIFF - Slikovna datoteka TIFF - Figurë TIFF - TIFF слика - TIFF-bild - зображення TIFF - Ảnh TIFF - TIFF 图像 - TIFF 影像 - TIFF - Tagged Image File Format - - - - - - - - - AutoCAD image - صورة AutoCAD - AutoCAD rəsmi - Vyjava AutoCAD - Изображение — AutoCAD - imatge d'AutoCAD - Obrázek AutoCAD - Delwedd AutoCAD - AutoCAD-billede - AutoCAD-Bild - εικόνα AutoCAD - AutoCAD image - AutoCAD-bildo - imagen de AutoCAD - AutoCAD-eko irudia - AutoCAD-kuva - AutoCAD mynd - image AutoCAD - íomhá AutoCAD - imaxe de AutoCAD - תמונה של AutoCAD - AutoCAD slika - AutoCAD-kép - Citra AutoCAD - Immagine AutoCAD - AutoCAD 画像 - AutoCAD-ის გამოსახულება - AutoCAD суреті - AutoCAD 그림 - AutoCAD paveikslėlis - AutoCAD attēls - Imej AutoCAD - AutoCAD-bilde - AutoCAD-afbeelding - AutoCAD-bilete - Obraz AutoCAD - imagem AutoCAD - Imagem do AutoCAD - Imagine AutoCAD - изображение AutoCAD - Obrázok AutoCAD - Slikovna datoteka AutoCAD - Figurë AutoCAD - AutoCAD слика - AutoCAD-bild - AutoCAD görüntüsü - зображення AutoCAD - Ảnh AutoCAD - AutoCAD 图像 - AutoCAD 影像 - - - - DXF vector image - صورة DXF نقطية - Vektarnaja vyjava DXF - Изображение — DXF - imatge vectorial DXF - Vektorový obrázek DXF - DXF-vektorbillede - DXF-Vektorbild - ανυσματική εικόνα DXF - DXF vector image - vektora DXF-bildo - imagen vectorial DXF - DXF bektore-grafikoa - DXF-vektorikuva - DXF vektormynd - image vectorielle DXF - íomhá veicteoir DXF - imaxe de vector DXF - תמונת DXF וקטורית - DXF vektorska slika - DXF-vektorkép - Citra vektor DXF - Immagine vettoriale DXF - DXF ベクター画像 - DXF ვექტორული გამოსახულება - DXF векторлық суреті - DXF 벡터 그림 - DXF vektorinis paveikslėlis - DXF vektora attēls - Imej vektor DXF - DXF-vektorgrafikk - DXF-vectorafbeelding - DXF-vektorgrafikk - Obraz wektorowy DXF - imagem de vectores DXF - Imagem vetorial DXF - Imagine vectorială DXF - векторное изображение DXF - Vektorový obrázok DXF - Slikovna vektorska datoteka DXF - Figurë vektoriale DFX - DXF векторска графика - DXF-vektorbild - векторне зображення DXF - Ảnh véc-tơ DXF - DXF 矢量图像 - DXF 向量圖 - - - - - - - - Microsoft Document Imaging format - صيغة مستند تصوير مايكروسوفت - Изображение — Microsoft Document Imaging - format Microsoft Document Imaging - Formát Microsoft Document Imaging - Microsofts dokumentbilledformat - Microsoft-Document-Imaging-Bildformat - μορφή Microsoft Document Imaging - Microsoft Document Imaging format - formato de imagen de Microsoft Document - Microsoft Document Imaging formatua - Microsoft Document Imaging -muoto - Microsoft Document Imaging snið - format Document Imaging Microsoft - formáid Microsoft Document Imaging - formato de Microsoft Document Imaging - פורמט של Microsoft Document Imaging - Microsoft Document Imaging formátum - Format Microsoft Document Imaging - Formato MDI (Microsoft Document Imaging) - Microsoft ドキュメントイメージフォーマット - Microsoft Document Imaging пішімі - 마이크로소프트 문서 이미지 형식 - Microsoft Document Imaging formatas - Microsoft dokumentu attēlošanas formāts - Microsoft Document Imaging - Format Microsoft Document Imaging - Formato do Microsoft Document Imaging - Format Microsoft Document Imaging - формат Microsoft Document Imaging - Formát Microsoft Document Imaging - Zapis Microsoft Document Imaging - Microsoft Document Imaging-format - формат Microsoft Document Imaging - Định dạng tạo ảnh tài liệu Microsoft - Microsoft Document Imaging 扫描图像 - 微軟文件影像格式 - MDI - Microsoft Document Imaging - - - - - - - 3D Studio image - صورة استديو ثلاثية الأبعاد - 3D Studio rəsmi - Vyjava 3D Studio - Изображение — 3D Studio - imatge de 3D Studio - Obrázek 3D Studio - Delwedd "3D Studio" - 3D Studio-billede - 3D-Studio-Bild - εικόνα 3D Studio - 3D Studio image - bildo de 3D Studio - imagen de 3D Studio - 3D Studio-ko irudia - 3D Studio -kuva - 3D Studio mynd - image 3D Studio - íomhá 3D Studio - imaxe de 3D Studio - תמונת 3D Studio - 3D Studio slika - 3D Studio-kép - Citra 3D Studio - Immagine 3D Studio - 3D Studio 画像 - 3D Studio-ის გამოსახულება - 3D Studio суреті - 3D Studio 그림 - 3D Studio paveikslėlis - 3D Studio attēls - Imej 3D Studio - 3D Studio-bilde - 3D-Studio-afbeelding - 3D Studio-bilete - Obraz 3D Studio - imagem 3D Studio - Imagem do 3D Studio - Imagine 3D Studio - сцена 3D Studio - Obrázok 3D Studio - Slikovna datoteka 3D Studio - Figurë 3D Studio - 3D Studio слика - 3D Studio-bild - 3D Studio görüntüsü - зображення 3D Studio - Ảnh xuởng vẽ 3D - 3D Studio 图像 - 3D Studio 影像 - - - - Applix Graphics image - صورة رسوميات Applix - Vyjava Applix Graphics - Изображение — Applix Graphics - imatge d'Applix Graphics - Obrázek Applix Graphics - Applix Graphics-billede - Applix-Graphics-Bild - εικόνα Applix Graphics - Applix Graphics image - bildo de Applix Graphics - imagen de Applix Graphics - Applix Graphics irudia - Applix Graphics -kuva - Applix Graphics mynd - image Applix Graphics - íomhá Applix Graphics - imaxe de Applix Graphics - תמונה של Applix Graphics - Applix Graphics slika - Applix Graphics-kép - Citra Applix Graphics - Immagine Applix Graphics - Applix Graphics 画像 - Applix Graphics-ის გამოსახულება - Applix Graphics суреті - Applix Graphics 그림 - Applix Graphics paveikslėlis - Applix Graphics attēls - Imej Applix Graphics - Applix Graphics-dokument - Applix Graphics-afbeelding - Applix Graphics-dokument - Obraz Applix Graphics - imagem Applix Graphics - Imagem do Applix Graphics - Imagine Applix Graphics - изображение Applix Graphics - Obrázok Applix Graphics - Slikovna datoteka Applix Graphics - Figurë Applix Graphics - Applix графички документ - Applix Graphics-bild - зображення Applix Graphics - Ảnh Applix Graphics - Applix Graphics 图像 - Applix Graphics 影像 - - - - - - - - - EPS image (bzip-compressed) - صورة EPS (مضغوط-bzip) - Vyjava EPS (bzip-skampresavanaja) - Изображение — EPS, компресирано с bzip - imatge EPS (comprimida amb bzip) - Obrázek EPS (komprimovaný pomocí bzip) - EPS-billede (bzip-komprimeret) - EPS-Bild (bzip-komprimiert) - EPS image (bzip-compressed) - imagen EPS (comprimida con bzip) - EPS irudia (bzip-ekin konprimitua) - EPS-kuva (bzip-pakattu) - EPS mynd (bzip-stappað) - image EPS (compressée bzip) - íomhá EPS (comhbhrúite le bzip) - imaxe EPS (comprimida con bzip) - תמונת EPS (מכווץ בbzip) - EPS slika (komprimirana bzip-om) - EPS kép (bzip-tömörítésű) - Citra EPS (terkompresi bzip) - Immagine EPS (compressa con bzip) - EPS 画像 (bzip 圧縮) - EPS გამოსახულება (bzip-ით შეკუმშული) - EPS суреті (bzip-пен сығылған) - EPS 그림 (BZIP 압축) - EPS paveikslėlis (suglaudintas su bzip) - EPS attēls (saspiests ar bzip) - EPS-bilde (bzip-komprimert) - EPS-afbeelding (ingepakt met bzip) - EPS-bilete (pakka med bzip) - Obraz EPS (kompresja bzip) - Imagem EPS (compactada com bzip) - Imagine EPS (compresie bzip) - изображение EPS (сжатое bzip) - Obrázok EPS (komprimovaný pomocou bzip) - Slikovna datoteka EPS (stisnjena z bzip) - Figurë EPS (e kompresuar me bzip) - EPS-bild (bzip-komprimerad) - EPS görüntüsü (bzip ile sıkıştırılmış) - зображення EPS (стиснене bzip) - Ảnh EPS (đã nén bzip) - EPS 图像(bzip 压缩) - EPS 影像 (bzip 格式壓縮) - - - - - - - CMU raster image - صورة CMU نقطية - CMU raster rəsmi - Rastravaja vyjava CMU - Изображение — CMU raster - imatge ràster CMU - Rastrový obrázek CMU - Delwedd raster CMU - CMU-rasterbillede - CMU-Rasterbild - εικόνα ράστερ CMU - CMU raster image - rastruma bildo de CMU - imagen ráster CMU - CMU bilbe-irudia - CMU-rasterikuva - CMU raster mynd - image raster CMU - íomhá rastar CMU - imaxe raster CMU - תמונת סריקה CMU - CMU-raszterkép - Citra raster CMU - Immagine raster CMU - CMU ラスター画像 - CMU-ის რასტრული გამოსახულება - CMU растрлық суреті - CMU 래스터 그림 - CMU rastrinis paveikslėlis - CMU rastra attēls - Imej raster CMU - CMU-rasterbilde - CMU-rasterafbeelding - CMU rasterbilete - Obraz rastrowy CMU - imagem rasterizada CMU - Imagem raster CMU - Imagine raster CMU - растровое изображение CMU - Rastrový obrázok CMU - Slikovna rastrska datoteka CMU - Figurë raster CMU - CMU растерска слика - CMU-rasterbild - растрове зображення CMU - Ảnh mành CMU - CMU 矢量图像 - CMU raster 影像 - - - - compressed GIMP image - صورة GIMP مضغوطة - skampresavanaja vyjava GIMP - Изображение — GIMP, компресирано - imatge GIMP comprimida - Komprimovaný obrázek GIMP - komprimeret GIMP-billede - Komprimiertes GIMP-Bild - συμπιεσμένη εικόνα GIMP - compressed GIMP image - imagen GIMP comprimida - konprimitutako GIMP irudia - pakattu GIMP-kuva - stappað GIMP mynd - image GIMP compressée - íomhá GIMP comhbhrúite - imaxe de GIMP comprimida - תמונת GIMP מכווצת - tömörített GIMP kép - Citra GIMP terkompresi - Immagine GIMP compressa - 圧縮 GIMP 画像 - сығылған GIMP суреті - 압축된 GIMP 그림 - suglaudintas GIMP paveikslėlis - saspiests GIMP attēls - komprimert GIMP-bilde - ingepakte GIMP-afbeelding - komprimert GIMP-bilete - Skompresowany obraz GIMP - Imagem compactada do GIMP - imagine comprimată GIMP - сжатое изображение GIMP - Komprimovaný obrázok GIMP - Slikovna datoteka GIMP (stisnjena) - Figurë GIMP e kompresuar - komprimerad GIMP-bild - стиснене зображення GIMP - ảnh GIMP đã nén - 压缩的 GIMP 图像 - 壓縮版 GIMP 影像 - - - - - DICOM image - صورة DICOM - Vyjava DICOM - Изображение — DICOM - imatge DICOM - Obrázek DICOM - DICOM-billede - DICOM-Bild - εικόνα DICOM - DICOM image - DICOM-bildo - imagen DICOM - DICOM irudia - DICOM-kuva - DICOM mynd - image DICOM - íomhá DICOM - imaxe DICOM - תמונת DICOM - DICOM slika - DICOM kép - Citra DICOM - Immagine DICOM - DICOM 画像 - DICOM გამოსახულება - DICOM суреті - DICOM 그림 - DICOM paveikslėlis - DICOM attēls - DICOM-bilde - DICOM-afbeelding - DICOM-bilete - Obraz DICOM - Imagem DICOM - Imagine DICOM - изображение DICOM - Obrázok DICOM - Slikovna datoteka DICOM - Figurë DICOM - DICOM-bild - DICOM görüntüsü - зображення DICOM - Ảnh DICOM - DICOM 图像 - DICOM 影像 - DICOM - Digital Imaging and Communications in Medicine - - - - - - - - - DocBook document - مستند DocBook - Dakument DocBook - Документ — DocBook - document DocBook - Dokument DocBook - DocBook-dokument - DocBook-Dokument - έγγραφο DocBook - DocBook document - DocBook-dokumento - documento DocBook - DocBook dokumentua - DocBook-asiakirja - DocBook skjal - document DocBook - cáipéis DocBook - documento de DocBook - מסמך DocBook - DocBook dokument - DocBook dokumentum - Dokumen DocBook - Documento DocBook - DocBook ドキュメント - DocBook-ის დოკუმენტი - DocBook құжаты - DocBook 문서 - DocBook dokumentas - DocBook dokuments - DocBook-dokument - DocBook-document - DocBook-dokument - Dokument DocBook - Documento DocBook - Document DocBook - документ DocBook - Dokument DocBook - Dokument DocBook - Dokument DocBook - DocBook-dokument - DocBook belgesi - документ DocBook - Tài liệu DocBook - DocBook 文档 - DocBook 文件 - - - - - - - - - - - - - - DIB image - صورة DIB - Vyjava DIB - Изображение — DIB - imatge DIB - Obrázek DIB - DIB-billede - DIB-Bild - εικόνα DIB - DIB image - DIB-bildo - imagen DIB - DIB irudia - DIB-kuva - DIB mynd - image DIB - íomhá DIB - imaxe DIB - תמונת DIB - DIB slika - DIB kép - Citra DIB - Immagine DIB - DIB 画像 - DIB გამოსახულება - DIB суреті - DIB 그림 - DIB paveikslėlis - DIB attēls - DIB-bilde - DIB-afbeelding - DIB-bilete - Obraz DIB - Imagem DIB - Imagine DIB - изображение DIB - Obrázok DIB - Slikovna datoteka DIB - Figurë DIB - DIB-bild - DIB görüntüsü - зображення DIB - Ảnh DIB - DIB 图像 - DIB 影像 - DIB - Device Independent Bitmap - - - - - - DjVu image - صورة DjVu - Vyjava DjVu - Изображение — DjVu - imatge DjVu - Obrázek DjVu - DjVu-billede - DjVu-Bild - εικόνα DjVu - DjVu image - DjVu-bildo - imagen DjVu - DjVU-ko irudia - DjVu-kuva - DjVu mynd - image DjVu - íomhá DjVu - imaxe de DjVu - תמונת DjVu - DjVu slika - DjVu-kép - Citra DjVu - Immagine DjVu - DjVu 画像 - DjVu გამოსახულება - DjVu суреті - DjVu 그림 - DjVu paveikslėlis - DjVu attēls - Imej DjVu - DjVu-bilde - DjVu-afbeelding - DjVu-bilete - Obraz DjVu - imagem DjVu - Imagem DjVu - Imagine DjVu - изображение DjVu - Obrázok DjVu - Slikovna datoteka DjVu - Figurë DjVu - DjVu слика - DjVu-bild - DjVu görüntüsü - зображення DjVu - Ảnh DjVu - DjVu 图像 - DjVu 影像 - - - - - - - - - - - - - - - - - DPX image - صورة DPX - Vyjava DPX - Изображение — DPX - imatge DPX - Obrázek DPX - DPX-billede - DPX-Bild - εικόνα DPX - DPX image - DPX-bildo - imagen DPX - DPX irudia - DPX-kuva - DPX mynd - image DPX - íomhá DPX - imaxe DPX - תמונת DPX - DPX slika - DPX kép - Citra DPX - Immagine DPX - DPX 画像 - DPX გამოსახულება - DPX суреті - DPX 그림 - DPX paveikslėlis - DPX attēls - DPX-bilde - DPX-afbeelding - DPX-bilete - Obraz DPX - Imagem DPX - Imagine DPX - изображение DPX - Obrázok DPX - Slikovna datoteka DPX - Figurë DPX - DPX-bild - DPX görüntüsü - зображення DPX - Ảnh DPX - DPX 图像 - DPX 影像 - DPX - Digital Moving Picture Exchange - - - - - - EPS image - صورة EPS - Vyjava EPS - Изображение — EPS - imatge EPS - Obrázek EPS - EPS-billede - EPS-Bild - εικόνα EPS - EPS image - EPS-bildo - imagen EPS - EPS irudia - EPS-kuva - EPS mynd - image EPS - íomhá EPS - imaxe EPS - תמונת EPS - EPS slika - EPS kép - Citra EPS - Immagine EPS - EPS 画像 - EPS გამოსახულება - EPS суреті - EPS 그림 - EPS paveikslėlis - EPS attēls - EPS-bilde - EPS-afbeelding - EPS-bilete - Obraz EPS - Imagem EPS - Imagine EPS - изображение EPS - Obrázok EPS - Slikovna datoteka EPS - Figurë EPS - EPS-bild - EPS görüntüsü - зображення EPS - Ảnh EPS - EPS 图像 - EPS 影像 - EPS - Encapsulated PostScript - - - - - - - - - - - - - - - - FITS document - مستند FITS - Dakument FITS - Документ — FITS - document FITS - Dokument FITS - FITS-dokument - FITS-Dokument - έγγραφο FITS - FITS document - FITS-dokumento - documento FITS - FITS dokumentua - FITS-asiakirja - FITS skjal - document FITS - cáipéis FITS - documento FICT - מסמך FITS - FITS dokument - FITS dokumentum - Dokumen FITS - Documento FITS - FITS ドキュメント - FITS დოკუმენტი - FITS құжаты - FITS 문서 - FITS dokumentas - FITS dokuments - FITS-dokument - FITS-document - FITS-dokument - Dokument FITS - Documento FITS - Document FITS - документ FITS - Dokument FITS - Dokument FITS - Dokument FITS - FITS-dokument - документ FITS - Tài liệu FITS - FITS 文档 - FITS 文件 - FITS - Flexible Image Transport System - - - - - - - - FPX image - صورة FPX - Vyjava FPX - Изображение — FPX - imatge FPX - Obrázek FPX - FPX-billede - FPX-Bild - εικόνα FPX - FPX image - FPX-bildo - imagen FPX - FPX irudia - FPX-kuva - FPX mynd - image FPX - íomhá FPX - imaxe FPX - תמונת FPX - FPX slika - FPX kép - Citra FPX - Immagine FPX - FPX 画像 - FPX გამოსახულება - FPX суреті - FPX 그림 - FPX paveikslėlis - FPX attēls - FPX-bilde - FPX-afbeelding - FPX-bilete - Obraz FPX - Imagem FPX - Imagine FPX - изображение FPX - Obrázok FPX - Slikovna datoteka FPX - Figurë FPX - FPX-bild - FPX görüntüsü - зображення FPX - Ảnh FPX - FPX 图像 - FPX 影像 - FPX - FlashPiX - - - - - - EPS image (gzip-compressed) - صورة EPS (مضغوط-gzip) - Vyjava EPS (gzip-skampresavanaja) - Изображение — EPS, компресирано с gzip - imatge EPS (comprimida amb gzip) - Obrázek EPS (komprimovaný pomocí gzip) - EPS-billede (gzip-komprimeret) - EPS-Bild (gzip-komprimiert) - EPS image (gzip-compressed) - imagen EPS (comprimida con gzip) - EPS irudia (gzip-ekin konprimitua) - EPS-kuva (gzip-pakattu) - EPS mynd (gzip-stappað) - image EPS (compressée gzip) - íomhá EPS (comhbhrúite le gzip) - imaxe EPS (comprimida con gzip) - תמונת EPS (מכווץ בgzip) - EPS slika (komprimirana gzip-om) - EPS kép (gzip-tömörítésű) - Citra EPS (terkompresi gzip) - Immagine EPS (compressa con gzip) - EPS 画像 (gzip 圧縮) - EPS გამოსახულება (gzip-ით შეკუმშული) - EPS суреті (gzip-пен сығылған) - EPS 그림 (GZIP 압축) - EPS paveikslėlis (suglaudintas su gzip) - EPS attēls (saspiests ar gzip) - EPS-bilde (gzip-komprimert) - EPS-afbeelding (ingepakt met gzip) - EPS-bilete (pakka med gzip) - Obraz EPS (kompresja gzip) - Imagem EPS (compactada com gzip) - Imagine EPS (compresie gzip) - изображение EPS (сжатое gzip) - Obrázok EPS (komprimovaný pomocou gzip) - Slikovna datoteka EPS (stisnjena z gzip) - Figurë EPS (e kompresuar me gzip) - EPS-bild (gzip-komprimerad) - EPS görüntüsü (gzip ile sıkıştırılmış) - зображення EPS (стиснене gzip) - Ảnh EPS (đã nén gzip) - EPS 图像(gzip 压缩) - EPS 影像 (gzip 格式壓縮) - - - - - - - Microsoft icon - أيقونة مايكروسوفت - Икона — Microsoft - icona de Microsoft - Ikona Microsoft - Microsoftikon - Microsoft-Symbol - εικονίδιο Microsoft - Microsoft icon - Microsoft-piktogramo - icono de Microsoft - Microsoft ikonoa - Microsoft-kuvake - Microsoft ímynd - icône Microsoft - deilbhín Microsoft - Icona de microsoft - אייקון של Microsofr - Microsoft ikona - Microsoft ikon - Ikon Microsoft - Icona Microsoft - Microsoft アイコン - Microsoft-ის ხატულა - Microsoft таңбашасы - 마이크로소프트 아이콘 - Microsoft piktograma - Microsoft ikona - Microsoft pictogram - Ikona Microsoft - Ícone da Microsoft - Iconiță Microsoft - значок Microsoft - Ikona Microsoft - Datoteka ikone Microsoft Windows - Microsoft-ikon - піктограма Microsoft - Biểu tượng Microsoft - Microsoft 图标 - 微軟圖示 - - - - - - - - - - - - - - - MacOS X icon - أيقونة MacOS X - Ikona MacOS X - Икона — MacOS X - icona MacOS X - Ikona MacOS X - MacOS X-ikon - MacOS-X-Symbol - εικονίδιο MacOS X - MacOS X icon - MacOS-X-piktogramo - icono de MacOS X - MacOS X ikonoa - MacOS X -kuvake - MacOS X ímynd - icône MacOS X - deilbhín MacOS X - Icona de MacOS X - אייקון של MacOS X - MacOS X ikona - MacOS X ikon - Ikon MacOS X - Icona MacOS X - MacOS X アイコン - MacOS X-ის ხატულა - MacOS X таңбашасы - MacOS X 아이콘 - MacOS X piktograma - MacOS X ikona - MacOS X-ikon - MacOS-X-pictogram - MacOS X-ikon - Ikona Mac OS X - Ícone do MacOS X - Iconiță MacOS X - значок MacOS X - Ikona MacOS X - Datoteka ikone MacOS X - Ikonë MacOS X - MacOS X-ikon - піктограма MacOS X - Biểu tượng MacOS X - MacOS X 图标 - MacOS X 圖示 - - - - - - - ILBM image - صورة ILBM - ILBM rəsmi - Vyjava ILBM - Изображение — ILBM - imatge ILBM - Obrázek ILMB - Delwedd ILBM - ILBM-billede - ILBM-Bild - εικόνα ILBM - ILBM image - ILBM-bildo - imagen ILBM - ILBM irudia - ILBM-kuva - ILBM mynd - image ILBM - íomhá ILBM - imaxe ILBM - תמונת ILBM - ILBM slika - ILBM-kép - Citra ILBM - Immagine ILBM - ILBM 画像 - ILBM суреті - ILBM 그림 - ILBM paveikslėlis - ILBM attēls - Imej ILBM - ILBM-bilde - ILBM-afbeelding - ILMB-bilete - Obraz ILBM - imagem ILBM - Imagem ILBM - Imagine ILBM - изображение ILBM - Obrázok ILMB - Slikovna datoteka ILBM - Figurë ILBM - ILBM слика - ILBM-bild - зображення ILBM - Ảnh ILBM - ILBM 图像 - ILBM 影像 - ILBM - InterLeaved BitMap - - - - - - - - - - - - JNG image - صورة JNG - JNG rəsmi - Vyjava JNG - Изображение — JNG - imatge JNG - Obrázek JNG - Delwedd JNG - JNG-billede - JNG-Bild - εικόνα JNG - JNG image - JNG-bildo - imagen JNG - JNG irudia - JNG-kuva - JNG mynd - image JNG - íomhá JNG - imaxe JNG - תמונת JNG - JNG slika - JNG-kép - Citra JNG - Immagine JNG - JNG 画像 - JNG суреті - JNG 그림 - JNG paveikslėlis - JNG attēls - Imej PNG - JNG-bilde - JNG-afbeelding - JNG-bilete - Obraz JNG - imagem JNG - Imagem JNG - Imagine JNG - изображение JNG - Obrázok JNG - Slikovna datoteka JNG - Figurë JNG - JNG слика - JNG-bild - JNG görüntüsü - зображення JNG - Ảnh JNG - JNG 图像 - JNG 影像 - JNG - JPEG Network Graphics - - - - LightWave object - كائن LightWave - LightWave cismi - Abjekt LightWave - Обект — LightWave - objecte de LightWave - Objekt LightWave - Gwrthrych LightWave - LightWave-objekt - LightWave-Objekt - αντικείμενο LightWave - LightWave object - LightWave-objekto - objeto LightWave - LightWave objektua - LightWave-esine - LightWave lutur - objet LightWave - réad LightWave - obxecto de LightWave - עצם LightWave - LightWave objekt - LightWave-objektum - Proyek LightWave - Oggetto LightWave - LightWave オブジェクト - LightWave объекті - LightWave 개체 - LightWave objektas - LightWave objekts - Objek LightWave - LightWave-objekt - LightWave-object - LightWave-objekt - Obiekt LightWave - Objecto LightWave - Objeto LightWave - Obiect LightWave - объект LightWave - Objekt LightWave - Datoteka predmeta LightWave - Objekt LightWave - LightWave објекат - LightWave-objekt - LightWave nesnesi - об'єкт LightWave - Đối tượng LightWave - LightWave 对象 - LightWave 物件 - - - - - LightWave scene - مشهد LightWave - LightWave səhnəsi - Scena LightWave - Сцена — LightWave - escena de LightWave - Scéna LightWave - Golygfa LightWave - LightWave-scene - LightWave-Szene - σκηνή LightWave - LightWave scene - LightWave-sceno - escena LightWave - LightWave eszena - LightWave-maisema - LightWave leikmynd - scène LightWave - radharc LightWave - escena de LightWave - סצנה של LightWave - LightWave scena - LightWave-jelenet - Scene LightWave - Scena LightWave - LightWave シーン - LightWave сахнасы - LightWave 장면 - LightWave scena - LightWave aina - Babak LightWave - LightWave-scene - LightWave-scène - LightWave-scene - Scena Lightwave - cenário LightWave - Cena LightWave - Scenă LightWave - сцена LightWave - Scéna LightWave - Datoteka scene LightWave - Skenë LightWave - LightWave сцена - LightWave-scen - сцена LightWave - Cảnh LightWave - LightWave 场景 - LightWave 場景 - - - - MacPaint Bitmap image - صورة MacPaint Bitmap - Bitmapnaja vyjava MacPaint - Изображение — MacPaint Bitmap - imatge de mapa de bits MacPaint - Obrázek MacPaint Bitmap - MacPaint BitMap-billede - MacPaint-Bitmap-Datei - εικόνα Bitmap MacPaint - MacPaint Bitmap image - imagen en mapa de bits de MacPaint - MacPaint Bitmap irudia - MacPaint-bittikartta - MacPaint Bitmap mynd - image matricielle MacPaint - íomhá MacPaint Bitmap - imaxe de mapa de bits MacPaint - תמונת מפת-סיביות של MacPaint - MacPaint bitkép - Citra MacPaint Bitmap - Immagine Bitmap MacPaint - MacPaint ビットマップ画像 - MacPaint растрлық суреті - MacPaint 비트맵 그림 - MacPaint rastrinis paveikslėlis - MacPaint bitkartes attēls - MacPaint Bitmap-bilde - MacPaint-bitmap-afbeelding - MacPaint punktbilete - Obraz bitmapowy MacPaint - Imagem de bitmap do MacPaint - Imagine MacPaint Bitmap - растровое изображение MacPaint - Obrázok MacPaint Bitmap - Slikovna bitna datoteka MacPaint - Figurë BitMap MacPaint - MacPaint Bitmap-bild - растрове зображення MacPaint - Ảnh mảng MacPaint - MacPaint 位图 - MacPaint 點陣影像 - - - - Office drawing - تصميم أوفيس - Ofisny rysunak - Чертеж — Office - dibuix d'Office - Kresba Office - Officetegning - Office-Zeichnung - σχέδιο Office - Office drawing - dibujo de Office - Office marrazkia - Office-piirros - Office tekning - dessin Office - líníocht Office - debuxo de Office - ציור של Office - Office rajz - Gambar Office - Disegno Office - Office ドロー - Office суреті - 오피스 드로잉 - Office piešinys - Office zīmējums - Office-tegning - Office-tekening - Office-teikning - Rysunek Office - Desenho do Office - Desen Office - изображение Office - Kresba Office - Datoteka risbe Office - Vizatim Office - Office-teckning - малюнок Office - Bản vẽ Office - Microsoft Office 绘图 - Office 繪圖 - - - - NIFF image - صورة NIFF - Vyjava NIFF - Изображение — NIFF - imatge NIFF - Obrázek NIFF - NIFF-billede - NIFF-Bild - εικόνα NIFF - NIFF image - NIFF-bildo - imagen NIFF - NIFF irudia - NIFF-kuva - NIFF mynd - image NIFF - íomhá NIFF - imaxe NIFF - תמונת NIFF - NIFF slika - NIFF kép - Citra NIFF - Immagine NIFF - NIFF 画像 - NIFF суреті - NIFF 그림 - NIFF paveikslėlis - NIFF attēls - NIFF-bilde - NIFF-afbeelding - NIFF-bilete - Obraz NIFF - Imagem NIFF - Imagine NIF - изображение NIFF - Obrázok NIFF - Slikovna datoteka NIFF - Figurë NIFF - NIFF-bild - NIFF görüntüsü - зображення NIFF - Ảnh NIFF - NIFF 图像 - NIFF 影像 - - - - - - PCX image - صورة PCX - Vyjava PCX - Изображение — PCX - imatge PCX - Obrázek PCX - PCX-billede - PCX-Bild - εικόνα PCX - PCX image - PCX-bildo - imagen PCX - PCX irudia - PCX-kuva - PCX mynd - image PCX - íomhá PCX - imaxe PCX - תמונת PCX - PCX kép - Citra PCX - Immagine PCX - PCX 画像 - PCX суреті - PCX 그림 - PCX paveikslėlis - PCX attēls - PCX-bilde - PCX-afbeelding - PCX-bilete - Obraz PCX - Imagem PCX - Imagine PCX - изображение PCX - Obrázok PCX - Slikovna datoteka PCX - Figurë PCX - PCX-bild - PCX görüntüsü - зображення PCX - Ảnh PCX - PCX 图像 - PCX 影像 - PCX - PiCture eXchange - - - - - - - - - - - - PCD image - صورة PCD - Vyjava PCD - Изображение — PCD - imatge PCD - Obrázek PCD - PCD-billede - PCD-Bild - εικόνα PCD - PCD image - PCD-bildo - imagen PCD - PCD irudia - PCD-kuva - PCD mynd - image PCD - íomhá PCD - imaxe PCD - תמונת PCD - PCD kép - Citra PCD - Immagine PCD - PCD 画像 - PCD გამოსახულება - PCD суреті - PCD 그림 - PCD paveikslėlis - PCD attēls - PCD-bilde - PCD-afbeelding - PCD-bilete - Obraz PCD - Imagem PCD - Imagine PCD - изображение PCD - Obrázok PCD - Slikovna datoteka PCD - Figurë PCD - PCD-bild - PCD görüntüsü - зображення PCD - Ảnh PCD - PCD 图像 - PCD 影像 - PCD - PhotoCD - - - - PNM image - صورة PNM - PNM rəsmi - Vyjava PNM - Изображение — PNM - imatge PNM - Obrázek PNM - Delwedd PNM - PNM-billede - PNM-Bild - εικόνα PNM - PNM image - PNM-bildo - imagen PNM - PNM irudia - PNM-kuva - PNM mynd - image PNM - íomhá PNM - imaxe PNM - תמונת PNM - PNM-kép - Citra PNM - Immagine PNM - PNM 画像 - PNM суреті - PNM 그림 - PNM paveikslėlis - PNM attēls - Imej PNM - PNM-bilde - PNM-afbeelding - PNM-bilete - Obraz PNM - imagem PNM - Imagem PNM - Imagine PNM - изображение PNM - Obrázok PNM - Slikovna datoteka PNM - Figurë PNM - PNM слика - PNM-bild - PNM görüntüsü - зображення PNM - Ảnh PNM - PNM 图像 - PNM 影像 - - - - PBM image - صورة PBM - Vyjava PBM - Изображение — PBM - imatge PBM - Obrázek PBM - Delwedd PBM - PBM-billede - PBM-Bild - εικόνα PBM - PBM image - PBM-bildo - imagen PBM - PBM irudia - PBM-kuva - PBM mynd - image PBM - íomhá PBM - imaxe PBM - תמונת PBM - PBM kép - Citra PBM - Immagine PBM - PBM 画像 - PBM გამოსახულება - PBM суреті - PBM 그림 - PBM paveikslėlis - PBM attēls - PBM-bilde - PBM-afbeelding - PBM-bilete - Obraz PBM - Imagem PBM - Imagine PBM - изображение PBM - Obrázok PBM - Slikovna datoteka PBM - Figurë PBM - PBM слика - PBM-bild - PBM görüntüsü - зображення PBM - Ảnh PBM - PBM 图像 - PBM 影像 - PBM - Portable BitMap - - - - - - - - - - - - - - - - - - - PGM image - صورة PGM - Vyjava PGM - Изображение — PGM - imatge PGM - Obrázek PGM - Delwedd PGM - PGM-billede - PGM-Bild - εικόνα PGM - PGM image - PGM-bildo - imagen PGM - PGM irudia - PGM-kuva - PGM mynd - image PGM - íomhá PGM - imaxe PGM - תמונת PGM - PGM kép - Citra PGM - Immagine PGM - PGM 画像 - PGM суреті - PGM 그림 - PGM paveikslėlis - PGM attēls - PGM-bilde - PGM-afbeelding - PGM-bilete - Obraz PGM - Imagem PGM - Imagine PGM - изображение PGM - Obrázok PGM - Slikovna datoteka PGM - Figurë PGM - PGM-bild - PGM görüntüsü - зображення PGM - Ảnh PGM - PGM 图像 - PGM 影像 - PGM - Portable GrayMap - - - - - - - - - - - - - - - - - - - PPM image - صورة PPM - Vyjava PPM - Изображение — PPM - imatge PPM - Obrázek PPM - Delwedd PPM - PPM-billede - PPM-Bild - εικόνα PPM - PPM image - PPM-bildo - imagen PPM - PPM irudia - PPM-kuva - PPM mynd - image PPM - íomhá PPM - imaxe PPM - תמונת PPM - PPM kép - Citra PPM - Immagine PPM - PPM 画像 - PPM суреті - PPM 그림 - PPM paveikslėlis - PPM attēls - PPM-bilde - PPM-afbeelding - PPM-bilete - Obraz PPM - Imagem PPM - Imagine PPM - изображение PPM - Obrázok PPM - Slikovna datoteka PPM - Figurë PPM - PPM слика - PPM-bild - PPM görüntüsü - зображення PPM - Ảnh PPM - PPM 图像 - PPM 影像 - PPM - Portable PixMap - - - - - - - - - - - - - - - - - - - Photoshop image - صورة فوتوشوب - Изображение — Photoshop - imatge de Photoshop - Obrázek Photoshop - Photoshop-billede - Photoshop-Bild - εικόνα Photoshop - Photoshop image - Photoshop-bildo - imagen de Photoshop - Photoshop irudia - Photoshop-kuva - Photoshop mynd - image Photoshop - íomhá Photoshop - imaxe de Photoshop - תמונת Photoshop - Photoshop-kép - Citra Photoshop - Immagine Photoshop - Photoshop 画像 - изображение Photoshop - 포토샵 이미지 - Photoshop paveikslėlis - Photoshop attēls - Imej Photoshop - Photoshop-afbeelding - Obraz Photoshop - imagem do Photoshop - Imagem do Photoshop - Imagine Photoshop - изображение Photoshop - Obrázok Photoshop - Slikovna datoteka Photoshop - Фотошоп слика - Photoshop-bild - Photoshop görüntüsü - зображення Photoshop - Ảnh Photoshop - Photoshop 图像 - Photoshop 影像 - - - - - - - - - - - - - RGB image - صورة RGB - RGB rəsmi - Vyjava RGB - Изображение — RGB - imatge RGB - Obrázek RGB - Delwedd RGB - RGB-billede - RGB-Bild - εικόνα RGB - RGB image - RGB-bildo - imagen RGB - RGB irudia - RGB-kuva - RGB mynd - image RGB - íomhá RGB - imaxe RGB - תמונת RGB - RGB slika - RGB-kép - Citra RGB - Immagine RGB - RGB 画像 - RGB суреті - RGB 그림 - RGB paveikslėlis - RGB attēls - Imej RGB - RGB-bilde - RGB-afbeelding - RGB-bilete - Obraz RGB - imagem RGB - Imagem RGB - Imagine RGB - изображение RGB - Obrázok RGB - Slikovna datoteka RGB - Figurë RGB - RGB слика - RGB-bild - зображення RGB - Ảnh kiểu RGB - RGB 图像 - RGB 影像 - - - - SGI image - صورة SGI - Vyjava SGI - Изображение — SGI - imatge SGI - Obrázek SGI - SGI-billede - SGI-Bild - εικόνα SGI - SGI image - SGI-bildo - imagen SGI - SGI irudia - SGI-kuva - SGI mynd - image SGI - íomhá SGI - imaxe SGI - תמונת SGI - SGI slika - SGI kép - Citra SGI - Immagine SGI - SGI 画像 - SGI суреті - SGI 그림 - SGI paveikslėlis - SGI attēls - SGI-bilde - SGI-afbeelding - SGI-bilete - Obraz SGI - Imagem SGI - Imagine SGI - изображение SGI - Obrázok SGI - Slikovna datoteka SGI - Figurë SGI - SGI-bild - SGI görüntüsü - зображення SGI - Ảnh SGI - SGI 图像 - SGI 影像 - - - - Sun raster image - صورة Sun raster - Rastravaja vyjava Sun - Изображение — Sun raster - imatge ràster Sun - Rastrový obrázek Sun - Sun rasterbillede - Sun-Rasterbild - εικόνα Sun raster - Sun raster image - imagen ráster de Sun - Sun raster irudia - Sun-rasterikuva - Sun raster mynd - image raster Sun - íomhá rastar Sun - imaxe ráster de Sun - תמונה סרוקה של Sun - SUN raszterkép - Citra raster Sun - Immagine raster Sun - Sun ラスタ画像 - Sun растрлық суреті - Sun 래스터 그림 - Sun rastrinis paveikslėlis - Sun rastra attēls - Sun rasterbilde - Sun-rasterafbeelding - Sun rasterbilete - Obraz rastrowy Sun - Imagem raster da Sun - Imagine rasterizată Sun - растровое изображение Sun - Rastrový obrázok Sun - Slikovna rastrska datoteka Sun - Figurë raster Sun - Sun-rasterbild - растрове зображення Sun - Ảnh mành Sun - Sun 光栅图像 - Sun raster 影像 - - - - - - - TGA image - صورة TGA - Vyjava TGA - Изображение — TGA - imatge TGA - Obrázek TGA - TGA-billede - TGA-Bild - εικόνα TGA - TGA image - TGA-bildo - imagen TGA - TGA irudia - TGA-kuva - TGA mynd - image TGA - íomhá TGA - imaxe TGA - תמונת TGA - TGA slika - TGA kép - Citra TGA - Immagine TGA - TGA 画像 - TGA суреті - TGA 그림 - TGA paveikslėlis - TGA attēls - TGA-bilde - TGA-afbeelding - TGA-bilete - Obraz TGA - Imagem TGA - Imagine TGA - изображение TGA - Obrázok TGA - Slikovna datoteka TGA - Figurë TGA - TGA-bild - зображення TGA - Ảnh TGA - TGA 图像 - TGA 影像 - TGA - Truevision Graphics Adapter - - - - - - - - - - - - - - - - - - - - - - - - Windows cursor - مؤشر ويندوز - Kursor Windows - Курсор — Windows - cursor de Windows - Kurzor Windows - Windowsmarkør - Windows-Cursor - δείκτης παραθυρικού περιβάλλοντος - Windows cursor - Windows-kursoro - cursor de Windows - Windows kurtsorea - Windows-osoitin - Windows vísi - curseur Windows - cúrsóir Windows - Cursor de Windows - סמן של Windows - Windows kursor - Windows-kurzor - Kursor Windows - Cursore Windows - Windows カーソル - Windows курсоры - Windows 커서 - Windows žymiklis - Windows kursors - Kursor Windows - Windows-markør - Windows-muisaanwijzer - Windows-peikar - Kursor Windows - cursor Windows - Cursor do Windows - Cursor Windows - курсор Windows - Kurzor Windows - Datoteka kazalke Windows - Kursor Windows - Виндуз курзор - Windows-muspekare - курсор Windows - Con chạy Windows - Windows 光标 - Windows 滑鼠指標 - - - - - - - - - Windows animated cursor - مؤشر ويندوز المتحرك - Animavany kursor Windows - Курсор — Windows, анимиран - cursor animat de Windows - Animovaný kurzor Windows - Windowsanimeret markør - Animierter Windows-Cursor - κινούμενος δρομέας Windows - Windows animated cursor - cursor animado de Windows - Windows-eko kurtsore animatua - animoitu Windows-osoitin - Windows livindaigjørdur vísi - curseur animé Windows - cúrsóir beo Windows - Cursor animado de Windows - סמן מונפש של Windows - Windows animirani kursor - Windows animált kurzor - Kursor animasi Windows - Cursore animato Windows - Windows アニメーションカーソル - Windows анимациясы бар курсор - Windows 움직이는 커서 - Animuotas Windows žymiklis - Windows animēts kursors - geanimeerde Windows-muisaanwijzer - Windows animert peikar - Animowany kursor Windows - Cursor animado do Windows - Cursor animat Windows - анимированный курсор Windows - Animovaný kurzor Windows - Datoteka animirane kazalke Windows - Kursor i animuar Windows - Animerad Windows-muspekare - анімований курсор Windows - Con chạy hoạt họa Windows - Windows 动画光标 - Windows 滑鼠動畫游標 - - - - - - - - - EMF image - صورة EMF - Vyjava EMF - Изображение — EMF - imatge EMF - Obrázek EMF - EMF-billede - EMF-Bild - εικόνα EMF - EMF image - EMF-bildo - imagen EMF - EMF irudia - EMF-kuva - EMF mynd - image EMF - íomhá EMF - imaxe EMF - תמונת EMF - EMF slika - EMF kép - Citra EMF - Immagine EMF - EMF 画像 - EMF გამოსახულება - EMF суреті - EMF 그림 - EMF paveikslėlis - EMF attēls - EMF-bilde - EMF-afbeelding - EMF-bilete - Obraz EMF - Imagem EMF - Imagine EMF - изображение EMF - Obrázok EMF - Slikovna datoteka EMF - Figurë EMF - EMF-bild - EMF görüntüsü - зображення EMF - Ảnh EMF - EMF 图像 - EMF 影像 - EMF - Enhanced MetaFile - - - - - - - - - - - - - - - - WMF image - صورة WMF - Vyjava WMF - Изображение — WMF - imatge WMF - Obrázek WMF - WMF-billede - WMF-Bild - εικόνα WML - WMF image - WMF-bildo - imagen WMF - WMF irudia - WMF-kuva - WMF mynd - image WMF - íomhá WMF - imaxe WMF - תמונת WMF - WMF slika - WMF kép - Citra WMF - Immagine WMF - WMF 画像 - WMF суреті - WMF 그림 - WMF paveikslėlis - WMF attēls - WMF-bilde - WMF-afbeelding - WMF-bilete - Obraz WMF - Imagem WMF - Imagine WMF - изображение WMF - Obrázok WMF - Slikovna datoteka WMF - Figurë WMF - WMF-bild - WMF görüntüsü - зображення WMF - Ảnh WMF - WMF 图像 - WMF 影像 - WMF - Windows Metafile - - - - - - - - - - - - - - - - - - - - - - XBM image - صورة XBM - Vyjava XBM - Изображение — XBM - imatge XBM - Obrázek XBM - XBM-billede - XBM-Bild - εικόνα XBM - XBM image - XBM-bildo - imagen XBM - XBM irudia - XBM-kuva - XBM mynd - image XBM - íomhá XBM - imaxe XBM - תמונת XBM - XBM slika - XBM-kép - Citra XBM - Immagine XBM - XBM 画像 - XBM суреті - XBM 그림 - XBM paveikslėlis - XBM attēls - XBM-bilde - XBM-afbeelding - XBM-bilete - Obraz XBM - Imagem XBM - Imagine XBM - изображение XBM - Obrázok XBM - Slikovna datoteka XBM - Figurë XBM - XBM-bild - зображення XBM - Ảnh XBM - XBM 图像 - XBM 影像 - XBM - X BitMap - - - - GIMP image - صورة GIMP - Vyjava GIMP - Изображение — GIMP - imatge del GIMP - Obrázek GIMP - GIMP-billede - GIMP-Bild - εικόνα GIMP - GIMP image - GIMP-bildo - imagen del GIMP - GIMP irudia - GIMP-kuva - GIMP mynd - image GIMP - íomhá GIMP - imaxe de GIMP - תמונת GIMP - GIMP slika - GIMP-kép - Citra GIMP - Immagine GIMP - GIMP 画像 - GIMP გამოსახულება - GIMP суреті - GIMP 그림 - GIMP paveikslėlis - GIMP attēls - Imej GIMP - GIMP-bilde - GIMP-afbeelding - GIMP-bilete - Obraz GIMP - imagem do GIMP - Imagem do GIMP - Imagine GIMP - изображение GIMP - Obrázok GIMP - Slikovna datoteka GIMP - Figurë GIMP - Гимп слика - GIMP-bild - GIMP görüntüsü - зображення GIMP - Ảnh GIMP - GIMP 图像 - GIMP 影像 - - - - - - - - - XFig image - صورة XFig - Vyjava XFig - Изображение — XFig - imatge de XFig - Obrázek XFig - XFig-billede - XFig-Bild - εικόνα XFig - XFig image - XFig-bildo - imagen de XFig - XFig irudia - XFig-kuva - XFig mynd - image XFig - íomhá XFig - imaxe de XFig - תמונת XFig - XFig slika - XFig-kép - Citra XFig - Immagine XFig - XFig 画像 - XFig суреті - XFig 그림 - XFig paveikslėlis - XFig attēls - Imej XFig - XFig-bilde - XFig-afbeelding - XFig-bilete - Obraz XFig - imagem XFig - Imagem do XFig - Imagine XFig - изображение XFig - Obrázok XFig - Slikovna datoteka XFig - Figurë XFig - XFig слика - XFig-bild - зображення XFig - Ảnh XFig - XFig 图像 - XFig 影像 - - - - - - - XPM image - صورة XPM - Vyjava XPM - Изображение — XPM - imatge XPM - Obrázek XPM - Delwedd XPM - XPM-billede - XPM-Bild - εικόνα XPM - XPM image - XPM-bildo - imagen XPM - XPM irudia - XPM-kuva - XPM mynd - image XPM - íomhá XPM - imaxe XPM - תמונת XPM - XPM slika - XPM kép - Citra XPM - Immagine XPM - XPM 画像 - XPM суреті - XPM 그림 - XPM paveikslėlis - XPM attēls - XPM-bilde - XPM-afbeelding - XPM-bilete - Obraz XPM - Imagem XPM - Imagine XPM - изображение XPM - Obrázok XPM - Slikovna datoteka XPM - Figurë XPM - XPM-bild - зображення XPM - Ảnh XPM - XPM 图像 - XPM 影像 - XPM - X PixMap - - - - - - - - X window image - صورة X window - X window rəsmi - Vyjava vakna X - Изображение — X Window - imatge de X window - Obrázek X window - Delwedd ffenest X - X-billede - X-Window-Bild - εικόνα περιβάλλοντος X - X window image - bildo de X window - imagen de X window - X window irudia - X-ikkunakuva - X vindeyga mynd - image X window - íomhá fhuinneog X - imaxe de X Window - תמונת חלון של X - X window slika - X window-kép - Citra X window - Immagine X window - X window 画像 - X window суреті - X 윈도 그림 - X window paveikslėlis - X window attēls - Imej tetingkap X - X-Windows skjermbilde - X-window-afbeelding - X window bilete - Obraz X Window - imagem de janela X - Imagem de janela do X - Imagine X window - изображение X window - Obrázok X window - slika X oken - Figurë X window - X прозор слика - X-fönsterbild - зображення X window - Ảnh cửa sổ X - X window 图像 - X window 影像 - - - - block device - جهاز كتلي - blokavaja pryłada - Блоково устройство - dispositiu de blocs - Blokové zařízení - blokenhed - Blockorientiertes Gerät - συσκευή block - block device - bloka disponaĵo - dispositivo de bloques - bloke-gailua - laitetiedosto - blokka tóleind - périphérique de blocs - gléas bloc - dispositivo de bloque - התקן בלוק - blokkos eszköz - blok divais - Device a blocchi - ブロックデバイス - блоктық құрылғысы - 블록 장치 - blokinis įrenginys - bloka ierīce - Peranti blok - blokkenhet - blok-apparaat - blokk-eining - Urządzenie blokowe - dispositivo de bloco - Dispositivo de bloco - dispozitiv bloc - блочное устройство - Blokové zariadenie - bločna naprava - device me blloqe - блок уређај - blockenhet - blok aygıtı - блоковий пристрій - thiết bị khối - 块设备 - 區塊裝置 - - - character device - جهاز حرفي - znakavaja pryłada - Символно устройство - dispositiu de caràcters - Znakové zařízení - tegnenhed - Zeichenorientiertes Gerät - συσκευή χαρακτήρων - character device - signa disponaĵo - dispositivo de caracteres - karaktereen gailua - merkkilaite - stavatóleind - périphérique de caractères - gléas carachtar - dispositivo de caracter - התקן תכונה - karakteres eszköz - karakter divais - Device a caratteri - キャラクタデバイス - символдық құрылғысы - 문자 장치 - simbolinis įrenginys - rakstzīmju ierīce - Peranti aksara - tegnenhet - byte-apparaat - teikneining - Urządzenie znakowe - dispositivo de caracteres - Dispositivo de caractere - dispozitiv caracter - символьное устройство - Znakové zariadenie - znakovna naprava - device me karaktere - знаковни уређај - teckenenhet - karakter aygıtı - символьний пристрій - thiết bị ký tự - 字符设备 - 字元裝置 - - - folder - مجلّد - kataloh - Папка - carpeta - Složka - mappe - Ordner - φάκελος - folder - dosierujo - carpeta - karpeta - kansio - mappa - dossier - fillteán - cartafol - תיקייה - direktorij - mappa - folder - Cartella - フォルダー - бума - 폴더 - aplankas - mape - Folder - mappe - map - mappe - Katalog - pasta - Pasta - dosar - папка - Priečinok - mapa - Kartelë - директоријум - mapp - dizin - тека - thư mục - 文件夹 - 資料夾 - - - - pipe - إنبوب - kanvejer - Конвейер - conducte - Roura - datakanal - Pipe - σωλήνωση - pipe - dukto - tubería - kanalizazioa - putki - rør - tube - píopa - tubería - צינור - adatcsatorna - pipa - Pipe - パイプ - арна - 파이프 - konvejeris - programmkanāls - Paip - rør - pijp - røyr - Potok - canal - Pipe - canal pipe - канал - Rúra - cev - Pipe - цев - rör - канал - ống dẫn - 管道 - 管線 - - - mount point - نقطة الوصْل - punkt mantavańnia - Точка на монтиране - punt de muntatge - Místo připojení - monteringspunkt - Einhängepunkt - σημείο προσάρτησης - mount point - surmetingo - punto de montaje - muntatze-puntua - liitospiste - ísetingarpunkt - point d'accès - pointe feistithe - punto de montaxe - נקודת עיגון - točka montiranja - csatolási pont - titik mount - Punto di mount - マウントポイント - тіркеу нүктесі - 마운트 위치 - prijungimo taškas - montēšanas punkts - Titik lekapan - monteringspunkt - aankoppelingspunt - monteringspunkt - Punkt montowania - ponto de montagem - Ponto de montagem - loc montare - точка монтирования - Miesto pripojenia - priklopna točka - Pikë montimi - тачка прикључења - monteringspunkt - точка монтування - điểm lắp - 挂载点 - 掛載點 - - - - socket - مقبس - sokiet - Гнездо - sòcol - Socket - sokkel - Socket - υποδοχή - socket - kontaktoskatolo - socket - socketa - pistoke - sokkul - connecteur réseau - soicéad - socket - נקודת חיבור - utičnica - illesztőpont - soket - Socket - ソケット - сокет - 소켓 - lizdas - sokets - Soket - plugg - socket - sokkel - Gniazdo - 'socket' - Socket - socket - сокет - Soket - vtič - Socket - сокет - uttag - сокет - ổ cắm - 套接字 - socket - - - symbolic link - وصلة رمزية - simvolik körpü - symbalnaja spasyłka - Символна връзка - enllaç simbòlic - Symbolický odkaz - cyswllt symbolaidd - symbolsk henvisning - Symbolische Verknüpfung - συμβολικός σύνδεσμος - symbolic link - simbola ligilo - enlace simbólico - esteka sinbolikoa - symbolinen linkki - tykislig leinkja - lien symbolique - nasc siombalach - ligazón simbólica - קישור סימבולי - simbolička veza - szimbolikus link - taut simbolik - Collegamento simbolico - シンボリックリンク - სიმბოლური ბმული - символдық сілтеме - 심볼릭 링크 - simbolinė nuoroda - simboliskā saite - Pautan simbolik - symbolsk lenke - symbolische koppeling - symbolsk lenkje - Dowiązanie symboliczne - ligação simbólica - Ligação simbólica - legătură simbolică - символьная ссылка - Symbolický odkaz - simbolna povezava - Lidhje simbolike - симболичка веза - symbolisk länk - символічне посилання - liên kết tượng trưng - 符号链接 - 符號鏈結 - - - mail delivery report - تقرير تسليم البريد - poçt yollama raportu - rapart ab dastaŭcy pošty - Отчет за пристигналата поща - informe de lliurament de correu - Zpráva o doručení pošty - Adroddiad trosgludo post - postleveringsrapport - E-Mail-Zustellungsbericht - αναφορά παράδοσης μηνύματος - mail delivery report - raporto pri transdono de retpoŝto - informe de entrega de correo - posta banaketako txostena - viestin jakeluilmoitus - post útberingarfrásøgn - rapport de livraison de courriels - tuairisc sheachadadh poist - informe de entrega de correo - דוח העברת דואר - izvještaj dostave pošte - jelentés levélkézbesítésről - laporan pengantaran surat - Rapporto di consegna posta - メール配送ポート - пошта жеткізілгені туралы отчет - 메일 배달 보고서 - pašto pristatymo ataskaita - pasta piegādes atskaite - Laporan penghantaran mel - e-postleveranserapport - e-mail-bezorgingsbericht - e-post-leveringsrapport - Raport z dostarczenia poczty - relatório de entrega de e-mail - Relatório de entrega de correspondência - raport de trimitere email - отчёт о доставке сообщения - Správa o doručení pošty - poročilo dostave pošte - Raport mbi dorëzimin e mesazhit - извештај доставе поруке - e-postleveransrapport - звіт про доставку пошти - thông báo phát thư - 邮件投递报告 - 郵件寄送回報 - - - - - mail disposition report - تقرير ترتيب البريد - poçt qayıtma raportu - rapart ab raźmiaščeńni pošty - Отчет за състоянието на пощата - informe de disposició de correu - Zpráva o předání pošty - adroddiad ffurf post - postdisponeringsrapport - E-Mail-Übertragungsbericht - αναφορά διάθεσης μηνύματος - mail disposition report - raporto pri dispono de retpoŝto - informe de disposición de correo - posta joerako txostena - viestin kuittausilmoitus - post avhendingarfrásøgn - rapport de disposition de courriels - tuairisc chóiriú poist - informe de disposición de correo - דוח אספקת דואר - jelentés levélkidobásról - laporan disposisi surat - Rapporto di disposizione posta - メール停止レポート - пошта жылжытылғаны туралы отчет - 메일 처리 보고서 - pašto charakteristikos ataskaita - pasta izvietojuma atskaite - Laporan pelupusan mel - e-postdispositionsrapport - e-mail-plaatsingsbericht - e-post-disposisjonsrapport - Raport z wysyłania poczty - relatório de disposição de e-mail - Relatório de disposição de correspondência - confirmare primire email - отчёт о перемещении почты - Správa o odovzdaní pošty - poročilo razporeditve pošte - Raport mbi njoftimin e mesazhit - извештај слања поруке - e-postdispositionsrapport - звіт про розташування пошти - thông báo chuyển nhượng thư - 邮件接收报告 - 郵件處置回報 - - - - - reference to remote file - مرجع إلى ملف بعيد - uzaq fayla göstəriş - spasyłka da addalenaha fajłu - Препратка към отдалечен файл - referència a fitxer remot - Odkaz na vzdálený soubor - cyfeiriad at ffeil bell - reference til fjern fil - Verweis auf entfernte Datei - αναφορά σε απόμακρο αρχείο - reference to remote file - referenco al fora dosiero - referencia a un archivo remoto - erreferentzia urruneko fitxategiari - viittaus etätiedostoon - tilvísing til fjarfílu - référence au fichier distant - tagairt do chomhad cianda - referencia a un ficheiro remoto - התיחסות לקובץ מרוחק - referenca na udaljenu datoteku - hivatkozás távoli fájlra - referensi ke berkas jarak jauh - Riferimento a file remoto - リモートファイルへの参照 - қашықтағы файлға сілтеме - 원격 파일 참조 - nuoroda į nutolusį failą - norāde uz attālinātu datni - Rujukan ke fail jauh - referanse til ekstern fil - verwijzing naar bestand op afstand - referanse til fil over nettverk - Odwołanie do pliku zdalnego - referência a um ficheiro remoto - Referência a um arquivo remoto - referință fișier la distanță - ссылка на удалённый файл - Odkaz na vzdialený súbor - sklic do oddaljene datoteke - Referim për tek file në distancë - референца на удаљену датотеку - referens till fjärrfil - посилання на віддалений файл - tham chiếu đến tập tin ở xa - 到远程文件的引用 - 遠端檔案的參照 - - - - Usenet news message - رسالة أخبار Usenet - Usenet xəbərlər ismarışı - Navina Usenet - Съобщение — Usenet - missatge de notícies Usenet - Příspěvek do diskusních skupin Usenet - Neges newyddion Usenet - Usenetnyhedsmeddelelse - Usenet-News-Nachricht - μήνυμα ομάδων συζητήσεων Usenet - Usenet news message - novaĵmesaĝo de Usenet - mensaje de noticias de Usenet - Usenet berrien mezua - nyyssiviesti - Usenet news boð - message de groupe d'échange Usenet - teachtaireacht nuacht Usenet - mensaxes de noticias de Usenet - הודעת חדשות של Usenet - Usenet poruka novosti - USENET-hírcsoportüzenet - Pesan berita Usenet - Messaggio news Usenet - Usenet news メッセージ - Usenet жаңалық мәлімдемесі - 유즈넷 뉴스 메시지 - Usenet naujienų žinutė - Usenet jaunumu ziņojums - Mesej berita USENET - Usenet nyhetsmelding - Usenet-nieuwsbericht - USENET diskusjonsmelding - Wiadomość grupy dyskusyjnej - mensagem de notícias Usenet - Mensagem de notícias da Usenet - Mesaj Usenet de știri - новостное сообщение Usenet - Príspevok do diskusných skupín Usenet - novičarsko sporočilo Usenet - Mesazh lajmesh Usenet - Порука са дискусионе групе - Usenet-diskussionsgruppsmeddelande - повідомлення новин Usenet - Thông điệp tin tức USENET - Usenet 新闻信 - Usenet 新聞訊息 - - - - - - - - - - partial email message - رسالة البريد الإلكتروني الجزئية - qismi poçt ismarışı - niapoŭny list email - Част от електронно писмо - missatge de correu electrònic parcial - Částečná e-mailová zpráva - darn o neges e-bost - delvis postmeddelelse - E-Mail-Nachrichtenfragment - τμηματικό ηλ. μήνυμα - partial email message - parta retpoŝta mesaĝo - mensaje de correo electrónico parcial - posta mezu partziala - osittainen sähköpostiviesti - message partiel de courriel - teachtaireacht ríomhphoist neamhiomlán - mensaxe de correo electrónico parcial - מסר דוא"ל חלקי - djelomična poruka e-pošte - részleges elektronikus levél - pesan email sebagian - Messaggio email parziale - 部分メールメッセージ - электронды поштаның үзінді мәлімдемесі - 부분적 전자 우편 메시지 - nepilnas el. laiškas - daļēja e-pasta vēstule - Bahagian mesej emel - del av e-postmelding - gedeeltelijk e-mailbericht - del av e-post-melding - Częściowa wiadomość e-mail - mensagem parcial de e-mail - Mensagem de e-mail parcial - mesaj de email parțial - фрагмент сообщения электронной почты - Čiastočná e-mailová správa - delno elektronsko sporočilo - Mesazh poste i pjesëshëm - делимична е-порука - del av e-postmeddelande - часткове поштове повідомлення - thư điện tử riêng phần - 部分电子邮件 - 部份電子郵件訊息 - - - - - email message - رسالة البريد الإلكتروني - list email - Съобщение по електронната поща - missatge de correu electrònic - E-mailová zpráva - postmeddelelse - E-Mail-Nachricht - ηλ. μήνυμα - email message - retpoŝta mesaĝo - mensaje de correo electrónico - helbide elektronikoen mezua - sähköpostiviesti - t-post boð - message de courriel - teachtaireacht ríomhphoist - mensaxe de correo electrónico - הודעת דואר אלקטרוני - poruka e-pošte - elektronikus levél - pesan email - Messaggio email - メール本文 - пошталық мәлімдеме - 전자 우편 본문 - el. laiškas - e-pasta vēstule - Mesej emel - e-postmelding - e-mailbericht - e-postmelding - Wiadomość e-mail - mensagem de e-mail - Mensagem de e-mail - mesaj email - почтовое сообщение - E-mailová správa - sporočilo elektronske pošte - Mesazh poste - е-порука - e-postmeddelande - повідомлення email - thư điện tử - 电子邮件 - 電子郵件內容 - - - - - - - - - - - - - - - - - - GNU mail message - رسالة بريد جنو - GNU poçt ismarışı - List GNU - Съобщение — GNU mail - missatge de GNU mail - Zpráva GNU mail - Neges E-Bost GNU - GNU-postmeddelelse - GNU-Mail-Nachricht - μήνυμα αλληλογραφίας GNU - GNU mail message - mesaĝo de GNU mail - mensaje de GNU mail - GNU posta mezua - GNU-postiviesti - GNU mail boð - message de courriel GNU - teachtaireacht phost GNU - mensaxe de correo electrónico de GNU - הודעת דואר של GNU - GNU poruka pošte - GNU elektronikus levél - Pesan surat GNU - Messaggio GNU mail - GNU メールメッセージ - GNU mail შეტყობინება - GNU пошта хабарламасы - GNU 메일 메시지 - GNU pašto žinutė - GNU pasta vēstule - Mesej emel GNU - GNU e-postmelding - GNU-mailbericht - GNU e-postmelding - Wiadomość pocztowa GNU - mensagem de e-mail GNU - Mensagem de correio GNU - Mesaj GNU mail - почтовое сообщение GNU - Správa GNU mail - Sporočilo pošte GNU - Mesazh GNU mail - ГНУ е-писмо - GNU-epostmeddelande - поштове повідомлення GNU - Thư điện tử của GNU - GNU mail 信件 - GNU 郵件訊息 - - - - - VRML document - مستند VRML - VRML sənədi - Dakument VRML - Документ — VRML - document VRML - Dokument VRML - Dogfen VRML - VRML-dokument - VRML-Dokument - έγγραφο VRML - VRML document - VRML-dokumento - documento VRML - VRML dokumentua - VRML-asiakirja - VRML skjal - document VRML - cáipéis VRML - documento VRML - מסמך VRML - VRML dokument - VRML-dokumentum - Dokumen VRML - Documento VRML - VRML ドキュメント - VRML құжаты - VRML 문서 - VRML dokumentas - VRML dokuments - Dokumen VRML - VRML-dokument - VRML-document - VRML-dokument - Dokument VRML - documento VRML - Documento VRML - Document VRML - документ VRML - Dokument VRML - Dokument VRML - Dokument VRML - VRML документ - VRML-dokument - VRML belgesi - документ VRML - Tài liệu VRML - VRML 文档 - VRML 文件 - VRML - Virtual Reality Modeling Language - - - - - - - - message in several formats - رسالة في عدة صيغ - verici formatlarında ismarış - paviedamleńnie ŭ niekalkich farmatach - Съобщение в няколко формата - missatge en varis formats - Zpráva v několika formátech - neges mewn sawl fformat - meddelelse i flere formater - Nachricht in mehreren Formaten - μήνυμα σε διάφορες μορφές - message in several formats - mesaĝo en pluraj formatoj - mensaje en varios formatos - hainbat formatuko mezua - viesti useissa muodoissa - boð í fleiri sniðum - message en formats divers - teachtaireacht i roinnt fhormáidí - mensaxe en varios formatos - הודעה במספר פורמטים - poruka u nekoliko oblika - többféle formátumú üzenet - pesan dalam beberapa format - Messaggio in diversi formati - いくつかの形式でのメッセージ - бірнеше пішімдегі мәлімдеме - 여러가지 형식의 메시지 - laiškas keletu formatų - ziņojums dažādos formātos - Mesej dalam beberapa format - melding i flere formater - bericht in meerdere opmaken - melding i fleire format - Wiadomość w wielu formatach - mensagem em vários formatos - Mensagem em vários formatos - mesaj în diferite formate - сообщение в нескольких форматах - Správa v niekoľkých formátoch - sporočilo v več zapisih - Mesazh në formate të ndryshëm - поруке у више записа - meddelande i flera format - повідомлення у кількох форматах - thông điệp có vài định dạng - 各种格式的消息 - 多種格式的訊息 - - - Macintosh AppleDouble-encoded file - ملف Macintosh AppleDouble مشفر - Macintosh AppleDouble-kodlanmış fayl - Fajł Macintosh, AppleDouble-zakadavany - Файл — кодиран с Macintosh AppleDouble - fitxer codificat AppleDouble de Macintosh - Soubor kódovaný pomocí Macintosh AppleDouble - Ffeil AppleDouble-amgodedig Macintosh - Macintosh AppleDouble-kodet fil - Macintosh-Datei (AppleDouble-kodiert) - αρχείο Macintosh κωδικοποίησης AppleDouble - Macintosh AppleDouble-encoded file - dosiero kodigita laŭ Macintosh AppleDouble - archivo Macintosh codificado con AppleDouble - Macintosh AppleDouble-rekin kodetutako fitxategia - Macintosh AppleDouble -koodattu tiedosto - Macintosh AppleDouble-bronglað fíla - fichier codé Macintosh AppleDouble - comhad ionchódaithe le Macintosh AppleDouble - ficheiro de Macintosh codificado con AppleDouble - קובץ מסוג Macintosh AppleDouble-encoded - Macintosh AppleDouble-kodirana datoteka - Macintosh AppleDouble kódolású fájl - Berkas tersandi Macintosh AppleDouble - File Macintosh codificato AppleDouble - Macintosh AppleDouble エンコードファイル - Macintosh AppleDouble кодталған файлы - 매킨토시 AppleDouble 인코딩된 파일 - Macintosh AppleDouble-encoded failas - Macintosh AppleDouble-kodēts datne - Fail terenkod-AppleDouble Macintosh - dokument kodet med Macintosh AppleDouble - Macintosh AppleDouble-gecodeerd bestand - Macintosh AppleDouble-koda fil - Zakodowany w AppleDouble plik Macintosh - ficheiro codificado em AppleDouble de Macintosh - Arquivo do Macintosh codificado com AppleDouble - Fișier codat Macintosh AppleDouble - файл (закодированный Macintosh AppleDouble) - Súbor kódovaný pomocou Macintosh AppleDouble - Kodirana datoteka Macintosh (AppleDouble) - File Macintosh i kodifikuar AppleDouble - Мекинтош AppleDouble-encoded датотека - Macintosh AppleDouble-kodad fil - файл закодований Macintosh AppleDouble - Tập tin đã mã hoá Apple-Double của Macintosh - Macintosh AppleDouble 编码的文件 - Macintosh AppleDouble 編碼檔 - - - message digest - خلاصة الرسالة - ismarış daycesti - digest paviedamleńniaŭ - Извадка от съобщение - recopilació de missatges - Přehled zpráv - crynodeb negeseuon - meddelelsessammendrag - Nachrichtensammlung - περίληψη μηνύματος - message digest - mesaĝaro - recopilación de mensajes - mezu laburra - viestikokoelma - boð samandráttur - condensé de message - achoimre theachtaireachtaí - recompilación de mensaxe - תקציר ההודעה - ömlesztett üzenet - pesan digest - Digest di messaggi - メッセージダイジェスト - мәлімдеме профилі - 메시지 묶음 - laiškų santrauka - ziņojumu apkopojums - Jilid mesej - medldingssamling - berichtenbundel - meldingsamandrag - Wiadomość przetwarzania - 'digest' de mensagens - Resumo de mensagem - colecție mesaje email - профиль сообщения - Prehľad správ - povzetek sporočila - Shpërndarje mesazhesh - гомила порука - meddelandesamling - збірка повідомлень - bản tóm tắt thông điệp - 消息摘要 - 訊息摘要 - - - encrypted message - رسالة مشفرة - şifrələnmiş ismarış - zašyfravanaje paviedamleńnie - Шифрирано съобщение - missatge xifrat - Zašifrovaná zpráva - Neges wedi ei hamgryptio - krypteret meddelelse - Verschlüsselte Nachricht - κρυπτογραφημένο μήνυμα - encrypted message - ĉifrita mesaĝo - mensaje cifrado - mezu enkriptatua - salattu viesti - bronglað boð - message chiffré - teachtaireacht chriptithe - mensaxe cifrado - הודעה מוצפנת - šifrirana poruka - titkosított üzenet - pesan terenkripsi - Messaggio cifrato - 暗号化メッセージ - шифрленген мәлімдеме - 암호화된 메시지 - užšifruotas laiškas - šifrēta vēstule - Mesej terenkripsi - kryptert melding - versleuteld bericht - kryptert melding - Wiadomość zaszyfrowana - mensagem cifrada - Mensagem criptografada - mesaj criptat - зашифрованное сообщение - Zašifrovaná správa - šifrirano sporočilo - Mesazh i kriptuar - шифрована порука - krypterat meddelande - şifrelenmiş mesaj - шифроване повідомлення - thông điệp đã mật mã - 加密信件 - 加密訊息 - - - compound documents - مستندات مركبة - składanyja dakumenty - Съставни документи - documents composats - Složené dokumenty - sammensatte dokumenter - Verbunddokumente - σύνθετα έγγραφα - compound documents - parentezaj dokumentoj - documentos compuestos - konposatutako dokumentuak - yhdisteasiakirjat - samansett skjøl - documents composés - cáipéisí comhshuite - documentos compostos - מסמכים מורכבים - összetett dokumentumok - dokumen kompon - Documenti composti - 複合ドキュメント - құрама құжаттары - 복합 문서 - sudurtiniai dokumentai - salikti dokumenti - Dokumen halaman - sammensatte dokumenter - samengestelde documenten - samansette dokument - Dokumenty złożone - documentos compostos - Documentos compostos - documente compuse - составные документы - Zložené dokumenty - združeni dokumenti - dokumente të përbërë - сједињени документи - sammansatta dokument - складні документи - tài liệu ghép - 组合文档 - 複合文件 - - - compound document - مستند مركب - birləşik sənəd - składany dakument - Съставен документ - document composat - Složený dokument - dogfen gyfansawdd - sammensat dokument - Verbunddokument - σύνθετο έγγραφο - compound document - parenteza dokumento - documento compuesto - konposatutako dokumentua - yhdisteasiakirja - samansett skjal - document composé - cáipéis comhshuite - documento composto - מסמך מורכב - összetett dokumentum - dokumen kompon - Documento composto - 複合ドキュメント - құрама құжаты - 복합 문서 - sudurtinis dokumentas - salikts dokuments - Dokumen halaman - sammensatt dokument - samengesteld document - samansett dokument - Dokument złożony - documento composto - Documento composto - document compus - составной документ - Zložený dokument - združeni dokument - dokumet i përbërë - сједињени документ - sammansatt dokument - складний документ - tài liệu ghép - 组合文档 - 複合文件 - - - mail system report - تقرير نظام البريد - poçt sistemi raportu - rapart paštovaj systemy - Отчет за пощенската система - informe de sistema de correu - Zpráva poštovního systému - adroddiad system bost - postsystemrapport - E-Mail-Systembericht - αναφορά συστήματος ηλ. ταχυδρομείου - mail system report - raporto de retpoŝta sistemo - informe del sistema de correo - posta sistemako txostena - viestijärjestelmän ilmoitus - postkervisfrásøgn - rapport système de courriels - tuairisc chóras poist - informe do sistema de correo - דו"ח של מערכת הדואר - levelezőrendszer jelentése - laporan sistem surat - Rapporto di sistema posta - メールシステムレポート - пошта жүйесінің мәлімдемесі - 메일 시스템 보고서 - pašto sistemos ataskaita - pasta sistēmas atskaite - Laporan sistem mel - e-postsystemrapport - e-mail-systeembericht - e-post-systemrapport - Raport systemu pocztowego - relatório de sistema de e-mail - Relatório do sistema de correspondência - raport sistem email - отчёт почтовой системы - Správa poštového systému - poročilo poštnega sistema - Raport i sistemit të postës - извештај поштанског система - e-postsystemrapport - звіт поштової системи - thông báo hệ thống thư - 邮件系统报告 - 郵件系統回報 - - - signed message - رسالة موقّعة - imzalanmış ismarış - padpisanaje paviedamleńnie - Подписано съобщение - missatge signat - Podepsaná zpráva - neges lofnodwyd - signeret meddelelse - Signierte Nachricht - υπογεγραμμένο μήνυμα - signed message - pruvita mesaĝo - mensaje firmado - sinatutako mezua - allekirjoitettu viesti - undirskrivað boð - message signé - teachtaireacht sínithe - mensaxe firmado - הודעה חתומה - potpisana poruka - aláírt üzenet - pesan ditandatangani - Messaggio firmato - 署名付きメッセージ - қолтаңбасы бар мәлімдеме - 서명된 메시지 - pasirašytas laiškas - parakstīta ziņa - Mesej ditandatangani - signert melding - ondertekend bericht - signert melding - Podpisana wiadomość - mensagem assinada - Mensagem assinada - mesaj semnat - подписанное сообщение - Podpísaná správa - podpisano sporočilo - Mesazh i firmosur - потписана порука - signerat meddelande - підписане повідомлення - thông điệp đã ký - 签名信件 - 簽署的訊息 - - - stream of data (server push) - دفق بيانات (دفع خادم) - płyń źviestak (ad servera) - Поток от данни, от страна на сървър - flux de dades (enviat pel servidor) - Proud dat (posílaný serverem) - datastrøm (serverskubbet) - Datenstrom (Server-Push) - χείμαρρος δεδομένων (στελλόμενα από τον εξυπηρετητή) - stream of data (server push) - datumstrio (puŝata per servilo) - flujo de datos (por iniciativa del servidor) - datu-korrontea (zerbitzari igortzailea) - tietovirta (palvelin työntää) - streymur av dáta (ambætara skump) - flux de données (émis par le serveur) - sruth sonraí (brú freastalaí) - fluxo de datos (por iniciativa do servidor) - מידע בזרימה (דחיפה ע"י השרת) - sugárzott adatfolyam (kiszolgálóról) - arus data (dorongan server) - Flusso di dati (server push) - データストリーム (サーバープッシュ型) - мәліметтер ағымы (server push) - 데이터 스트림 (서버 푸시) - duomenų srautas (iš serverio) - datu straume (servera grūsta) - Aliran dara (paksaan pelayan) - datastrøm (server push) - gegevensstroom (server duwt) - datastraum (dytta av tenaren) - Strumień danych (wymuszenie serwera) - fluxo de dados (empurrados pelo servidor) - Fluxo de dados (por iniciativa do servidor) - flux de date (de la server) - поток данных (server push) - Prúd dát (posielaný serverom) - pretok podatkov (strežniški) - Fluks me të dhëna (server push) - проток података (гурање са сервера) - dataflöde (serverutsändning) - потік даних (від сервера) - luồng dữ liệu (trình phục vụ đẩy) - 数据流(服务器推送) - 資料串流 (server push) - - - VCS/ICS calendar - سجل VCS/ICS - Kalandar VCS/ICS - Календар — VCS/ICS - calendari VCS/ICS - Kalendář VCS/ICS - VCS/ICS-kalender - VCS/ICS-Kalender - ημερολόγιο VCS/ICS - VCS/ICS calendar - VCS/ICS-kalendaro - calendario VCS/ICS - VCS/ICS egutegia - VCS/ICS-kalenteri - VCS/ICS kalendari - calendrier VCS/ICS - féilire VCS/ICS - Calendario VCS/ICS - לוח שנה VCS/ICS - VCS/ICS kalendar - VCS/ICS naptár - Kalender VCS/ICS - Calendario VCS/ICS - VCS/ICS カレンダー - VCS/ICS күнтізбесі - VCS/ICS 달력 - VCS/ICS kalendorius - VCS/ICS kalendārs - VCS/ICS-kalender - VCS/ICS-kalender - VCS/ICS-kalender - Kalendarz VCS/ICS - Calendário VCS/ICS - Calendar VCS/ICS - календарь VCS/ICS - Kalendár VCS/ICS - Datoteka koledarja VCS/ICS - Kalendar VCS/ICS - VCS/ICS-kalender - VCS/ICS takvimi - календар VCS/ICS - Lịch VCS/ICS - VCS/ICS 日历 - VCS/ICS 行事曆 - VCS/ICS - vCalendar/iCalendar - - - - - - - - - - - - CSS stylesheet - نمط CSS - Arkuš stylaŭ CSS - Стилове — CSS - llista d'estil CSS - Styl CSS - CSS-stilark - CSS-Stilvorlage - φύλο στυλ CSS - CSS stylesheet - CSS-stilfolio - hoja de estilo CSS - CSS estilo-orria - CSS-tyylitiedosto - CSS sniðark - feuille de style CSS - stílbhileog CSS - folla de estilos CSS - גליון עיצוב CSS - CSS stilska tablica - CSS stíluslap - Lembar gaya CSS - Foglio di stile CSS - CSS スタイルシート - CSS სტილი - CSS стильдер кестесі - CSS 스타일시트 - CSS stiliaus aprašas - CSS stilu saraksts - CSS-stilark - CSS-stijlblad - CSS-stilark - Arkusz stylów CSS - Folha de estilo CSS - Pagină de stil CSS - таблица стилей CSS - Štýly CSS - Slogovna predloga CSS - Fletë stili CSS - CSS-stilmall - таблиця стилів CSS - Tờ kiểu dáng CSS - CSS 样式表 - CSS 樣式表 - CSS - Cascading Style Sheets - - - - - - electronic business card - بطاقة أعمال إلكترونية - elektronnaja biznes-kartka - Електронна визитна картичка - targeta de visita electrònica - Elektronická navštívenka - elektronisk visitkort - Elektronische Visitenkarte - ηλεκτρονική επαγγελματική κάρτα - electronic business card - elektronika vizitkarto - tarjeta de visita electrónica - enpresako txartel elektronikoa - sähköinen käyntikortti - elektroniskt handilskort - carte de visite électronique - cárta gnó leictreonach - tarxeta de negocio electrónica - כרטיס ביקור אלקטרוני - elektronička posjetnica - elektronikus névjegykártya - kartu bisnis elektronik - Biglietto da visita elettronico - 電子名刺 - электронда визит карточкасы - 전자 명함 - elektroninė vizitinė kortelė - elektroniskā biznesa kartiņa - elektronisch visitekaartje - elektronisk visittkort - Wizytówka elektroniczna - cartão de visita electrónico - Cartão de visitas eletrônico - carte de vizită electronică - электронная визитная карточка - Elektronická vizitka - elektronska poslovna vizitka - Skedë elektronike biznesi - elektroniskt visitkort - електронна бізнес-картка - danh thiếp điện tử - 电子商务卡 - 電子商務名片 - - - - - - - - - - - - - - txt2tags document - مستند txt2tags - dakument txt2tags - Документ — txt2tags - document txt2tags - Dokument txt2tags - txt2tags-dokument - txt2tags-Dokument - αρχείο txt2tags - txt2tags document - txt2tags-dokumento - documento txt2tags - txt2tags dokumentua - txt2tags-asiakirja - txt2tags skjal - document txt2tags - cáipéis txt2tags - documento txt2tags - מסמך txt2tags - txt2tags dokument - txt2tags dokumentum - dokumen txt2tags - Documento txt2tags - txt2tags ドキュメント - txt2tags დოკუმენტი - txt2tags құжаты - txt2tags 문서 - txt2tags dokumentas - txt2tags dokuments - txt2tags-dokument - txt2tags-document - txt2tags-dokument - Dokument txt2tags - Documento do txt2tags - document txt2tags - документ txt2tags - Dokument txt2tags - Dokument txt2tags - Dokument txt2tags - txt2tags-dokument - документ txt2tags - tài liệu txt2tags - txt2tags 文档 - txt2tags 文件 - - - - - - - - - Verilog source code - Изходен код — Verilog - codi font en Verilog - Zdrojový kód Verilog - Verilog-kildekode - Verilog-Quellcode - πηγαίος κώδικας Verilog - Verilog source code - Verilog-fontkodo - código fuente en Verilog - Verilog-lähdekoodi - code source Verilog - código fonte en Verilog - קוד מקור של - Verilog izvorni kod - Verilog-forráskód - Kode sumber Verilog - Codice sorgente Verilog - Verilog ソースコード - Verilog бастапқы коды - Verilog 소스 코드 - Verilog pirmkods - Verilog broncode - Kod źródłowy Verilog - Código-fonte Verilog - исходный код Verilog - Zdrojový kód Verilog - Datoteka izvorne kode Verilog - Verilog-källkod - Verilog kaynak kodu - вихідний код мовою Verilog - Verilog 源代码 - Verilog 源碼 - - - - - SystemVerilog header - Заглавен файл — SystemVerilog - capçalera de SystemVerilog - Záhlaví SystemVerilog - SystemVerilog-teksthoved - SystemVerilog-Header - κεφαλίδα SystemVerilog - SystemVerilog header - cabeceras de SystemVerilog - SystemVerilog-otsake - en-tête - Cabeceiras de SystemVerilog - כותרת SystemVerilog - SystemVerilog zaglavlje - SystemVerilog fejléc - Header SystemVerilog - Header SystemVerilog - SystemVerilog ヘッダー - SystemVerilog тақырыптамасы - SystemVerilog 헤더 - SystemVerilog galvene - SystemVerilog header - Nagłówek SystemVerilog - Cabeçalho de SystemVerilog - заголовочный файл SystemVerilog - Hlavičky SystemVerilog - Datoteka glave SystemVerilog - SystemVerilog-headerfil - заголовки SystemVerilog - SystemVerilog 头 - SystemVerilog 標頭 - - - - - SystemVerilog source code - Изходен код — SystemVerilog - codi font en SystemVerilog - Zdrojový kód SystemVerilog - SystemVerilog-kildekode - SystemVerilog-Quellcode - πηγαίος κώδικας SystemVerilog - SystemVerilog source code - código fuente en SystemVerilog - SystemVerilog-lähdekoodi - code source - código fonte en SystemVerilog - קוד מקור של SystemVerilog - SystemVerilog izvorni kod - SystemVerilog-forráskód - Kode sumber SystemVerilog - Codice sorgente - SystemVerilog ソースコード - SystemVerilog бастапқы коды - SystemVerilog 소스 코드 - SystemVerilog pirmkods - SystemVerilog broncode - Kod źródłowy SystemVerilog - Código-fonte de SystemVerilog - исходный код SystemVerilog - Zdrojový kód SystemVerilog - Datoteka izvorne kode SystemVerilog - SystemVerilog-källkod - вихідний файл мовою SystemVerilog - SystemVerilog 源代码 - SystemVerilog 源碼 - - - - - VHDL source code - Изходен код — VHDL - codi font en VHDL - Zdrojový kód VHDL - VHDL-kildekode - VHDL-Quellcode - πηγαίος κώδικας VHDL - VHDL source code - VHDL-fontkodo - código fuente en VHDL - VHDL-lähdekoodi - code source VHDL - código fonte en VHDL - קוד מקור של VHDL - VHDL izvorni kod - VHDL-forráskód - Kode sumber VHDL - Codice sorgente VHDL - VHDL ソースコード - VHDL бастапқы коды - VHDL 소스 코드 - VHDL pirmkods - VHDL broncode - Kod źródłowy VHDL - Código-fonte VHDL - исходный код VHDL - Zdrojový kód VHDL - Datoteka izvorne kode VHDL - VHDL-källkod - VHDL kaynak kodu - вихідний код мовою VHDL - VHDL 源代码 - VHDL 源碼 - VHDL - Very-High-Speed Integrated Circuit Hardware Description Language - - - - - - enriched text document - مستند نصي مغنى - zəngin mətn sənədi - azdobleny tekstavy dakument - Документ с обогатен текст - document de text enriquit - Rozšířený textový dokument - Dogfen testun wedi ei gyfoethogi - beriget tekstdokument - Angereichertes Textdokument - εγγραφο εμπλουτισμένου κειμένου - enriched text document - riĉigita teksta dokumento - documento de texto enriquecido - aberastutako testu dokumentua - rikastettu tekstiasiakirja - ríkað tekstskjal - document texte enrichi - cáipéis téacs saibhrithe - documento de texto enriquecido - מסמך טקסט מועשר - obogaćeni tekstualni dokument - enriched text dokumentum - dokumen teks diperkaya - Documento testo arricchito - リッチテキストドキュメント - пішімделген мәтіндік құжаты - 확장된 텍스트 문서 - praturtinto teksto dokumentas - bagātināta teksta formāts - Dokumen teks diperkaya - riktekst-dokument - verrijkt tekstdocument - rik tekst tekstdokument - Wzbogacony dokument tekstowy - documento de texto rico - Documento de texto enriquecido - document text îmbogățit - форматированный текстовый документ - Rozšírený textový dokument - dokument z obogatenim besedilom - Dokument teksti i pasuruar - обогаћени текстуални документ - berikat textdokument - форматований текстовий документ - tài liệu văn bản có kiểu dáng - 富文本文档 - 豐富化文字文件 - - - - help page - صفحة المساعدة - yardım səhifəsi - staronka dapamohi - Страница от помощта - pàgina d'ajuda - Stránka nápovědy - tudalen gymorth - hjælpeside - Hilfeseite - σελίδα βοήθειας - help page - help-paĝo - página de ayuda - laguntzako orria - ohjesivu - hjálparsíða - page d'aide - leathanach cabhrach - páxina de axuda - דף עזרה - stranica pomoći - súgóoldal - halaman bantuan - Pagina di aiuto - ヘルプページ - анықтама парағы - 도움말 페이지 - žinyno puslapis - palīdzības lapa - Halaman bantuan - hjelpside - hulppagina - hjelpeside - Strona pomocy - página de ajuda - Página de ajuda - pagină de ajutor - страница справки - Stránka Pomocníka - stran pomoči - Faqe ndihme - страна помоћи - hjälpsida - yardım sayfası - сторінка довідки - trang trợ giúp - 帮助页面 - 幫助頁面 - - - - plain text document - مستند نصي مجرد - prosty tekstavy dakument - Документ с неформатиран текст - document de text pla - Prostý textový dokument - rent tekstdokument - Einfaches Textdokument - έγγραφο απλού κειμένου - plain text document - plata teksta dokumento - documento de texto sencillo - testu soileko dokumentua - perustekstiasiakirja - document texte brut - cáipéis ghnáth-théacs - documento de texto sinxelo - מסמך טקסט פשוט - običan tekstualni dokument - egyszerű szöveg - dokumen teks biasa - Documento in testo semplice - 平文テキストドキュメント - мәтіндік құжаты - 일반 텍스트 문서 - paprastas tekstinis dokumentas - vienkāršs teksta dokuments - Dokumen teks jernih - vanlig tekstdokument - plattetekst-document - vanleg tekstdokument - Zwykły dokument tekstowy - documento em texto simples - Documento somente texto - document text simplu - текстовый документ - Obyčajný textový dokument - običajna besedilna datoteka - Dokument në tekst të thjeshtë - обичан текстуални документ - vanligt textdokument - звичайний текстовий документ - tài liệu nhập thô - 纯文本文档 - 純文字文件 - - - - - - - - - - RDF file - ملف RDF - Fajł RDF - Файл — RDF - fitxer RDF - Soubor RDF - RDF-fil - RDF-Datei - αρχείο RDF - RDF file - RDF-dosiero - archivo RDF - RDF fitxategia - RDF-tiedosto - RDF fíla - fichier RDF - comhad RDF - ficheiro RDF - קובץ RDF - RDF datoteka - RDF fájl - Arsip RDF - File RDF - RDF ファイル - RDF файлы - RDF 파일 - RDF failas - RDF datne - RDF-fil - RDF-bestand - RDF-fil - Plik RDF - Arquivo RDF - Fișier RDF - файл RDF - Súbor RDF - Datoteka RDF - File RDF - RDF-fil - файл RDF - Tập tin RDF - RDF 文件 - RDF 檔 - RDF - Resource Description Framework - - - - - - - - - email headers - ترويسة البريد الإلكتروني - epoçt başlıqları - paštovyja zahałoŭki - Заглавни части на електронни писма - capçaleres de correu electrònic - Záhlaví e-mailu - penawdau e-bost - posthoveder - E-Mail-Kopfzeilen - κεφαλίδες ηλ. μηνυμάτων - email headers - retpoŝtaj ĉapoj - cabeceras de correo electrónico - helbide elektronikoen goiburuak - sähköpostiotsakkeet - t-post tekshøvd - en-têtes de courriel - ceanntásca ríomhphoist - cabeceiras de correo electrónico - כותרת דוא"ל - zaglavlja e-pošte - levélfejléc - tajuk email - Intestazioni email - メールヘッダー - пошталық тақырыптамалары - 전자 우편 헤더 - el. laiško antraštės - e-pasta galvene - Pengepala emel - e-posthode - e-mail-kopregels - e-post-hovud - Nagłówki wiadomości e-mail - cabeçalhos de e-mail - Cabeçalhos de e-mail - antete email - почтовые заголовки - Hlavičky e-mailu - glava elektronske pošte - Header email - заглавља е-порука - e-posthuvuden - eposta başlığı - заголовки email - dòng đầu thư điện tử - 电子邮件头 - 電子郵件標頭 - - - - rich text document - مستند نصي غني - zəngin mətn sənədi - azdobleny tekstavy dakument - Документ — rich text - document de text enriquit - Textový dokument RTF - dogfen testun gyfoethog (rtf) - richtekstdokument - RTF-Textdokument - έγγραφο εμπλουτισμένου κειμένου (RTF) - rich text document - riĉteksta dokumento - documento de texto enriquecido - aberastutako testu formatua - RTF-asiakirja - document « rich text » - cáipéis mhéith-théacs - documento do texto enriquecido - מסמך טקסט עשיר - obogaćeni tekstualni dokument - rich text-dokumentum - dokumen teks kaya - Documento rich text - リッチテキストドキュメント - пішімделген мәтіні бар құжаты - 서식있는 텍스트 문서 - praturtinto teksto dokumentas - bagātā teksta dokuments - Dokumen teks diperkaya - rik tekst-dokument - opgemaakt tekstdocument - rik tekst-dokument - Dokument Rich Text - documento em texto rico - Documento rich text - document text îmbogățit - документ с форматированным текстом - Textový dokument RTF - dokument z oblikovanim besedilom - Dokument rich text - обогаћени текстуални документ - RTF-textdokument - форматований текстовий документ - tài liệu văn bản có kiểu dáng (RTF) - RTF 丰富文本文档 - 豐富文字文件 - - - - - RSS summary - ملخص RSS - Karotki ahlad RSS - Обобщение за сайтове — RSS - resum RSS - Souhrn RSS - RSS-sammendrag - RSS-Zusammenfassung - σύνοψη RSS - RSS summary - resumen RSS - RSS laburpena - RSS-tiivistelmä - RSS samandráttur - résumé RSS - achoimre RSS - Resumo RSS - תקציר RSS - RSS sažetak - RSS összefoglaló - Ringkasan RSS - Sommario RSS - RSS サマリ - RSS жинақталғаны - RSS 요약 - RSS santrauka - RSS kopsavilkums - RSS-sammendrag - RSS-samenvatting - RSS-samandrag - Podsumowanie RSS - Resumo RSS - Rezumat RSS - сводка RSS - Súhrn RSS - Datoteka povzetek RSS - Përmbledhje RSS - RSS-sammanfattning - зведення сайту RSS - Bản tóm tắt RSS - RSS 摘要 - RSS 摘要 - RSS - RDF Site Summary - - - - - - - - - - - Atom syndication feed - مروج تغذية Atom - Syndykacyjny kanał navinaŭ Atom - Емисия — Atom - canal de sindicació Atom - Kanál Atom - Atom syndication-feed - Atom-Nachrichtenquelle - Atom syndication feed - proveedor de noticias Atom - Atom harpidetze-iturria - Atom-yhdistevirta - fil de syndication Atom - fotha sindeacáitithe Atom - fonte de sindicación Atom - הזנה דרך הרשת של Atom - Atom egyesítőfolyam - Umpan sindikasi Atom - Feed di distribuzione Atom - Atom 配信フィード - Atom жаңалықтар таспасы - Atom 동기화 피드 - Atom sindikacijos kanalas - Atom sindikāta barotne - Atom syndikeringsstrøm - Atom-syndicatie-feed - Atom-kjelde - Kanał Atom - Fonte de notícias Atom - Flux agregare Atom - лента новостей Atom - Kanál Atom - Sindikalni vir Atom - Feed për përhapje Atom - Atom-syndikeringskanal - трансляція подач Atom - Nguồn tin tức Atom - Atom 更新种子 - Atom 聯合供稿饋流 - - - - - - - - - - OPML syndication feed - مروج تغذية OPML - Syndykacyjny kanał OPML - Емисия — OPML - canal de sindicació OPML - Kanál OPML - OPML-syndikeringsfeed - OPML-Nachrichtenquelle - ροή φορέα OPML - OPML syndication feed - proveedor de noticias OPML - OPML harpidetze-iturria - OPML-yhdistevirta - fil de syndication OPML - fotha sindeacáitithe OPML - fonte de sindicación OPML - הזנה דרך הרשת OPML - OPML egyesítőfolyam - Umpan sindikasi OPML - Feed di distribuzione OPML - OPML 配信フィード - OPML жаңалықтар таспасы - OPML 묶음 feed - OPML sindikacijos kanalas - OPML sindikāta barotne - OPML syndikeringsstrøm - OPML-syndicatie-feed - OPML-kjelde - Kanał OPML - Fonte de notícias OPML - Flux OPML syndication - лента новостей OPML - Kanál OPML - Sindikalni vir OPML - Feed për përhapje OPML - OPML-syndikeringskanal - трансляція подач OPML - Nguồn tin tức OPML - OPML 聚合种子 - OPML 聯合供稿饋流 - - - - - - - - - - SGML document - مستند SGML - Dakument SGML - Документ — SGML - document SGML - Dokument SGML - Dogfen SGML - SGML-dokument - SGML-Dokument - έγγραφο SGML - SGML document - SGML-dokumento - documento SGML - SGML dokumentua - SGML-asiakirja - SGML skjal - document SGML - cáipéis SGML - documento SGML - מסמך SGML - SGML dokument - SGML-dokumentum - Dokumen SGML - Documento SGML - SGML ドキュメント - SGML құжаты - SGML 문서 - SGML dokumentas - SGML dokuments - Dokumen SGML - SGML-dokument - SGML-document - SGML-dokument - Dokument SGML - documento SGML - Documento SGML - Document SGML - документ SGML - Dokument SGML - Dokument SGML - Dokument SGML - SGML документ - SGML-dokument - SGML belgesi - документ SGML - Tài liệu SGML - SGML 文档 - SGML 文件 - SGML - Standard Generalized Markup Language - - - - - - spreadsheet interchange document - مستند تبادل الجدول - dakument dla abmienu raźlikovymi arkušami - Документ за обмяна между програми за електронни таблици - document d'intercanvi de full de càlcul - Sešitový přenosový dokument - regnearksudvekslingsdokument - Tabellenkalkulations-Austauschdokument - έγγραφο ανταλλαγής λογιστικού φύλλου - spreadsheet interchange document - documento de intercambio de hojas de cálculo - kalkulu-orriak trukatzeko dokumentua - taulukkovälitysasiakirja - rokniarks umbýtisskjal - document d'échange de feuilles de calcul - cáipéis idirmhalartaithe scarbhileog - documento de intercambio de follas de cálculo - מסמך גליון נתונים מתחלף - spreadsheet-cserélhetődokumentum - dokumen lembar sebar saling tukar - Documento di scambio per foglio di calcolo - スプレッドシート交換ドキュメント - spreadsheet interchange құжаты - 스프레드시트 교환 문서 - skaičialenčių apsikeitimo dokumentas - izklājlapu apmaiņas dokuments - dokument for regnearkutveksling - rekenblad-uitwisselingsdocument - Utvekslingsdokument for rekneark - Dokument wymiany arkuszy kalkulacyjnych - Documento de intercâmbio de planilhas - document schimb filă de calcul - документ Spreadsheet Interchange - Zošitový prenosový dokument - dokument izmenjeve preglednic - Dokument shkëmbimi për fletë llogaritje - spreadsheet interchange-dokument - документ обміну ел. таблицями - tài liệu hoán đổi bảng tính - 电子表格交换文档 - 試算表交換文件 - - - - - - - - - TSV document - مستند TSV - Dakument TSV - Документ — TSV - document TSV - Dokument TSV - TSV-dokument - TSV-Dokument - έγγραφο TSV - TSV document - documento TSV - TSV dokumentua - TSV-asiakirja - TSV skjal - document TSV - cáipéis TSV - documento TSV - מסמך TSV - TSV dokument - TSV dokumentum - Dokumen TSV - Documento TSV - TSV ドキュメント - TSV құжаты - TSV 문서 - TSV dokumentas - TSV dokuments - TSV-dokument - TSV-document - TSV-dokument - Dokument TSV - Documento TSV - Document TSV - документ TSV - Dokument TSV - Dokument TSV - Dokument TSV - TSV-dokument - документ TSV - Tài liệu TSV - TSV 文档 - TSV 文件 - TSV - Tab Separated Values - - - - - Graphviz DOT graph - مبيان Graphviz DOT - Граф — Graphviz DOT - gràfic Graphviz DOT - Graf Graphviz DOT - Graphviz DOT-graf - Graphviz-DOT-Graph - Γράφημα Graphviz DOT - Graphviz DOT graph - gráfico Graphviz DOT - Graphviz DOT grafikoa - Graphviz DOT -graafi - Graphviz DOT ritmynd - graphe Graphviz DOT - graf DOT Graphviz - gráfica DOT de Graphviz - גרף של Graphviz DOT - Graphviz DOT grafikon - Graphviz DOT-grafikon - Grafik Graphviz DOT - Grafico Graphviz DOT - Graphviz DOT グラフ - Graphviz DOT сызбасы - Graphviz DOT 그래프 - Graphviz DOT diagrama - Graphviz DOT grafiks - Graphviz wetenschappelijke grafiek - Wykres DOT Graphviz - Gráfico do Graphviz DOT - Grafic Graphviz DOT - Диаграмма Graphviz DOT - Graf Graphviz DOT - Datoteka grafikona Graphviz DOT - Graphviz DOT-graf - граф DOT Graphviz - Biểu đồ DOT Graphviz - Graphviz DOT 科学图形 - Graphviz DOT 圖 - - - - - - - - - - - - JAD document - مستند JAD - Dakument JAD - Документ — JAD - document JAD - Dokument JAD - JAD-dokument - JAD-Dokument - έγγραφο JAD - JAD document - JAD-dokumento - documento JAD - JAD dokumentua - JAD-asiakirja - JAD skjal - document JAD - cáipéis JAD - documento JAD - מסמך JAD - JAD dokument - JAD dokumentum - Dokumen JAD - Documento JAD - JAD ドキュメント - JAD құжаты - JAD 문서 - JAD dokumentas - JAD dokuments - JAD-dokument - JAD-document - JAD-dokument - Dokument JAD - Documento JAD - Document JAD - документ JAD - Dokument JAD - Dokument JAD - Dokument JAD - JAD-dokument - JAD belgesi - документ JAD - Tài liệu JAD - JAD 文档 - JAD 文件 - JAD - Java Application Descriptor - - - - - - - WML document - مستند WML - WML sənədi - Dakument WML - Документ — WML - document WML - Dokument WML - Dogfen WML - WML-dokument - WML-Dokument - έγγραφο WML - WML document - WML-dokumento - documento WML - WML dokumentua - WML-asiakirja - WML skjal - document WML - cáipéis WML - documento WML - מסמך WML - WML dokument - WML-dokumentum - Dokumen WML - Documento WML - WML ドキュメント - WML құжаты - WML 문서 - WML dokumentas - WML dokuments - Dokumen XML - WML-dokument - WML-document - WML-dokument - Dokument WML - documento WML - Documento WML - Document WML - документ WML - Dokument WML - Dokument WML - Dokument WML - WML документ - WML-dokument - WML belgesi - документ WML - Tài liệu WML - WML 文档 - WML 文件 - WML - Wireless Markup Language - - - - - WMLScript program - برنامج WMLScript - Prahrama WMLScript - Програма — WMLScript - programa WMLScript - Program WMLScript - WMLScript-program - WMLScript-Programm - πρόγραμμα WMLScript - WMLScript program - programa en WMLScript - WMLScript programa - WMLScript-ohjelma - WMLScript forrit - programme WMLScript - ríomhchlár WMLScript - programa en WMLScript - תוכנית של WMLScript - WMLScript program - WMLScript program - Program WMLScript - Programma WMLScript - WMLScript プログラム - WMLScript бағдарламасы - WMLScript 프로그램 - WMLScript programa - WMLScript programma - WMLScript-program - WMLScript-programma - WMLScript-program - Pogram WMLScript - Programa WMLScript - Program WMLScript - сценарий WMLScript - Program WMLScript - Programska datoteka WMLScript - Program WMLScript - WMLScript-program - WMLScript programı - програма мовою WMLScript - Chương trình WMLScript - WMLScript 程序 - WMLScript 程式 - - - - ACE archive - أرشيف ACE - Archiŭ ACE - Архив — ACE - arxiu ACE - Archiv ACE - ACE-arkiv - ACE-Archiv - αρχείο ACE - ACE archive - ACE-arkivo - archivador ACE - ACE artxiboa - ACE-arkisto - ACE skjalasavn - archive ACE - cartlann ACE - arquivo ACE - ארכיון ACE - ACE arhiva - ACE archívum - Arsip ACE - Archivio ACE - ACE アーカイブ - ACE არქივი - ACE архиві - ACE 압축 파일 - ACE archyvas - ACE arhīvs - ACE-arkiv - ACE-archief - ACE-arkiv - Archiwum ACE - Pacote ACE - Arhivă ACE - архив ACE - Archív ACE - Datoteka arhiva ACE - Arkiv ACE - ACE-arkiv - ACE arşivi - архів ACE - Kho nén ACE - ACE 归档文件 - ACE 封存檔 - - - - - - - - Ada source code - شفرة مصدر Ada - Kryničny kod Ada - Изходен код — Ada - codi font en Ada - Zdrojový kód v Adě - Ada-kildekode - Ada-Quelltext - πηγαίος κώδικας Ada - Ada source code - Ada-fontkodo - código fuente en Ada - Ada iturburu-kodea - Ada-lähdekoodi - Ada keldukota - code source Ada - cód foinseach Ada - código fonte en Ada - קוד מקור Ada - Ada izvorni kod - Ada-forráskód - Kode program Ada - Codice sorgente Ada - Ada ソースコード - Ada-ის საწყისი კოდი - Ada бастапқы коды - Ada 소스 코드 - Ada pradinis kodas - Ada pirmkods - Kod sumber Ada - Ada-kildekode - Ada-broncode - Ada-kjeldekode - Kod źródłowy Ada - código fonte Ada - Código-fonte Ada - Cod sursă Ada - исходный код Ada - Zdrojový kód jazyka Ada - Datoteka izvorne kode Ada - Kod burues Ada - Ада изворни ко̂д - Ada-källkod - Ada kaynak kodu - вихідний код мовою Ada - Mã nguồn Ada - Ada 源代码 - Ada 源碼 - - - - - - author list - لائحة المؤلف - śpis aŭtaraŭ - Списък на авторите - llista d'autors - Seznam autorů - forfatterliste - Autorenliste - κατάλογος συγγραφέων - author list - listo de aŭtoroj - lista de autores - egile-zerrenda - tekijäluettelo - høvundalisti - liste d'auteurs - liosta údar - lista de autores - רשימת יוצרים - szerzőlista - senarai penulis - Elenco autori - 著者リスト - авторлар тізімі - 저자 목록 - autorių sąrašas - autoru saraksts - Senarai penulis - forfatterliste - auteurslijst - forfattarliste - Lista autorów - lista de autores - Lista de autores - listă autori - список авторов - Zoznam autorov - seznam avtorjev - Lista e autorëve - списак аутора - författarlista - yazar listesi - перелік авторів - danh sách tác giả - 作者列表 - 作者清單 - - - - - BibTeX document - مستند BibTeX - Dakument BibTeX - Документ — BibTeX - document BibTeX - Dokument BibTeX - BibTeX-dokument - BibTeX-Dokument - έγγραφο BibTeX - BibTeX document - BibTeX-dokumento - documento BibTeX - BibTeX dokumentua - BibTeX-asiakirja - BibTeX skjal - document BibTeX - cáipéis BibTeX - documento BibTex - מסמך BibTeX - BibTeX dokument - BibTeX dokumentum - Dokumen BibTeX - Documento BibTeX - BibTeX ドキュメント - BibTeX-ის დოკუმენტი - BibTeX құжаты - BibTeX 문서 - BibTeX dokumentas - BibTeX dokuments - BibTeX-dokument - BibTeX-document - BibTeX-dokument - Dokument BibTeX - Documento BibTeX - Document BibTeX - документ BibTeX - Dokument BibTeX - Dokument BibTeX - Dokument BibTeX - BibTeX-dokument - BibTeX belgesi - документ BibTeX - Tài liệu BibTeX - BibTeX 文档 - BibTeX 文件 - - - - - - - - C++ header - ترويسة سي++ - Zahałoŭny fajł C++ - Заглавен файл — C++ - capçalera en C++ - Záhlaví v C++ - C++-posthoved - C++-Header - κεφαλίδα C++ - C++ header - cabecera de código fuente en C++ - C++ goiburua - C++-otsake - C++ tekshøvd - en-tête C++ - ceanntásc C++ - cabeceira de código fonte en C++ - כותר ++C - C++ zaglavlje - C++ fejléc - Tajuk C++ - Header C++ - C++ ヘッダー - C++-ის თავსართი - C++ тақырыптама файлы - C++ 헤더 - C++ antraštė - C++ galvene - C++-kildekodeheader - C++-header - C++-kjeldekode-hovud - Plik nagłówkowy C++ - Cabeçalho C++ - Antet C++ - заголовочный файл C++ - Hlavičky jazyka C++ - Datoteka glave C++ - Header C++ - C++-huvud - файл заголовків мовою C++ - Phần đầu mã nguồn C++ - C++ 源代码头文件 - C++ 標頭檔 - - - - - - - - - C++ source code - شفرة مصدر سي++ - Kryničny kod C++ - Изходен код — C++ - codi font en C++ - Zdrojový kód v C++ - C++-kildekode - C++-Quelltext - πηγαίος κώδικας C++ - C++ source code - C++-fontkodo - código fuente en C++ - C++ iturburu-kodea - C++-lähdekoodi - C++ keldukota - code source C++ - cód foinseach C++ - código fonte de C++ - קוד מקור של C++ - C++ izvorni kod - C++-forráskód - Kode program C++ - Codice sorgente C++ - C++ ソースコード - C++-ის საწყისი კოდი - C++ бастапқы коды - C++ 소스 코드 - C++ pradinis kodas - C++ pirmkods - Kod sumber C++ - C++-kildekode - C++-broncode - C++-kjeldekode - Kod źródłowy C++ - código fonte C++ - Código-fonte C++ - Cod sursă C++ - исходный код C++ - Zdrojový kód jazyka C++ - Datoteka izvorne kode C++ - Kod burues C++ - C++ изворни ко̂д - C++-källkod - вихідний код мовою C++ - Mã nguồn C++ - C++ 源代码 - C++ 源碼 - - - - - - - - - ChangeLog document - مستند ChangeLog - Dakument zafiksavanych źmienaŭ ChangeLog - Дневник за промени — ChangeLog - document de registre de canvis - Dokument ChangeLog - ChangeLot-dokument - Änderungsprotokoll - έγγραφο ChangeLog - ChangeLog document - documento de cambios - ChangeLog dokumentua - Muutoslokiasiakirja - ChangeLog skjal - document ChangeLog - cáipéis ChangeLog - documento Changelog - מסמך של ChangeLog - ChangeLog dokumentum - Dokumen ChangeLog - Documento ChangeLog - ChangeLog ドキュメント - ChangeLog დოკუმენტი - ChangeLog құжаты - ChangeLog 문서 - ChangeLog dokumentas - ChangeLog dokuments - ChangeLog-dokument - ChangeLog-document - ChangeLog-dokument - Dokument zmian (ChangeLog) - Documento ChangeLog - Document ChangeLog - протокол изменений - Dokument ChangeLog - Dokument ChangeLog - Dokument ChangeLog - Ändringsloggsdokument - документ ChangeLog - Tài liệu ChangeLog (ghi lưu thay đổi) - 变更日志文档 - ChangeLog 文件 - - - - - C header - ترويسة C - Zahałoŭny fajł C - Заглавен файл — C - capçalera en C - Záhlaví v C - C-posthoved - C-Header - κεφαλίδα C - C header - cabecera de código fuente en C - C goiburua - C-otsake - C tekshøvd - en-tête C - ceanntásc C - cabeceira de códifo fonte de C - כותר C - C zaglavlje - C fejléc - Tajuk C - Header C - C ヘッダー - C-ის თავსართი - C тақырыптама файлы - C 헤더 - C antraštė - C galvene - C-kildekodeheader - C-header - C-kjeldekode-hovud - Plik nagłówkowy C - Cabeçalho C - Antet C - заголовочный файл C - Hlavičky jazyka C - Datoteka glave C - Header C - C-huvud - C başlığı - файл заголовків мовою C - Phần đầu mã nguồn C - C 程序头文件 - C 標頭檔 - - - - - CMake source code - شفرة مصدر CMake - Kryničny kod CMake - Изходен код — CMake - codi font en CMake - Zdrojový kód CMake - CMake-kildekode - CMake-Quelltext - πηγαίος κώδικας CMake - CMake source code - CMake-fontkodo - código fuente en CMake - CMake iturburu-kodea - CMake-lähdekoodi - CMake keldukota - code source CMake - cód foinseach CMake - código fonte de CMake - קוד מקור של CMake - CMake izvorni kod - CMake-forráskód - Kode program CMake - Codice sorgente CMake - CMake ソースコード - CMake-ის საწყისი კოდი - CMake бастапқы коды - CMake 소스 코드 - CMake pirminis tekstas - CMake pirmkods - CMake-kildekode - CMake-broncode - CMake-kjeldekode - Kod źródłowy CMake - Código-fonte CMake - Cod sursă CMake - исходный код CMake - Zdrojový kód CMake - Datoteka izvorne kode CMake - Kod burues CMake - CMake-källkod - вихідний код CMake - Mã nguồn CMake - CMake 源代码 - CMake 源碼 - - - - - - CSV document - مستند CSV - Dakument CSV - Документ — CSV - document CSV - Dokument CSV - CSV-dokument - CSV-Dokument - αρχείο CSV - CSV document - CSV-dokumento - documento CSV - CSV dokumentua - CSV-asiakirja - CSV skjal - document CSV - cáipéis CSV - documento CSV - מסמך CSV - CSV dokument - CSV dokumentum - Dokumen CSV - Documento CSV - CSV ドキュメント - CSV დოკუმენტი - CSV құжаты - CSV 문서 - CSV dokumentas - CSV dokuments - CSV-dokument - CSV-document - CSV-dokument - Dokument CSV - Documento CSV - Document CSV - документ CSV - Dokument CSV - Dokument CSV - Dokument CSV - CSV-dokument - документ CSV - Tài liệu CSV - CSV 文档 - CSV 文件 - CSV - Comma Separated Values - - - - - - - license terms - شروط الترخيص - licenzijnyja ŭmovy - Лицензни условия - condicions de llicència - Licenční podmínky - licensbetingelser - Lizenzbedingungen - όροι άδειας - licence terms - términos de licencia - lizentzia baldintzak - lisenssiehdot - loyvistreytir - termes de licence - téarmaí ceadúnais - termos de licenza - תנאי רישיון - uvjeti licence - licencfeltételek - persyaratan lisensi - Termini di licenza - ソフトウェアライセンス条項 - лицензиялық келісімі - 라이선스 조항 - licencijos sąlygos - licences nosacījumi - lisensbestemmelser - licentievoorwaarden - lisensvilkår - Warunki licencji - Termos de licença - termeni de licență - лицензионное соглашение - Licenčné podmienky - pogoji in dovoljenja uporabe - Kushte liçence - licensvillkor - ліцензійні умови - điều kiện giấy phép - 软件许可条款 - 授權條款 - - - - - author credits - شكر وتقدير المؤلف - zasłuhi aŭtara - Благодарности към авторите - atribucions d'autor - Autorské zásluhy - bidragydere - Autorendanksagung - author credits - reconocimiento de autoría - tekijöiden kiitokset - høvundaheiður - remerciements - admhálacha údar - créditos de autor - קרדיטים של היוצר - szerzők listája - kredit penulis - Riconoscimenti autori - ソフトウェア作者クレジット - бағдарлама авторлары - 저작자 크레딧 - padėkos autoriams - veidotāji - liste med bidragsytere - auteursinformatie - forfattarliste - Podziękowania autorów programu - Créditos do autor - mulțumiri autori - авторы программы - Autorské zásluhy - avtorske zasluge - Kreditë e autorëve - författarlista - подяки авторам програми - công trạng tác giả - 软件作者致谢 - 作者致謝名單 - - - - - C source code - شفرة مصدر سي - Kryničny kod C - Изходен код — C - codi font en C - Zdrojový kód v C - C-kildekode - C-Quelltext - πηγαίος κώδικας C - C source code - C-fontkodo - código fuente en C - C iturburu-kodea - C-lähdekoodi - C keldukota - code source C - cód foinseach C - código fonte en C - קוד מקור של C - C izvorni kod - C-forráskód - Kode program C - Codice sorgente C - C ソースコード - C-ის საწყისი კოდი - C бастапқы коды - C 소스 코드 - C pradinis kodas - C pirmkods - Kod sumber C - C-kildekode - C-broncode - C-kjeldekode - Kod źródłowy C - código fonte C - Código-fonte C - Cod sursă C - исходный код C - Zdrojový kód jazyka C - Datoteka izvorne kode C - Kod burues C - C изворни ко̂д - C-källkod - C kaynak kodu - вихідний код мовою C - Mã nguồn C - C 源代码 - C 源碼 - - - - - - - - - - - C# source code - شفرة مصدر سي# - Kryničny kod C# - Изходен код — C# - codi font en C# - Zdrojový kód v C# - C#-kildekode - C#-Quelltext - πηγαίος κώδικας C# - C# source code - C#-fontkodo - código fuente en C# - C# iturburu-kodea - C#-lähdekoodi - C# keldukota - code source C# - cód foinseach C# - código fonte en C# - קוד מקור של C# - C# izvorni kod - C#-forráskód - Kode program C# - Codice sorgente C# - C# ソースコード - C#-ის საწყისი კოდი - C# бастапқы коды - C# 소스 코드 - C# pradinis kodas - C# pirmkods - Kod sumber C# - C#-kildekode - C#-broncode - C#-kjeldekode - Kod źródłowy C# - código fonte C# - Código-fonte C# - Cod sursă C# - исходный код C# - Zdrojový kód jazyka C# - Datoteka izvorne kode C# - Kod burues C# - C# изворни ко̂д - C#-källkod - C# kaynak kodu - вихідний код мовою C# - Mã nguồn C# - C# 源代码 - C# 源碼 - - - - - Vala source code - شفرة مصدر Vala - Kryničny kod Vala - Изходен код — Vala - codi font en Vala - Zdrojový kód Vala - Valakildekode - Vala-Quelltext - πηγαίος κώδικας Vala - Vala source code - Vala-fontkodo - código fuente en Vala - Vala iturburu-kodea - Vala-lähdekoodi - Vala keldukota - code source Vala - cód foinseach Vala - código fonte en Vala - קוד מקור של Vala - Vala izvorni kod - Vala forráskód - Kode program Vala - Codice sorgente Vala - Vala ソースコード - Vala бастапқы коды - Vala 소스 코드 - Vala pradinis kodas - Vala pirmkods - Vala-kildekode - Vala-broncode - Vala-kjeldekode - Kod źródłowy Vala - Código-fonte Vala - Cod sursă Vala - исходный код Vala - Zdrojový kód Vala - Datoteka izvorne kode Vala - Kod burues Vala - Vala-källkod - Vala kaynak kodu - вихідний код мовою Vala - Mã nguồn Vala - Vala 源代码 - Vala 源碼 - - - - - - OOC source code - Изходен код — OOC - codi font en OOC - Zdrojový kód OOC - OOC-kildekode - OOC-Quellcode - πηγαίος κώδικας OOC - OOC source code - OOC-fontkodo - Código fuente en OOC - OOC-lähdekoodi - source code OOC - código fonte de OOC - קוד מקור של OOC - OOC izvorni kod - OOC forráskód - Kode sumber OOC - Codice sorgente OOC - OOC ソースコード - OOC-ის საწყისი კოდი - OOC бастапқы коды - OOC 소스 코드 - OOC pirmkods - OOC broncode - Kod źródłowy OOC - Código-fonte OOC - исходный код OOC - Izvorna koda OOC - OOC-källkod - вихідний код мовою OOC - OOC - OOC 源碼 - OOC - Out Of Class - - - - - DCL script - سكربت DCL - DCL skripti - Skrypt DCL - Скрипт — DCL - script DCL - Skript DCL - Sgript DCL - DCL-program - DCL-Skript - πρόγραμμα εντολών DCL - DCL script - DCL-skripto - script en DCL - DCL script-a - DCL-komentotiedosto - DCL boðrøð - script DCL - script DCL - script de DCL - תסריט DCL - DCL skripta - DCL-parancsfájl - Skrip DCL - Script DCL - DCL スクリプト - DCL სცენარი - DCL сценарийі - DCL 스크립트 - DCL scenarijus - DCL skripts - Skrip DCL - DCL-skript - DCL-script - DCL-skript - Skrypt DCL - 'script' DCL - Script DCL - Script DCL - сценарий DCL - Skript DCL - Skriptna datoteka DCL - Script DCL - DCL скрипта - DCL-skript - DCL betiği - скрипт DCL - Văn lệnh DCL - DCL 脚本 - DCL 指令稿 - DCL - Data Conversion Laboratory - - - - - DSSSL document - مستند DSSSL - DSSSL sənədi - Dakument DSSSL - Документ — DSSSL - document DSSSL - Dokument DSSSL - Dogfen DSSSL - DSSSL-dokument - DSSSL-Dokument - έγγραφο DSSSL - DSSSL document - DSSSL-dokumento - documento DSSSL - DSSSL dokumentua - DSSSL-asiakirja - DSSSL skjal - document DSSSL - cáipéis DSSSL - documento DSSSL - מסמך DSSSL - DSSSL dokument - DSSSL-dokumentum - Dokumen DSSSL - Documento DSSSL - DSSSL ドキュメント - DSSSL დოკუმენტი - DSSSL құжаты - DSSSL 문서 - DSSSL dokumentas - DSSSL dokuments - Dokumen DSSSL - DSSSL-dokument - DSSSL-document - DSSSL-dokument - Dokument DSSSL - documento DSSSL - Documento DSSSL - Document DSSSL - документ DSSSL - Dokument DSSSL - Dokument DSSSL - Dokument DSSSL - DSSSL документ - DSSSL-dokument - DSSSL belgesi - документ DSSSL - Tài liệu DSSSL - DSSSL 文档 - DSSSL 文件 - DSSSL - Document Style Semantics and Specification Language - - - - - D source code - شفرة مصدر D - Kryničny kod D - Изходен код — D - codi font en D - Zdrojový kód v D - D-kildekode - D-Quelltext - πηγαίος κώδικας D - D source code - D-fontkodo - código fuente en D - D iturburu-kodea - D-lähdekoodi - D keldukota - code source D - cód foinseach D - código fonte de D - קוד מקור לשפת D - D izvorni kod - D-forráskód - Kode program D - Codice sorgente D - D ソースコード - D-ის საწყისი კოდი - D бастапқы коды - D 소스 코드 - D pradinis kodas - D pirmkods - D-kildekode - D-broncode - D-kjeldekode - Kod źródłowy D - Código-fonte D - Cod sursă D - исходный код D - Zdrojový kód jazyka D - Datoteka izvorne kode D - Kod burues D - D изворни ко̂д - D-källkod - вихідний код мовою D - Mã nguồn D - D 源代码 - D 源碼 - - - - - - DTD file - ملف DTD - Fajł DTD - Документ — DTD - fitxer DTD - Soubor DTD - DTD-fil - DTD-Datei - αρχείο DTD - DTD file - DTD-dosiero - archivo DTD - DTD fitxategia - DTD-tiedosto - DTD fíla - fichier DTD - comhad DTD - ficheiro DTD - מסמך DTD - DTD datoteka - DTD fájl - Berkas DTD - File DTD - DTD ファイル - DTD ფაილი - DTD файлы - DTD 파일 - DTD failas - DTD datne - DTD-fil - DTD-bestand - DTD-fil - Plik DTD - Arquivo DTD - Fișier DTD - файл DTD - Súbor DTD - Datoteka DTD - File DTD - DTD-fil - DTD dosyası - файл DTD - Tập tin DTD - DTD 文件 - DTD 檔 - DTD - Document Type Definition - - - - - - - Eiffel source code - شفرة مصدر Eiffel - Kryničny kod Eiffel - Изходен код — Eiffel - codi font en Eiffel - Zdrojový kód Eiffel - Eiffelkildekode - Eiffel-Quelltext - πηγαίος κώδικας Eiffel - Eiffel source code - Eiffel-fontkodo - código fuente en Eiffel - Eiffel iturburu-kodea - Eiffel-lähdekoodi - Eiffel keldukota - code source Eiffel - cód foinseach Eiffel - código fone de Eiffel - קוד מקור של Eiffel - Eiffel izvorni kod - Eiffel forráskód - Kode program Eiffel - Codice sorgente Eiffel - Eiffel ソースコード - Eiffel-ის საწყისი კოდი - Eiffel бастапқы коды - Eiffel 소스 코드 - Eiffel pirminis programos tekstas - Eiffel pirmkods - Eiffel-kildekode - Eiffel-broncode - Eiffel-kjeldekode - Kod źródłowy Eiffel - Código-fonte Eiffel - Cod sursă Eiffel - исходный код Eiffel - Zdrojový kód Eiffel - Datoteka izvorne kode Eiffel - Kod burues Eiffel - Eiffel-källkod - Eiffel kaynak kodu - вихідний код мовою Eiffel - Mã nguồn Eiffel - Eiffel 源代码 - Eiffel 源碼 - - - - - - Emacs Lisp source code - شفرة مصدر Emacs Lisp - Emacs Lisp mənbə kodu - Kryničny kod Emacs Lisp - Изходен код — Emacs Lisp - codi font en Emacs Lisp - Zdrojový kód Emacs Lisp - Ffynhonnell rhaglen EMACS LISP - Emacs Lisp-kildekode - Emacs-Lisp-Quelltext - πηγαίος κώδικας Emacs Lisp - Emacs Lisp source code - fontkodo en Emacs Lisp - código fuente en Lisp de Emacs - Emacs Lisp iturburu-kodea - Emacs Lisp -lähdekoodi - Emacs Lisp keldukota - code source Emacs Lisp - cód foinseach Emacs Lisp - código fonte de Emacs Lisp - קוד מקור של Emcas Lisp - Emacs Lisp izvorni kod - Emacs Lisp-forráskód - Kode sumber Emacs Lisp - Codice sorgente Emacs Lisp - Emacs Lisp ソースコード - Emacs-ის Lisp საწყისი კოდი - Emacs Lisp бастапқы коды - Emacs Lisp 소스 코드 - Emacs Lisp pradinis kodas - Emacs Lisp pirmkods - Kod sumber Emacs Lisp - Emacs Lisp-kildekode - Emacs Lisp-broncode - Emacs Lisp kjeldekode - Plik źródłowy Emacs Lisp - código fonte Emacs Lisp - Código-fonte Lisp do Emacs - Cod sursă Emacs Lisp - исходный код Emacs Lisp - Zdrojový kód Emacs Lisp - Datoteka izvorne kode Emacs Lisp - Kod burues Emacs Lisp - Емакс Лисп изворни ко̂д - Emacs Lisp-källkod - Emacs Lisp kaynak kodu - вихідний код мовою Emacs Lisp - Mã nguồn Lisp Emacs - Emacs Lisp 源代码 - Emacs Lisp 源碼 - - - - - - - - - Erlang source code - شفرة مصدر Erlang - Kryničny kod Erlang - Изходен код — Erlang - codi font en Erlang - Zdrojový kód Erlang - Erlangkildekode - Erlang-Quelltext - πηγαίος κώδικας Erlang - Erlang source code - Erlang-fontkodo - código fuente en Erlang - Erlang iturburu-kodea - Erlang-lähdekoodi - Erlang keldukota - code source Erlang - cód foinseach Erlang - código fonte de Erlang - קוד מקור של Erlang - Erlang izvorni kod - Erlang forráskód - Kode program Erlang - Codice sorgente Erlang - Erlang ソースコード - Erlang-ის საწყისი კოდი - Erlang бастапқы коды - Erlang 소스 코드 - Erlang pradinis kodas - Erlang pirmkods - Erlang-kildekode - Erlang-broncode - Erlang-kjeldekode - Kod źródłowy Erlang - Código-fonte Erlang - Cod sursă Erlang - исходный код Erlang - Zdrojový kód Erlang - Datoteka izvorne kode Erlang - Kod burues Erlang - Erlang-källkod - Erlang kaynak kodu - вихідний код мовою Erlang - Mã nguồn Erlang - Erlang 源代码 - Erlang 源碼 - - - - - Fortran source code - شفرة مصدر Fortran - Fortran mənbə kodu - Kryničny kod Fortran - Изходен код — Fortran - codi font en Fortran - Zdrojový kód Fortran - Ffynhonnell rhaglen FORTRAN - Fortrankildekode - Fortran-Quelltext - πηγαίος κώδικας Fortran - Fortran source code - Fotran-fontkodo - código fuente en Fortran - Fortran-en iturburu-kodea - Fortran-lähdekoodi - Fortran keldukota - code source Fortran - cód foinseach Fortran - código fonte de Fortran - קוד מקור של Fortran - Fortran izvorni kod - Fortran-forráskód - Kode program Fortran - Codice sorgente Fortran - Fortran ソースコード - Fortran-ის საწყისი კოდი - Fortran бастапқы коды - 포트란 소스 코드 - Fortran pradinis kodas - Fortran pirmkods - kod sumber Fortran - Fortran-kildekode - Fortran-broncode - Fortran-kjeldekode - Kod źródłowy Fortran - código fonte Fortran - Código-fonte Fortran - Cod sursă Fortran - исходный код Fortran - Zdrojový kód Fortran - Datoteka izvorne kode Fortran - Kod burues Fortran - Фортран изворни ко̂д - Fortran-källkod - Fortran kaynak kodu - вихідний код мовою Fortran - Mã nguồn Fortran - Fortran 源代码 - Fortran 源碼 - - - - - - - - translation file - ملف الترجمة - fajł pierakładu - Превод - fitxer traducció - Soubor překladu - oversættelsesfil - Übersetzungsdatei - αρχείο μετάφρασης - translation file - tradukad-dosiero - archivo de traducción - itzulpen-fitxategia - käännöstiedosto - týðingarfíla - fichier de traduction - comhad aistrithe - ficheiro de tradución - קובץ תרגום - datoteka prijevoda - fordítási fájl - berkas terjemahan - File traduzione - 翻訳ファイル - თარგმნის ფაილი - аудармалар файлы - 번역 파일 - vertimo failas - tulkošanas datne - oversettelsesfil - vertalingsbestand - omsetjingsfil - Plik tłumaczenia - Arquivo de tradução - fișier traducere - файл переводов - Súbor prekladu - datoteka prevoda programa - File përkthimesh - översättningsfil - файл перекладу - tập tin dịch - 消息翻译文件 - 翻譯檔 - - - - - - - translation template - قالب الترجمة - šablon dla pierakładu - Шаблон за преводи - plantilla de traducció - Šablona překladu - oversættelsesskabelon - Übersetzungsvorlage - πρότυπο μετάφρασης - translation template - tradukad-ŝablono - plantilla de traducción - itzulpenen txantiloia - käännösmalli - týðingarformur - modèle de traduction - teimpléad aistrithe - plantilla de tradución - תבנית תרגום - predložak prijevoda - fordítási sablon - templat terjemahan - Modello di traduzione - 翻訳テンプレート - თარგმნის შაბლონი - аудармалар үлгісі - 메시지 번역 서식 - vertimo šablonas - tulkošanas veidne - mal for oversetting - vertalingssjabloon - omsetjingsmal - Szablon tłumaczenia - Modelo de tradução - șablon de traducere - шаблон переводов - Šablóna prekladu - predloga datoteke prevoda programa - Model përkthimesh - översättningsmall - шаблон перекладу - mẫu dịch - 消息翻译模板 - 翻譯模版 - - - - - - - - - HTML document - مستند HTML - Dakument HTML - Документ — HTML - document HTML - Dokument HTML - HTML-dokument - HTML-Dokument - έγγραφο HTML - HTML document - HTML-dokumento - documento HTML - HTML dokumentua - HTML-asiakirja - HTML skjal - document HTML - cáipéis HTML - documento HTML - מסמך HTML - HTML dokument - HTML dokumentum - Dokumen HTML - Documento HTML - HTML ドキュメント - HTML құжаты - HTML 문서 - HTML dokumentas - HTML dokuments - HTML-dokument - HTML-document - HTML-dokument - Dokument HTML - Documento HTML - Document HTML - документ HTML - Dokument HTML - Dokument HTML - Dokument HTML - HTML-dokument - документ HTML - Tài liệu HTML - HTML 文档 - HTML 文件 - HTML - HyperText Markup Language - - - - - - - - - - - - - - - - - - - - - - - - - Web application cache manifest - قائمة التخزين الموقت لتطبيق الويب - Манифест за кеша на уеб приложение - manifest de memòria cau d'aplicació Web - Manifest mezipaměti webové aplikace - Manifest for internetprogrammellemlager - Webanwendungscache-Manifest - Web application cache manifest - manifiesto de caché de aplicación web - Web aplikazioaren cache-aren agiria - Net nýtsluskipanarkova manifest - manifeste de cache d'application Web - lastliosta taisce d'fheidhmchlár Gréasáin - manifesto de caché de aplicativo web - הצהרה של מטמון של תוכנית ברשת - Webalkalmazás gyorsítótár-összefoglalója - Manifes singgahan aplikasi web - Manifesto cache applicazione Web - Web アプリケーションキャッシュ manifest - Веб қолданбасының кэш манифесті - 웹 애플리케이션 캐시 정의 - Žiniatinklio programos podėlio manifestas - Tīmekļa lietotņu keša manifests - Webapplicatie cache manifest - Manifest pamięci podręcznej aplikacji WWW - Manifest de cache de aplicação web - Manifest de cache pentru aplicații web - манифест кэша веб-приложения - Predpomnilnik spletnega programa - Cachemanifest för webbapplikation - маніфест кешу веб-програми - 网络应用程序缓存清单 - 網頁應用程式快取聲明 - - - - - - - - - - - - - Google Video Pointer - مؤشر فيديو جوجل - Pakazalnik Google Video - Документ-указател към видео на Google - apuntador a vídeo de Google - Google Video Pointer - Google Video-peger - Google Video Pointer - Google Video Pointer - lista de reproducción de Google Video (GVP) - Google Video-ren erreprodukzio-zerrenda - Google-video-osoitin - Google Video Pointer - pointeur vidéo Google - pointeoir Google Video - punteiro de vídeo de Google - מצביע וידאו של Google - Google Video Pointer - Google Video Pointer - Puntatore Google Video - Google ビデオポインター - Google Video Pointer - 구글 비디오 포인터 - Google Video Pointer - Google Video Pointer - Peker til Google Video - Google-videoverwijzing - Google Video-peikar - Lista odtwarzania Google Video - Ponteiro do Google Vídeo - Indicator Google Video - Google Video Pointer - Google Video Pointer - Kazalec Google Video - Puntues Google Video - Google Video-pekare - вказівник відео Google - Con trỏ ảnh động Google - Google 视频指向 - Google Video Pointer - - - - - - - - - Haskell source code - شفرة مصدر Haskell - Haskell mənbə kodu - Kryničny kod Haskell - Изходен код на Haskell - codi font en Haskell - Zdrojový kód Haskell - Ffynhonnell rhaglen Haskell - Haskellkildekode - Haskell-Quelltext - πηγαίος κώδικας Haskell - Haskell source code - Haskell-fontkodo - código fuente en Haskell - Haskell iturburu-kodea - Haskell-lähdekoodi - Haskell keldukota - code source Haskell - cód foinseach Haskell - código fonte de Haskell - קוד מקור של Haskell - Haskell izvorni kod - Haskell-forráskód - Kode program Haskell - Codice sorgente Haskell - Haskell ソースコード - Haskell бастапқы коды - Haskell 소스 코드 - Haskell pradinis kodas - Haskell pirmkods - Kod sumber Haskell - Haskell-kildekode - Haskell-broncode - Haskell-kjeldekode - Kod źródłowy Haskell - código fonte Haskell - Código-fonte Haskell - Cod sursă Haskell - исходный код Haskell - Zdrojový kód Haskell - Datoteka izvorne kode Haskell - Kod burues Haskell - Haskell изворни ко̂д - Haskell-källkod - вихідний код мовою Haskell - Mã nguồn Haskell - Haskell 源代码 - Haskell 源碼 - - - - - IDL document - مستند IDL - IDL sənədi - Dakument IDL - Документ — IDL - document IDL - Dokument IDL - Dogfen IDL - IDL-dokument - IDL-Dokument - έγγραφο IDL - IDL document - IDL-dokumento - documento IDL - IDL dokumentua - IDL-asiakirja - IDL skjal - document IDL - cáipéis IDL - documento IDL - מסמך IDL - IDL dokument - IDL-dokumentum - Dokumen IDL - Documento IDL - IDL ドキュメント - IDL құжаты - IDL 문서 - IDL dokumentas - IDL dokuments - Dokumen IDL - IDL-dokument - IDL-document - IDL-dokument - Dokument IDL - documento IDL - Documento IDL - Document IDL - документ IDL - Dokument IDL - Dokument IDL - Dokument IDL - IDL документ - IDL-dokument - документ IDL - Tài liệu IDL - IDL 文档 - IDL 文件 - IDL - Interface Definition Language - - - - - installation instructions - تعليمات التثبيت - instrukcyja dla instalavańnia - Инструкции за инсталация - instruccions d'instal·lació - Návod k instalaci - installationsinstruktioner - Installationsanleitung - οδηγίες εγκατάστασης - installation instructions - instrucciones de instalación - instalazioaren instrukzioak - asennusohjeet - innleggingar vegleiðing - instructions d'installation - treoracha suiteála - instrucións de instalación - הוראות התקנה - upute za instalaciju - telepítési utasítások - instruksi instalasi - Istruzioni di installazione - ソフトウェアインストール説明 - бағдарламаны орнату нұсқаулары - 설치 방법 - diegimo instrukcijos - instalācijas instrukcijas - installationsinstruksjoner - installatie-instructies - installasjonsinstruksjonar - Instrukcje instalacji - Instruções de instalação - instrucțiuni de instalare - инструкции по установке программы - Návod na inštaláciu - navodila namestitve - Udhëzime instalimi - installationsinstruktioner - інструкції з встановлення - hướng dẫn cài đặt - 软件安装指南 - 安裝指引 - - - - - Java source code - شفرة مصدر Java - Kryničny kod Java - Изходен код на Java - codi font en Java - Zdrojový kód v Javě - Javakildekode - Java-Quelltext - πηγαίος κώδικας Java - Java source code - Java-fontkodo - código fuente en Java - Java iturburu-kodea - Java-lähdekoodi - Java keldukota - code source Java - cód foinseach Java - código fonte de Java - קוד מקור ב־Java - Java izvorni kod - Java-forráskód - Kode program Java - Codice sorgente Java - Java ソースコード - Java бастапқы коды - 자바 소스 코드 - Java pradinis kodas - Java pirmkods - Kod sumber Java - Java-kildekode - Java-broncode - Java-kjeldekode - Kod źródłowy Java - código fonte Java - Código-fonte Java - Cod sursă Java - исходный код Java - Zdrojový kód Java - Datoteka izvorne kode Java - Kod burues Java - Јава изворни ко̂д - Java-källkod - Java kaynak kodu - вихідний код мовою Java - Mã nguồn Java - Java 源代码 - Java 源碼 - - - - - LDIF address book - دفتر عناوين LDIF - Adrasnaja kniha LDIF - Адресна книга — LDIF - llibreta d'adreces LDIF - Adresář LDIF - LDIF-adressebog - LDIF-Adressbuch - διευθυνσιολόγιο LDIF - LDIF address book - LDIF-adresaro - libreta de direcciones LDIF - LDIF helbide-liburua - LDIF-osoitekirja - LDIF adressubók - carnet d'adresses LDIF - leabhar sheoltaí LDIF - lista de enderezos LDIF - ספר כתובות של LDIF - LDIF adresar - LDIF címjegyzék - Buku alamat LDIF - Rubrica LDIF - LDIF アドレス帳 - LDIF адрестер кітабы - LDIF 주소록 - LDIF adresų knygelė - LDIF adrešu grāmata - LDIF-adressebok - LDIF-adresboek - LDIF-adressebok - Książka adresowa LDIF - Livro de endereços LDIF - Agendă LDIF - адресная книга LDIF - Adresár LDIF - Datoteka imenika naslovov LDIF - Rubrikë LDIF - LDIF-adressbok - LDIF adres defteri - адресна книга LDIF - Sổ địa chỉ LDIF - LDIF 地址簿 - LDIF 通訊錄 - LDIF - LDAP Data Interchange Format - - - - - - - - - Lilypond music sheet - صفحة موسيقى Lilypond - Muzyčny arkuš Lilypond - Нотация на Lilypond - full de música Lilypond - Notový papír Lilypond - Lilypondmusikkort - Lilypond-Notenblatt - παρτιτούρα Lilypond - Lilypond music sheet - partitura de LilyPond - Lilypond musika-orria - Lilypond-nuotit - Lilypond tónleika ark - partition musicale Lilypond - bileog cheoil Lilypond - folla de música de Lilypond - דף מוזיקה של Lilypond - Lilypond kotta - Lembar musik Lilypond - Partitura Lilypond - Lilypond 楽譜データ - Lilypond музыка тізімі - Lilypond 악보 - Lilypond muzikos lapas - Lilypond mūzikas lapa - Lilypond-muziekblad - Lilypond noteark - Plik partytury Lilypond - Partitura do Lilypond - Fișă muzică Lilypond - список музыки Lilypond - Notový papier Lilypond - Glasbena predloga Lilypond - Partiturë Lilypond - Lilypond-notblad - нотний запис Lilypond - Bản nhạc Lilypond - Lilypond 乐谱 - Lilypond 樂譜 - - - - - LHS source code - شفرة مصدر LHS - Kryničny kod LHS - Изходен код на LHS - codi font en LHS - Zdrojový kód v LHS - LHS-kildekode - LHS-Quelltext - πηγαίος κώδικας LHS - LHS source code - LHS-fontkodo - código fuente en LHS - LHS iturburu-kodea - LHS-lähdekoodi - LHS keld - code source LHS - cód foinseach LHS - código fonte en LHS - קוד מקור של LHS - LHS izvorni kod - LHS forráskód - Kode program LHS - Codice sorgente LHS - LHS ソースコード - LHS бастапқы коды - LHS 소스 코드 - LHS pradinis kodas - LHS pirmkods - LHS-kildekode - LHS-broncode - LHS-kjeldekode - Kod źródłowy LHS - Código-fonte LHS - Cod sursă LHS - исходный код LHS - Zdrojový kód LHS - Datoteka izvorne kode LHS - Kod burues LHS - LHS-källkod - LHS kaynak kodu - вихідний код LHS - Mã nguồn LHS - LHS 源代码 - LHS 源碼 - LHS - Literate Haskell source code - - - - - application log - سجل التطبيق - časopis aplikacyi - Файл-дневник на приложение - registre d'aplicació - Záznam aplikace - programlog - Anwendungsprotokoll - ημερολόγιο συμβάντων εφαρμογής - application log - protokolo de aplikaĵo - registro de aplicación - aplikazio egunkaria - sovelluksen lokitiedosto - nýtsluskipan logg - journal d'application - logchomhad feidhmchláir - rexistro de aplicativo - יומן התוכנה - alkalmazás naplója - log aplikasi - Log applicazione - アプリケーションログ - мәлімдемелер журналы - 프로그램 기록 - programos žurnalas - lietotnes žurnāls - Log aplikasi - applikasjonslogg - programma-logbestand - programlogg - Dziennik programu - registo de aplicação - Registro de aplicativo - înregistrare aplicație - журнал сообщений - Záznam aplikácie - dnevnik programa - log i mesazheve të programit - дневник програма - programlogg - uygulama günlüğü - журнал програми - bản ghi ứng dụng - 应用程序日志 - 程式紀錄檔 - - - - - Makefile - ملف Makefile - İnşa faylı - Makefile - Файл — make - Makefile - Makefile - Ffeil "make" - Bygningsfil - Makefile - Makefile - Makefile - Muntodosiero - Makefile - Makefile - Makefile - Makefile - makefile - Makefile - Makefile - Makefile - Makefile - Makefile - Makefile - Makefile - Makefile - Makefile (жинау файлы) - Makefile - Makefile - Makefile - Makefile - Makefile - Makefile - Makefile - Plik make - Makefile - Makefile (arquivo do make) - Makefile - Makefile (файл сборки) - Makefile - Datoteka Makefile - Makefile - Производна датотека - Makefil - файл проекту make - Tập tin tạo ứng dụng (Makefile) - Makefile - Makefile - - - - - - - - - - - - - Markdown document - Документ — Markdown - document Markdown - Dokument Markdown - Markdown-dokument - Markdown-Dokument - Markdown document - Documento de Markdown - Markdown-asiakirja - document Markdown - documento de Markdown - מסמך Markdown - Markdown dokument - Markdown dokumentum - Dokumen markdown - Documento Markdown - Markdown - Markdown құжаты - 마크다운 문서 - Markdown dokuments - Markdown document - Dokument Markdown - Documento Markdown - документ Markdown - Dokument Markdown - документ Markdown - Markdown 文档 - Markdown 文件 - - - - - - - Qt MOC file - ملف Qt MOC - Fajł Qt MOC - Файл — Qt MOC - fitxer MOC de Qt - Soubor Qt MOC - Qt MOC-fil - Qt-MOC-Datei - αρχείο Qt MOC - Qt MOC file - archivo MOC Qt - Qt MOC fitxategia - Qt MOC -tiedosto - Qt MOC fíla - fichier Qt MOC - comhad MOC Qt - ficheiro MOC Qt - קובץ Qt MOC - Qt MOC datoteka - Qt MOC fájl - Berkas Qt MOC - File MOC Qt - Qt MOC ファイル - Qt MOC файлы - Qt MOC 파일 - Qt MOC failas - Qt MOC datne - Qt MOC-fil - Qt MOC-bestand - Qt MOC-fil - Plik Qt MOC - Arquivo Qt MOC - Fișier Qt MOC - файл Qt MOC - Súbor Qt MOC - Datoteka Qt MOC - File Qt MOC - Qt MOC-fil - файл-метаоб'єкт Qt - Tập tin MOC của Qt - Qt 元对象编译文件 - Qt MOC 檔 - Qt MOC - Qt Meta Object Compiler - - - - - Windows Registry extract - استخراج مسجل ويندوز - Element rehistru Windows - Извадка от регистъра на Windows - extracte del registre de Windows - Část registrů Windows - Windows Registy-udtrækning - Windows-Registry-Auszug - αποσυμπίεση Windows Registry - Windows Registry extract - extracto del registro de Windows - Windows-eko erregistro erauzlea - Windows-rekisteritietue - Windows Registry úrdráttur - extrait de registre Windows - sliocht as Clárlann Windows - Extracto do rexistro de Windows - קובץ Registry של Windows - Windows Registry kivonat - Ekstrak Windows Registry - Estratto Windows Registry - WIndows レジストリ抽出ファイル - Windows Registry бөлігі - Windows 레지스트리 파일 - Windows registro ištrauka - Windows Registry izvilkums - Utdrag av Windows Registry - Windows Registry-extract - Windows Registry-utdrag - Wycinek rejestru Windows - Extrator de registro do Windows - Extras al registrului Windows - фрагмент Windows Registry - Časť registrov Windows - izvleček vpisnika Windows - Pjesë Windows Registry - Windows Registry-utdrag - частина реєстру Windows - Bản trích Registry Windows - Windows 注册表文件 - Windows Registry 抽出 - - - - - - - - - - Managed Object Format - صيغة كائن مدار - Farmat Managed Object - Управлявани обекти — MOF - format d'objecte gestionat - Managed Object Format - Håndteret objektformat - Managed Object Format - Μορφή Διαχειριζόμενου Αντικειμένου - Managed Object Format - formato de objeto manejado - Kudeatutako objektu formatua - Managed Object Format - format Managed Object - formáid réada bainistithe - formato de obxecto xestionado - פורמט ניהול אובייקט - Felügyelt objektum (MO) formátum - Managed Object Format - Managed Object Format - 管理オブジェクトフォーマット - Басқарылатын объект пішімі - 관리되는 오브젝트 형식 - Sutvarkytų objektų formatas - Pārvaldītu objektu formāts - Managed Object Format - Managed Object Format - Managed Object Format - Plik Managed Object Format - Formato de objeto gerenciado - Managed Object Format - формат управляемого объекта - Formát Managed Object - Datoteka Managed Object - Managed Object Format - Managed Object Format - формат керування об’єктами - Định dạng Đối tượng đã Quản lý - 托管对象格式 - Managed Object Format - - - - - Mup publication - منشور Mup - Publikacyja Mup - Издание — Mup - publicació Mup - Publikace Mup - Mupudgivelse - Mup-Veröffentlichung - δημοσίευση Mup - Mup publication - publicación Mup - Mup publikazioa - Mup-julkaisu - Mup útgáva - publication Mup - foilseachán Mup - publicación Mup - פרסום של Mup - Mup publikáció - Publikasi Mup - Pubblicazione Mup - Mup 出版ファイル - Mup жариялымы - Mup 출판물 - Mup leidinys - Mup publikācija - Mup publikasjon - Mup-publicatie - Mup-publikasjon - Publikacja Mup - Publicação do Mup - Publicație Mup - публикация Mup - Publikácie Mup - Datoteka objave Mup - Publikim Mup - Mup-publicering - публікація Mup - Bản xuất Mup - Mup 应用程序 - Mup 出版品 - - - - - - - - - Objective-C source code - شفرة مصدر الهدف-C - Kryničny kod Objective-C - Изходен код — Objective C - codi font en Objective-C - Zdrojový kód v Objective-C - Objektiv C-kildekode - Objective-C-Quelltext - πηγαίος κώδικας Objective-C - Objective-C source code - fontkodo en Objective-C - código fuente en Objective-C - Objective-C iturburu-kodea - Objective-C-lähdekoodi - Objective-C keldukota - code source Objective-C - cód foinseach Objective-C - código fonte de Objective-C - קוד מקור של Objective-C - Objective-C forráskód - Kode program Objective-C - Codice sorgente Objective-C - Objective-C ソースコード - Objective-C-ის საწყისი კოდი - Objective-C бастапқы коды - Objective-C 소스 코드 - Objective-C pradinis kodas - Objective-C pirmkods - Kod sumber Objective-C - Objective-C-kildekode - Objective-C-broncode - Objective-C-kjeldekode - Kod źródłowy Objective-C - código fonte Objective-C - Código-fonte Objective-C - Cod sursă Objective-C - исходный код Objective-C - Zdrojový kód Objective-C - Datoteka izvorne kode Objective-C - Kod burues C objekt - Објектни-C изворни ко̂д - Objective-C-källkod - вихідний код мовою Objective-C - Mã nguồn Objective-C - Objective-C 源代码 - Objective-C 源碼 - - - - - - - - OCaml source code - شفرة مصدر OCaml - Kryničny kod OCaml - Изходен код — OCaml - codi font en OCaml - Zdrojový kód OCaml - OCaml-kildekode - OCaml-Quelltext - πηγαίος κώδικας OCaml - OCaml source code - OCaml-fontkodo - código fuente en OCaml - OCaml iturburu-kodea - OCaml-lähdekoodi - OCaml keldukota - code source OCaml - cód foinseach OCaml - código fonte de OCaml - קוד מקור של OCaml - OCaml izvorni kod - OCaml forráskód - Kode program OCaml - Codice sorgente OCaml - OCaml ソースコード - OCaml бастапқы коды - OCaml 소스 코드 - OCaml pradinis kodas - OCaml pirmkods - OCaml-kildekode - OCaml-broncode - OCaml-kjeldekode - Kod źródłowy OCaml - Código-fonte OCaml - Cod sursă OCaml - исходный код OCaml - Zdrojový kód OCaml - Datoteka izvorne kode OCaml - Kod burues OCaml - OCaml-källkod - OCaml kaynak kodu - первинний код мовою OCaml - Mã nguồn OCaml - OCaml 源代码 - OCaml 源碼 - - - - - MATLAB script/function - سكربت/وظيفة MATLAB - Skrypt/funkcyja MATLAB - Скрипт/функция — MATLAB - script/funció MATLAB - Skript/funkce MATLAB - MATLAB-program/-funktion - MATLAB-Skript/-Funktion - δέσμη εντολών / συνάρτηση MATLAB - MATLAB script/function - script/función de MATLAB - MATLAB script/funtzioa - MATLAB-komentotiedosto/funktio - MATLAB boðrøð/funka - script/fonction MATLAB - script/feidhm MATLAB - función/script de MATLAB - תסריט/פונקציית MATLAB - MATLAB skripta/funkcija - MATLAB parancsfájl/funkció - Skrip/fungsi MATLAB - Script/Funzione MATLAB - MATLAB スクリプト/関数 - MATLAB сценарий/функциясы - MATLAB 스크립트/함수 - MATLAB scenarijus / funkcija - MATLAB skripts/funkcija - Skript/funksjon for MATLAB - MATLAB-script/functie - MATLAB-skript/funksjon - Skrypt/funkcja MATLAB - Script/função do MATLAB - Funcție/script MATLAB - сценарий/функция MATLAB - Skript/funkcia MATLAB - Skriptna datoteka MATLAB - Script/Funksion MATLAB - MATLAB-skript/funktion - скрипт/функція MATLAB - Văn lệnh/chức năng MATLAB - MATLAB 脚本/函数 - MATLAB 指令稿/函式 - - - - - - - - - - - - - - - Modelica model - - - - - - - - - - - - - - - - - - - - Pascal source code - شفرة مصدر باسكال - Kryničny kod Pascal - Изходен код — Pascal - codi font en Pascal - Zdrojový kód v Pascalu - Pascalkildekode - Pascal-Quelltext - πηγαίος κώδικας Pascal - Pascal source code - Pascal-fontkodo - código fuente en Pascal - Pascal iturburu-kodea - Pascal-lähdekoodi - Pascal keldukota - code source Pascal - cód foinseach Pascal - código fonte en Pascal - קוד מקור של Pascal - Pascal-forráskód - Kode program Pascal - Codice sorgente Pascal - Pascal ソースコード - Pascal бастапқы коды - 파스칼 소스 코드 - Pascal pradinis kodas - Pascal pirmkods - Kod sumber Pascal - Pascal-kildekode - Pascal-broncode - Pascal-kjeldekode - Kod źródłowy Pascal - código fonte Pascal - Código-fonte Pascal - Cod sursă Pascal - исходный код Pascal - Zdrojový kód Pascal - Datoteka izvorne kode Pascal - Kod burues Pascal - Паскал изворни ко̂д - Pascal-källkod - Pascal kaynak kodu - вихідний код мовою Pascal - Mã nguồn Pascal - Pascal 源代码 - Pascal 源碼 - - - - - - differences between files - الاختلافات بين الملفات - adroźnieńni pamiž fajłami - Разлики между файлове - diferències entre fitxers - Rozdíly mezi soubory - forskel mellem filer - Unterschiede zwischen Dateien - διαφορές μεταξύ αρχείων - differences between files - diferencoj inter dosieroj - diferencias entre archivos - fitxategien arteko ezberdintasunak - tiedostojen väliset erot - munur millum fílur - différences entre fichiers - difríochtaí idir chomhaid - diferenzas entre ficheiros - ההבדל בין קבצים - razlike između datoteka - diff-különbségfájl - perbedaan diantara berkas - Differenze tra file - ファイル間差分 - файлдар арасындағы айырмашылықтары - 파일 사이의 차이점 - skirtumai tarp failų - divu datņu atšķirība - Perbezaan antara fail - forskjeller mellom filer - verschillen tussen bestanden - skilnader mellom filer - Różnica pomiędzy plikami - diferenças entre ficheiros - Diferenças entre arquivos - diferențe între fișiere - различия между файлами - Rozdiely medzi súbormi - razlike med datotekami - Diferencë midis file - разлике међу датотекама - skillnader mellan filer - різниця між файлами - khác biệt giữa các tập tin - 文件的区别 - 檔案內容差異 - - - - - - - - - - - - - - - - - - - Go source code - Изходен код — Go - codi font en Go - Zdrojový kód Go - Go-kildekode - Go-Quellcode - πηγαίος κώδικας Go - Go source code - Go-fontkodo - Ir al código fuente - Go-lähdekoodi - code source Go - código fonte de Go - קוד מקור של Go - Go izvorni kod - Go forráskód - Kode sumber Go - Codice sorgente Go - Go ソースコード - Go-ის საწყისი კოდი - Go бастапқы коды - Go 소스 코드 - Go pirmkods - Go broncode - Kod źródłowy Go - Código-fonte Go - исходный код Go - Izvorna koda Go - вихідний код мовою Go - Go - Go 源碼 - - - - - Python script - سكربت بايثون - Skrypt Python - Скрипт — Python - script Python - Skript v Pythonu - Pythonprogram - Python-Skript - πρόγραμμα εντολών Python - Python script - Python-skripto - script en Python - Python script-a - Python-komentotiedosto - Python boðrøð - script Python - script Python - Script en Python - תסריט Python - Python skripta - Python-parancsfájl - Skrip Python - Script Python - Python スクリプト - Python сценарийі - 파이썬 스크립트 - Python scenarijus - Python skripts - Skrip Python - Python-skript - Python-script - Python-skript - Skrypt Python - 'script' Python - Script Python - Script Python - сценарий Python - Skript Python - Skriptna datoteka Python - Script Python - Питон скрипта - Pythonskript - скрипт мовою Python - Văn lệnh Python - Python 脚本 - Python 指令稿 - - - - - - - - - - - - - - - - - - - - Lua script - سكربت Lua - Skrypt Lua - Скрипт на Lua - script Lua - Skript Lua - Luaprogram - Lua-Skript - δέσμη εντολών Lua - Lua script - Lua-skripto - script en Lua - Lua script-a - Lua-komentotiedosto - Lua boðrøð - script Lua - script Lua - script de Lua - תסריט Lua - Lua skripta - Lua parancsfájl - Skrip Lua - Script Lua - Lua スクリプト - Lua сценарийі - Lua 스크립트 - Lua scenarijus - Lua skripts - Lua-skript - Lua-script - Lua-skript - Skrypt Lua - Script Lua - Script Lua - сценарий Lua - Skript Lua - Skriptna datoteka Lua - Script Lua - Lua-skript - скрипт Lua - Văn lệnh Lua - Lua 脚本 - Lua 指令稿 - - - - - - - - - - - - README document - مستند README - README sənədi - Dakument README - Документ — „Да се прочете“ - document README - Dokument README - Dogfen README - README-dokument - README-Dokument - έγγραφο README - README document - README-dokumento - documento README - README dokumentua - LUEMINUT-asiakirja - README skjal - document LISEZ-MOI - cáipéis README - documento README - מסמך README - README dokument - README-dokumentum - Dokumen README - Documento README - README ドキュメント - README құжаты - README 문서 - README dokumentas - README dokuments - Dokumen README - README-dokument - LEESMIJ-document - README-dokument - Dokument README - documento LEIA-ME - Documento README - Document README - документ README - Dokument README - Dokument README - Dokument README - ПРОЧИТАЈМЕ документ - README-dokument - документ README - Tài liệu Đọc Đi (README) - README 文档 - README 說明文件 - - - - - NFO document - مستند NFO - Dakument NFO - Документ — NFO - document NFO - Dokument NFO - NFO-dokument - NFO-Dokument - έγγραφο NFO - NFO document - NFO-dokumento - documento NFO - NFO dokumentua - NFO-asiakirja - NFO skjal - document NFO - cáipéis NFO - documento NFO - מסמך NFO - NFO dokument - NFO-dokumentum - Dokumen NFO - Documento NFO - NFO ドキュメント - NFO құжаты - NFO 문서 - NFO dokumentas - NFO dokuments - NFO-dokument - NFO-document - NFO-dokument - Dokument NFO - Documento NFO - Document NFO - документ NFO - Dokument NFO - Dokument NFO - Dokument NFO - NFO-dokument - NFO belgesi - документ NFO - Tài liệu NFO - NFO 文档 - NFO 文件 - - - - - RPM spec file - ملف مواصفات RPM - Specyfikacyjny fajł RPM - Файл — спецификация за RPM - fitxer spec RPM - Soubor spec RPM - RPM spec-fil - RPM-Spezifikationsdatei - αρχείο spec RPM - RPM spec file - archivo de especificaciones RPM - RPM espezifikazio fitxategia - RPM spec -tiedosto - RPM tøknilýsingarfíla - fichier de spécification RPM - comhad spec RPM - ficheiro de especificacións RPM - קובץ מפרט RPM - RPM spec fájl - Berkas spesifikasi RPM - File specifica RPM - RPM spec ファイル - RPM анықтама файлы - RPM spec 파일 - RPM spec failas - RPM specifikācijas datne - RPM-spesifikasjonsfil - RPM-spec-bestand - RPM spec-fil - Plik spec RPM - Arquivo de especificação RPM - Fișier RPM spec - файл описания RPM - Súbor RPM spec - Določilna datoteka RPM - File specifikimi RPM - RPM spec-fil - spec-файл RPM - Tập tin đặc tả RPM - RPM spec 文件 - RPM spec 規格檔 - RPM - Red Hat Package Manager - - - - - - - - - Scala source code - Изходен код — Scala - codi font en Scala - Zdrojový kód Scala - Scala-kildekode - Scala-Quellcode - πηγαίος κώδικας Scala - Scala source code - Código fuente en Scala - Scala-lähdekoodi - code source Scala - código fnote en Scala - קוד מקור של Scala - Scala izvorni kod - Scala forráskód - Kode sumber Scala - Codice sorgente Scala - Scala ソースコード - Scala-ის საწყისი კოდი - Scala бастапқы коды - Scala 소스 코드 - Scala pirmkods - Scala broncode - Kod źródłowy Scala - Código-fonte Scala - исходный код Scala - Izvorna koda Scala - Scala-källkod - вихідний код мовою Scala - Scala 源代码 - Scala 源碼 - - - - - Scheme source code - شفرة مصدر Scheme - Sxem mənbə kodu - Kryničny kod Scheme - Изходен код — Scheme - codi font en Scheme - Zdrojový kód Scheme - Ffynhonnell Rhaglen Scheme - Schemekildekode - Scheme-Quelltext - πηγαίος κώδικας Scheme - Scheme source code - Scheme-fontkodo - código fuente en Scheme - Scheme iturburu-kodea - Scheme-lähdekoodi - Scheme keldukota - code source Scheme - cód foinseach Scheme - código fonte en Scheme - קוד מקור של Scheme - Scheme izvorni kod - Scheme-forráskód - Kode program Scheme - Codice sorgente Scheme - Scheme ソースコード - Scheme бастапқы коды - Scheme 소스 코드 - Scheme pradinis kodas - Scheme pirmkods - Kod sumber Scheme - Scheme-kildekode - Scheme-broncode - Scheme-kjeldekode - Kod źródłowy Scheme - código fonte Scheme - Código-fonte Scheme - Cod sursă Scheme - исходный код Scheme - Zdrojový kód Scheme - Datoteka izvorne kode Scheme - Kod burues Scheme - Scheme изворни ко̂д - Scheme-källkod - Scheme kaynak kodu - вихідний файл мовою Scheme - Mã nguồn Scheme - Scheme 源代码 - Scheme 源碼 - - - - - - Setext document - مستند Setext - Setext sənədi - Dakument Setext - Документ — Setext - document Setext - Dokument Setext - Dogfen Setext - Setextdokument - Setext-Dokument - έγγραφο Setext - Setext document - Setext-dokumento - documento Setext - Setext dokumentua - Setext-asiakirja - Setext skjal - document Setext - cáipéis Setext - documento Settext - מסמך של Setext - Setext dokument - Setext-dokumentum - Dokumen Setext - Documento Setext - Setext ドキュメント - Setext құжаты - Setext 문서 - Setext dokumentas - Setext dokuments - Dokumen Setext - Setext-dokument - Setext-document - Setext-dokument - Dokument Setext - documento Setext - Documento Setext - Document Setext - документ Setext - Dokument Setext - Dokument Setext - Dokument Setext - Setext документ - Setext-dokument - Setext belgesi - документ Setext - Tài liệu Setext - Setext 文档 - Setext 文件 - - - - - SQL code - شفرة SQL - SQL kodu - Kod SQL - Код — SQL - codi en SQL - Kód SQL - Côd SQL - SQL-kode - SQL-Befehle - κώδικας SQL - SQL code - SQL-kodo - código SQL - SQL kodea - SQL-koodi - SQL kota - code SQL - cód SQL - código SQL - קוד SQL - SQL kod - SQL-kód - Kode SQL - Codice SQL - SQL コード - SQL коды - SQL 코드 - SQL kodas - SQL kods - Kod SQL - SQL-kildekode - SQL-code - SQL-kode - Kod SQL - código SQL - Código SQL - Cod SQL - код SQL - Kód SQL - Datoteka kode SQL - Kod SQL - SQL ко̂д - SQL-kod - SQL kodu - код SQL - Mã SQL - SQL 代码 - SQL 代碼 - - - - - - Tcl script - سكربت Tcl - Skrypt Tcl - Скрипт — Tcl - script Tcl - Skript v Tcl - Tcl-program - Tcl-Skript - πρόγραμμα εντολών Tcl - Tcl script - Tcl-skripto - script en Tcl - Tcl script-a - Tcl-komentotiedosto - Tcl boðrøð - script Tcl - script Tcl - Script en Tcl - תסריט Tcl - Tcl skripta - Tcl-parancsfájl - Skrip Tcl - Script Tcl - Tcl スクリプト - Tcl сценарийі - Tcl 스크립트 - Tcl scenarijus - Tcl skripts - Skrip Tcl - Tcl-skript - Tcl-script - Tcl-skript - Skrypt Tcl - 'script' Tcl - Script Tcl - Script Tcl - сценарий Tcl - Skript Tcl - Skriptna datoteka Tcl - Script Tcl - Tcl скрипта - Tcl-skript - скрипт Tcl - Văn lệnh Tcl - Tcl 脚本 - Tcl 描述語言檔 - - - - - - TeX document - مستند TeX - Dakument TeX - Документ — TeX - document TeX - Dokument TeX - Dogfen TeX - TeX-dokument - TeX-Dokument - έγγραφο TeX - TeX document - TeX-dokumento - documento TeX - TeX dokumentua - TeX-asiakirja - TeX skjal - document TeX - cáipéis TeX - documenton TeX - מסמך TeX - TeX dokument - TeX-dokumentum - Dokumen TeX - Documento TeX - TeX ドキュメント - TeX құжаты - TeX 문서 - TeX dokumentas - TeX dokuments - Dokumen TeX - TeX-dokument - TeX-document - TeX-dokument - Dokument TeX - documento TeX - Documento TeX - Document TeX - документ TeX - Dokument TeX - Dokument TeX - Dokument TeX - ТеХ документ - TeX-dokument - TeX belgesi - документ TeX - Tài liệu TeX - TeX 文档 - TeX 文件 - - - - - - - - - - - - - - - - - - TeXInfo document - مستند TeXInfo - TeXInfo sənədi - Dakument TeXInfo - Документ — TeXInfo - document TeXInfo - Dokument TeXInfo - Dogfen TeXInfo - TeXInfo-dokument - TeXInfo-Dokument - έγγραφο TeXInfo - TeXInfo document - TeXInfo-dokumento - documento TeXInfo - TeXInfo dokumentua - TeXInfo-asiakirja - TeXInfo skjal - document TeXInfo - cáipéis TeXInfo - documento TeXInfo - מסמך של TeXInfo - TeXInfo dokument - TeXInfo-dokumentum - Dokumen TeXInfo - Documento TeXInfo - TeXInfo ドキュメント - TeXInfo құжаты - TeXInfo 문서 - TeXInfo dokumentas - TeXInfo dokuments - Dokumen TeXInfo - TeXInfo-dokument - TeXInfo-document - TeXInfo-dokument - Dokument TeXInfo - documento TeXInfo - Documento TeXInfo - Document TexInfo - документ TeXInfo - Dokument TeXInfo - Dokument TeXInfo - Dokument TeXInfo - ТеХинфо документ - TeXInfo-dokument - TeXInfo belgesi - документ TeXInfo - Tài liệu TeXInfo - TeXInfo 文档 - TeXInfo 文件 - - - - - - Troff ME input document - مستند Troff ME input - Uvodny dakument Troff ME - Изходен документ — Troff ME - document d'entrada Troff ME - Vstupní dokument Troff ME - Troff ME inddata-dokument - Troff-ME-Eingabedokument - έγγραφο/πρόγραμμα εντολών troff ME - Troff ME input document - eniga dokumento de Troff ME - documento de entrada Troff ME - Troff ME sarrerako dokumentua - Troff ME -syöteasiakirja - Troff ME inntaksskjal - document d'entrée Troff ME - cáipéis ionchur Troff ME - documento de entrada Troff ME - מסמך קלט של Troff ME - Troff ME ulazni dokument - Troff ME bemeneti dokumentum - Dokumen masukan Troff ME - Documento di input Troff ME - Troff ME 入力ドキュメント - Troff ME кіріс құжаты - Troff ME 입력 문서 - Troff ME įvesties dokumentas - Troff ME ievades dokuments - Dokumen input Troff ME - Troff ME-inndatadokument - Troff ME-invoerdocument - Troff ME inndata-dokument - Dokument wejściowy Troff ME - documento origem Troff ME - Documento de entrada Troff ME - Document intrare Troff ME - входной документ Troff ME - Vstupný dokument Troff ME - Vnosni dokument Troff ME - Dokument i input Troff ME - Troff ME улазни документ - Troff ME-indatadokument - Troff ME girdi belgesi - вхідний документ Troff ME - Tài liệu nhập ME Troff - Troff ME 输入文档 - Troff ME 輸入文件 - - - - - Troff MM input document - مستند Troff MM input - Uvodny dakument Troff MM - Изходен документ — Troff MM - document d'entrada Troff MM - Vstupní dokument Troff MM - Troff MM inddata-dokument - Troff-MM-Eingabedokument - έγγραφο/πρόγραμμα εντολών troff MM - Troff MM input document - eniga dokumento de Troff MM - documento de entrada Troff MM - Troff MM sarrerako dokumentua - Troff MM -syöteasiakirja - Troff MM inntaksskjal - document d'entrée Troff MM - cáipéis ionchur Troff MM - documento de entrada Troff MM - מסמך קלט של Troff MM - Troff MM ulazni dokument - Troff MM bemeneti dokumentum - Dokumen masukan Troff MM - Documento di input Troff MM - Troff MM 入力ドキュメント - Troff MM кіріс құжаты - Troff MM 입력 문서 - Troff MM įvesties dokumentas - Troff MM ievades dokuments - Dokumen input Troff MM - Troff MM-inndatadokument - Troff MM-invoerdocument - Troff MM inndata-dokument - Dokument wejściowy Troff MM - documento origem Troff MM - Documento de entrada Troff MM - Document intrare Troff MM - входной документ Troff MM - Vstupný dokument Troff MM - Vnosni dokument Troff MM - Dokument i input Troff MM - Troff MM улазни документ - Troff MM-indatadokument - Troff MM girdi belgesi - вхідний документ Troff MM - Tài liệu nhập MM Troff - Troff MM 输入文档 - Troff MM 輸入文件 - - - - - Troff MS input document - مستند Troff MS input - Uvodny dakument Troff MS - Изходен документ — Troff MS - document d'entrada Troff MS - Vstupní dokument Troff MS - Troff MS inddata-dokument - Troff-MS-Eingabedokument - έγγραφο/πρόγραμμα εντολών troff MS - Troff MS input document - eniga dokumento de Troff MS - documento de entrada Troff MS - Troff MS sarrerako dokumentua - Troff MS -syöteasiakirja - Troff MS inntaksskjal - document d'entrée Troff MS - cáipéis ionchur Troff MS - documento de entrada Troff MS - מסמך קלט של Troff MS - Troff MS ulazni dokument - Troff MS bemeneti dokumentum - Dokumen masukan Troff MS - Documento di input Troff MS - Troff MS 入力ドキュメント - Troff MS кіріс құжаты - Troff MS 입력 문서 - Troff MS įvesties dokumentas - Troff MS ievades dokuments - Dokumen input Troff MS - Troff MS-inndatadokument - Troff MS-invoerdocument - Troff MS inndata-dokument - Dokument wejściowy Troff MS - documento origem Troff MS - Documento de entrada Troff MS - Document intrare Troff MS - входной документ Troff MS - Vstupný dokument Troff MS - Vnosni dokument Troff MS - Dokument i input Troff MS - Troff MS улазни документ - Troff MS-indatadokument - Troff MS girdi belgesi - вхідний документ Troff MS - Tài liệu nhập MS Troff - Troff MS 输入文档 - Troff MS 輸入文件 - - - - - X-Motif UIL table - جدول X-Motif UIL - Tablica X-Motif UIL - Таблица — X-Motif UIL - taula UIL de X-Motif - Tabulka X-Motif UIL - X-Motif UIL-tabel - X-Motif-UIL-Tabelle - πίνακας X-Motif UIL - X-Motif UIL table - tabla de X-Motif UIL - X-Motif UIL taula - X-Motif UIL -taulukko - X-Motif UIL talva - table X-Motif UIL - tábla X-Motif UIL - Táboa de X-Motif UIL - טבלה של X-Motif UIL - X-Motif UIL tablica - X-Motif UIL-táblázat - Tabel X-Motif UIL - Tabella UIL X-Motif - X-Motif UIL 表 - X-Motif UIL кестесі - X-Motif UIL 테이블 - X-Motif UIL lentelė - X-Motif UIL tabula - Jadual X-Motif UIL - X-Motif UIL-tabell - X-Motif UIL-tabel - X-Motif UIL-tabell - Tabela UIL X-Motif - tabela UIL do X-Motif - Tabela UIL do X-Motif - Tabel X-Motif UIL - таблица UIL X-Motif - Tabuľka X-Motif UIL - Preglednica X-Motif UIL - Tabelë X-Motif UIL - X-Motif UIL табела - X-Motif UIL-tabell - таблиця X-Motif UIL - Bảng UIL X-Motif - X-Motif UIL 表 - X-Motif UIL 表格 - - - - - resource location - موقع المورد - pałažeńnie resursu - Местоположение на ресурс - localització de recurs - Umístění zdroje - resurseplacering - Ressourcenort - τοποθεσία πόρου - resource location - loko de risurco - ubicación del recurso - baliabidearen kokalekua - resurssisijainti - tilfeingisstaður - localisation de ressource - suíomh acmhainne - localización do recurso - מיקומו של המקור - položaj resursa - erőforrás-hely - lokasi sumber daya - Posizione risorsa - リソースの場所 - ресурс орналасуы - 자원 위치 - resurso vieta - resursa atrašanās vieta - Lokasi sumber - ressurslokasjon - bronlocatie - ressursplassering - Położenie zasobu - localização de recurso - Localização de recurso - locație de resursă - расположение ресурса - Umiestnenie zdroja - mesto vira - Pozicion rezerve - путања ресурса - resursplats - розташування ресурсу - địa điểm tài nguyên - 资源位置 - 資源位置 - - - - - uuencoded file - - - - - - - - - XMI file - ملف XMI - Fajł XMI - Файл — XMI - fitxer XMI - Soubor XMI - XMI-fil - XMI-Datei - αρχείο XML - XMI file - XMI-dosiero - archivo XMI - XMI fitxategia - XMI-tiedosto - XMI fíla - fichier XMI - comhad XMI - ficheiro XMI - קובץ XMI - XMI datoteka - XMI fájl - Berkas XMI - File XMI - XMI ファイル - XMI файлы - XMI 파일 - XMI failas - XMI datne - XMI-fil - XMI-bestand - XMI-fil - Plik XMI - Arquivo XMI - Fișier XMI - файл XMI - Súbor XMI - Datoteka XMI - File XMI - XMI-fil - файл XMI - Tập tin XMI - XMI 文件 - XMI 檔 - XMI - XML Metadata Interchange - - - - - - - XSL FO file - ملف XSL FO - Fajł XSL FO - Форматиращ файл — XSL FO - fitxer FO XSL - Soubor XSL FO - XML FO-fil - XSL-FO-Datei - αρχείο XSL FO - XSL FO file - XSL-FO-dosiero - archivo XSL FO - XSL FO fitxategia - XSL FO -tiedosto - XSL FO fíla - fichier XSL FO - comhad XSL FO - ficheiro XSL FO - קובץ XSL FO - XSL FO datoteka - XSL FO fájl - Berkas XSL FO - File XSL FO - XSL FO ファイル - XSL FO файлы - XSL 포매팅 개체 파일 - XSL FO failas - XSL FO datne - FO-fil for XSL - XSL FO-bestand - XSL FO-fil - Plik XSL FO - Arquivo XSL FO - Fișier XSL FO - файл XSL FO - Súbor XSL FO - Datoteka XSL FO - File XSL FO - XSL FO-fil - файл XSL FO - Tập tin FO của XSL (XFO) - XSL 格式化对象文件 - XSL FO 檔 - XSL FO - XSL Formatting Objects - - - - - - - iptables configuration file - ملف تضبيط iptables - kanfihuracyjny fajł iptables - Настройки за iptables - fitxer de configuració d'iptables - Soubor nastavení iptables - iptableskonfigurationsfil - iptables-Konfigurationsdatei - αρχείο ρυθμίσεων iptables - iptables configuration file - archivo de configuración de iptables - iptables konfigurazio-fitxategia - iptables-asetustiedosto - iptables samansetingarfíla - fichier de configuration iptables - comhad cumraíochta iptables - ficheiro de configuración de iptables - קובץ הגדרה של iptables - iptables datoteka s postavkama - iptables beállítófájl - berkas konfigurasi iptables - File configurazione iptables - iptables 設定ファイル - iptables баптаулар файлы - iptables 설정 파일 - iptables konfigūracijos failas - iptables konfigurācijas datne - konfigurasjonsfil for iptables - iptables-configuratiebestand - iptables oppsettfil - Plik konfiguracji iptables - Arquivo de configuração do iptables - fișier configurare iptables - конфигурационный файл iptables - Súbor nastavení iptables - nastavitvena datoteka iptables - File konfigurimi iptables - iptables-konfigurationsfil - файл налаштувань iptables - tập tin cấu hình iptables - iptables 防火墙配置文件 - iptables 組態檔 - - - - - - - - - - - - - - - - - - - - - - - - - XSLT stylesheet - نمط XSLT - Arkuš stylaŭ XSLT - Стилове — XSLT - full d'estil XSLT - Styl XSLT - XSLT-stilark - XSLT-Stylesheet - φύλλο στυλ XSLT - XSLT stylesheet - XSLT-stilfolio - hoja de estilo XSLT - XSLT estilo-orria - XSLT-tyylitiedosto - XSLT sniðark - feuille de style XSLT - stílbhileog XSLT - folla de estilo XSLT - סגנון גליון XSLT - XSLT stilska tablica - XSLT-stíluslap - Lembar gaya XSLT - Foglio di stile XSLT - XSLT スタイルシート - XSLT стильдер кестесі - XSLT 스타일시트 - XSLT stiliaus aprašas - XSLT izklājlapa - Helaian Gaya XSLT - XSLT-stilark - XSLT-stijlblad - XSLT-stilark - Arkusz stylów XSLT - folha de estilos XSLT - Folha de estilo XSLT - Fișă de stil XSLT - таблица стилей XSLT - Štýl XSLT - Slogovna predloga XSLT - Fletë stili XSLT - Датотека са XSLT стилом - XSLT-stilmall - таблиця стилів XSLT - Tờ kiểu dáng XSLT - XSLT 样式表 - XSLT 樣式表 - XSLT - eXtensible Stylesheet Language Transformation - - - - - - - - - - - XMCD CD database - قاعدة بيانات XMCD CD - Baza źviestak ab dyskach XMCD - База от данни за CD-та — XMCD - base de dades de CD XMCD - Databáze XMCD CD - XMCD-cd-database - XMCD-CD-Datenbank - βάση δεδομένων CD XMCD - XMCD CD database - base de datos de CD XMCD - XMCD CD datu-basea - XMCD CD -tietokanta - XMCD fløgu dátustovnur - base de données de CD XMCD - bunachar sonraí XMCD CD - base de datos de CD XMCD - בסיס נתונים XMCD CD - XMCD CD baza podataka - XMCD CD-adatbázis - Basis data XMCD CD - Database XMCD CD - XMCD CD データベース - XMCD CD дерекқоры - XMCD CD 데이터베이스 - XMCD CD duomenų bazė - XMCD CD datubāze - XMCD CD-database - XMCD CD-gegevensbank - XMCD CD-database - Baza danych CD XMCD - Banco de dados de CD XMCD - Bază de date XMCD CD - база данных компакт-дисков XMCD - Databáza XMCD CD - Podatkovna zbirka XMCD CD - Bazë me të dhëna XMCD CD - XMCD cd-databas - база даних XMCD CD - Cơ sở dữ liệu CD XMCD - XMCD CD 数据库 - XMCD CD 資料庫 - - - - - - - XML document - مستند XML - Dakument XML - Документ — XML - document XML - Dokument XML - XML-dokument - XML-Dokument - έγγραφο XML - XML document - XML-dokumento - documento XML - XML dokumentua - XML-asiakirja - XML skjal - document XML - cáipéis XML - documento XML - מסמך XML - XML dokument - XML dokumentum - Dokumen XML - Documento XML - XML ドキュメント - XML құжаты - XML 문서 - XML dokumentas - XML dokuments - XML-dokument - XML-document - XML-dokument - Dokument XML - Documento XML - Document XML - документ XML - Dokument XML - Dokument XML - Dokument XML - XML-dokument - документ XML - Tài liệu XML - XML 文档 - XML 文件 - XML - eXtensible Markup Language - - - - - - - - - - - - - - XML entities document - مستند كيانات XML - Dakument elementaŭ XML - Документ — заместващи последователности в XML - document d'entitats XML - Dokument entit XML - XML-enhedsdokument - XML-Dokument-Entitäten - έγγραφο οντοτήτων XML - XML entities document - documento de entidades XML - XML entitateen dokumentua - XML-entiteettiasiakirja - XML einindisskjal - document d'entités XML - cáipéis aonán XML - documento de entidades XML - מסמך ישיות XML - XML egyeddokumentum - Dokumen entitas XML - Documento entità XML - XML エントリドキュメント - XML мәндер құжаты - XML 엔티티 문서 - XML esybių dokumentas - XML vienību dokuments - XML-entitetsdokument - XML entiteiten-document - XML-entitet-dokument - Dokument jednostek XML - Documento de entidades XML - Document entități XML - файл сущностей XML - Dokument entít XML - Dokument XML določil - Dokument njësish XML - XML-entitetsdokument - документ об’єктів XML - Tài liệu thực thể XML - XML 特征文档 - XML 實體文件 - XML - eXtensible Markup Language - - - - - - - DV video - DV مرئي - Videa DV - Видео — DV - vídeo DV - Video DV - DV-video - DV-Video - βίντεο DV - DV video - DV-video - vídeo DV - DV bideoa - DV-video - DV video - vidéo DV - físeán DV - vídeo DV - וידאו DV - DV video - DV videó - Video DV - Video DV - DV 動画 - DV ვიდეო - DV видеосы - DV 비디오 - DV vaizdo įrašas - DV video - DV-film - DV-video - DV-video - Plik wideo DV - Vídeo DV - Video DV - видео DV - Video DV - Video datoteka DV - Video DV - DV-video - відеокліп DV - Ảnh động DV - DV 视频 - DV 視訊 - DV - Digital Video - - - - - - - ISI video - مرئي ISI - ISI video faylı - Videa ISI - Видео — ISI - vídeo ISI - Video ISI - Fideo ISI - ISI-video - ISI-Video - βίντεο ISI - ISI video - ISI-video - vídeo ISI - ISI bideoa - ISI-video - ISI video - vidéo ISI - físeán ISI - vídeo ISI - וידאו ISI - ISI video - ISI-videó - Video ISI - Video ISI - ISI 動画 - ISI видеосы - ISI 비디오 - ISI vaizdo įrašas - ISI video - Video ISI - ISI-film - ISI-video - ISI video - Plik wideo ISI - vídeoISI - Vídeo ISI - Video ISI - видео ISI - Video ISI - Video datoteka ISI - Video ISI - ISI видео - ISI-video - відеокліп ISI - Ảnh động ISI - ISI 视频 - ISI 視訊 - - - MPEG-2 transport stream - بث نقل MPEG-2 - Поток — транспорт по MPEG-2 - flux de transport MPEG-2 - Přenosový proud MPEG-2 - MPEG-2-transportstrøm - MPEG-2-Transportstrom - ροή μεταφορών MPEG-2 - MPEG-2 transport stream - flujo de transporte MPEG-2 - MPEG-2 -siirtobittivirta - MPEG-2 flutningsstreymur - flux de transport MPEG-2 - Sruth aistrithe MPEG-2 - fluxo de transporte MPEG-2 - העברת זרימה של MPEG-2 - MPEG-2 átviteli adatfolyam - Stream transport MPEG-2 - Stream di trasporto MPEG-2 - MPEG-2 トランスポートストリーム - MPEG-2-ის ტრანსპორტული ნაკადი - MPEG-2 көліктік ағыны - MPEG-2 전송 스트림 - MPEG-2 transportavimo srautas - MPEG-2 transporta straume - MPEG-2 transport stream - Strumień przesyłania MPEG-2 - Fluxo de transporte de MPEG-2 - Flux transport MPEG-2 - транспортный поток MPEG-2 - Pretočni vir prenosega MPEG - MPEG-2 transportström - потік передавання даних MPEG-2 - MPEG-2 传输流 - MPEG-2 傳輸串流 - MPEG-2 TS - Moving Picture Experts Group 2 Transport Stream - - - - - - - - - - - - - - - - MPEG video - MPEG مرئي - Videa MPEG - Видео — MPEG - vídeo MPEG - Video MPEG - MPEG-video - MPEG-Video - βίντεο MPEG - MPEG video - MPEG-video - vídeo MPEG - MPEG bideoa - MPEG-video - MPEG video - vidéo MPEG - físeán MPEG - vídeo MPEG - וידאו MPEG - MPEG video - MPEG-videó - Video MPEG - Video MPEG - MPEG 動画 - MPEG ვიდეო - MPEG видеосы - MPEG 비디오 - MPEG vaizdo įrašas - MPEG video - Video MPEG - MPEG-film - MPEG-video - MPEG-video - Plik wideo MPEG - vídeo MPEG - Vídeo MPEG - Video MPEG - видео MPEG - Video MPEG - Video datoteka MPEG - Video MPEG - MPEG видео - MPEG-video - відеокліп MPEG - Ảnh động MPEG - MPEG 视频 - MPEG 視訊 - MPEG - Moving Picture Experts Group - - - - - - - - - - - - - - - - MPEG video (streamed) - Видео — MPEG, поточно - vídeo MPEG (flux) - Video MPEG (proud) - MPEG-video (streamet) - MPEG-Video (Datenstrom) - βίντεο MPEG (εκπεμπόμενο) - MPEG video (streamed) - Vídeo MPEG (flujo) - MPEG-video (virtaus) - vidéo MPEG (flux) - vídeo MPEG (en stream) - קובץ MPEG (בהזרמה) - MPEG videó (szórt) - Video MPEG (di-stream-kan) - Video MPEG (streamed) - MPEG ビデオ(ストリーム) - MPEG ვიდეო (ნაკადი) - MPEG видео (ағымдық) - MPEG 비디오 (스트리밍) - MPEG video (straumēts) - MPEG video (streamed) - Plik wideo MPEG (strumień) - Vídeo MPEG (fluxo) - видео MPEG (потоковое) - MPEG-video (pretočni) - MPEG-video (strömmad) - відеокліп MPEG (потоковий) - MPEG 视频流媒体 - MPEG 視訊 (串流) - - - - - - - - - - - QuickTime video - QuickTime مرئي - Videa QuickTime - Видео — QuickTime - vídeo QuickTime - Video QuickTime - QuickTime-video - QuickTime-Video - βίντεο QuickTime - QuickTime video - QuickTime-video - vídeo QuickTime - QuickTime bideoa - QuickTime-video - QuickTime video - vidéo QuickTime - físeán QuickTime - vídeo QuickTime - וידאו של QuickTime - QuickTime video - QuickTime videó - Video QuickTime - Video QuickTime - QuickTime 動画 - QuickTime видеосы - 퀵타임 비디오 - QuickTime vaizdo įrašas - QuickTime video - Video QuickTime - Quicktime film - QuickTime-video - QuickTime-video - Plik wideo QuickTime - vídeo QuickTime - Vídeo do QuickTime - Video QuickTime - видео QuickTime - Video QuickTime - Video datoteka QuickTime - Video QuickTime - QuickTime видео - QuickTime-video - відеокліп QuickTime - Ảnh động QuickTime - QuickTime 视频 - QuickTime 視訊 - - - - - - - - - - - - - QuickTime image - صورة QuickTime - Vyjava QuickTime - Изображение — QuickTime - imatge QuickTime - Obrázek QuickTime - QuickTime-billede - QuickTime-Bild - εικόνα QuickTime - QuickTime image - QuickTime-bildo - imagen QuickTime - QuickTime irudia - QuickTime-kuva - QuickTime mynd - image QuickTime - íomhá QuickTime - imaxe QuickTime - תמונה של QuickTime - QuickTime slika - QuickTime kép - Citra QuickTime - Immagine QuickTime - QuickTime 画像 - QuickTime суреті - 퀵타임 그림 - QuickTime paveikslėlis - QuickTime attēls - Quicktime bilde - QuickTime-afbeelding - QuickTime-bilete - Obraz QuickTime - Imagem do QuickTime - Imagine QuickTime - изображение QuickTime - Obrázok QuickTime - Slikovna datoteka QuickTime - Figurë QuickTime - QuickTime-bild - зображення QuickTime - Ảnh QuickTime - QuickTime 图像 - QuickTime 影像 - - - - - - - - Vivo video - Vivo مرئي - Vivo video faylı - Videa Vivo - Видео — Vivo - vídeo Vivo - Video Vivo - Fideo Vivo - Vivo-video - Vivo-Video - βίντεο Vivo - Vivo video - Vivo-video - vídeo Vivo - Vivo bideoa - Vivo-video - Vivo video - vidéo Vivo - físeán Vivo - vídeo Vivo - וידאו של Vivo - Vivo video - Vivo-videó - Video Vivo - Video Vivo - Vivo 動画 - Vivo видеосы - Vivo 비디오 - Vivo vaizdo įrašas - Vivo video - Video Vivo - Vivo-film - Vivo-video - Vivo-film - Plik wideo Vivo - vídeo Vivo - Vídeo Vivo - Video Vivo - видео Vivo - Video Vivo - Video datoteka Vivo - Video Vivo - Vivo видео - Vivo-video - відео Vivo - Ảnh động Vivo - Vivo 视频 - Vivo 視訊 - - - - - - Wavelet video - Wavelet مرئي - Wavelet video faylı - Videa Wavelet - Видео — Wavelet - vídeo Wavelet - Video Wavelet - Fideo Wavelet - Waveletvideo - Wavelet-Video - βίντεο Wavelet - Wavelet video - Wavelet-video - vídeo Wavelet - Wavelet bideoa - Wavelet-video - Wavelet video - vidéo Wavelet - físeán Wavelet - vídeo Wavelet - וידאו של Wavelet - Wavelet video - Wavelet-videó - Video Wavelet - Video Wavelet - Wavelet 動画 - Wavelet видеосы - Wavelet 비디오 - Wavelet vaizdo įrašas - Wavelet video - Video Wavelet - Wavelet-film - Wavelet-video - Wavelet video - Plik wideo Wavelet - vídeo Wavelet - Vídeo Wavelet - Video Wavelet - видео Wavelet - Video Wavelet - Video datoteka Wavelet - Video Wavelet - Wavelet видео - Wavelet-video - відеокліп Wavelet - Ảnh động Wavelet - Wavelet 视频 - Wavelet 視訊 - - - ANIM animation - تحريكة ANIM - ANIM animasiyası - Animacyja ANIM - Анимация — ANIM - animació ANIM - Animace ANIM - Animeiddiad ANIM - ANIM-animation - ANIM-Animation - κινούμενο σχέδιο ANIM - ANIM animation - ANIM-animacio - animación ANIM - ANIM animazioa - ANIM-animaatio - ANIM teknmyndagerð - animation ANIM - beochan ANIM - animación ANIM - הנפשת ANIM - ANIM animacija - ANIM-animáció - Animasi ANIM - Animazione ANIM - ANIM アニメーション - ANIM ანიმაცია - ANIM анимациясы - ANIM 동화상 - ANIM animacija - ANIM animācija - Animasi ANIM - ANIM-animasjon - ANIM-animatie - ANIM-animasjon - Plik animacji ANIM - animação ANIM - Animação ANIM - Animație ANIM - анимация ANIM - Animácia ANIM - Datoteka animacije ANIM - Animim ANIM - ANIM анимација - ANIM-animering - анімація ANIM - Hoạt ảnh ANIM - ANIM 动画 - ANIM 動畫 - - - - FLIC animation - تحريكة FLIC - Animacyja FLIC - Анимация — FLIC - animació FLIC - Animace FLIC - FLIC-animation - FLIC-Animation - κινούμενες εικόνες FLIC - FLIC animation - animación FLIC - FLIC animazioa - FLIC-animaatio - FLIC teknimyndagerð - animation FLIC - beochan FLIC - animación FLIC - הנפשת FLIC - FLIC animacija - FLIC animáció - Animasi FLIC - Animazione FLIC - FLIC アニメーション - FLIC ანიმაცია - FLIC анимациясы - FLIC 동화상 - FLIC animacija - FLIC animācija - FLIC-animasjon - FLIC-animatie - FLIC-animasjon - Plik animacji FLIC - Animação FLIC - Animație FLIC - анимация FLIC - Animácia FLIC - Datoteka animacije FLIC - Animim FLIC - FLIC-animering - FLIC animasyonu - анімація FLIC - Hoạt ảnh FLIC - FLIC 动画 - FLIC 動畫 - - - - - - - - - - - Haansoft Hangul document - مستند Haansoft Hangul - Dakument Haansoft Hangul - Документ — Haansoft Hangul - document Haansoft Hangul - Dokument Haansoft Hangul - Haansoft Hangul-dokument - Haansoft-Hangul-Dokument - έγγραφο Haansoft Hangul - Haansoft Hangul document - documento de Haansoft Hangul - Haansoft Hangul dokumentua - Haansoft Hangul -asiakirja - Haansoft Hangul skjal - document Haansoft Hangul - cáipéis Haansoft Hangul - documento de Haansoft Hangul - מסמך Haansoft Hangul - Haansoft Hangul dokument - Haansoft hangul dokumentum - Dokumen Haansoft Hangul - Documento Haansoft Hangul - Haansoft Hangul ドキュメント - Haansoft Hangul құжаты - 한소프트 한글 문서 - Haansoft Hangul dokumentas - Haansoft Hangul dokuments - Haansoft Hangul-dokument - Haansoft Hangul-document - Haansoft Hangul-dokument - Dokument Haansoft Hangul - Documento do Haansoft Hangul - Document Haansoft Hangul - документ Haansoft Hangul - Dokument Haansoft Hangul - Dokument Haansoft Hangul - Dokument Haansoft Hangul - Haansoft Hangul-dokument - документ Haansoft Hangul - Tài liệu Hangul Haansoft - Haansoft Hangul 文档 - Haansoft 韓文文件 - - - - - - - - - Haansoft Hangul document template - قالب مستند Haansoft Hangul - Šablon dakumentu Haansoft Hangul - Шаблон за документи — Haansoft Hangul - plantilla de document Haansoft Hangul - Šablona dokumentu Haansoft Hangul - Haansoft Hangul-dokumentskabelon - Haansoft-Hangul-Dokumentvorlage - πρότυπο εγγράφου Haansoft Hangul - Haansoft Hangul document template - plantilla de documento de Haansoft Hangul - Haansoft Hangul dokumentuaren txantiloia - Haansoft Hangul -asiakirjamalli - Haansoft Hangul skjalaformur - modèle de document Haansoft Hangul - teimpléad cháipéis Haansoft Hangul - modelo de documento de Haansoft Hangul - תבנית מסמך של Haansoft Hangul - Haansoft Hangul predložak dokumenta - Haansoft hangul dokumentumsablon - Templat dokumen Haansoft Hangul - Modello documento Haansoft Hangul - Haansoft Hangul ドキュメントテンプレート - Haansoft Hangul құжат үлгісі - 한소프트 한글 문서 서식 - Haansoft Hangul dokumento šablonas - Haansoft Hangul dokumentu veidne - Haansoft Hangul-dokumentmal - Haansoft Hangul-documentsjabloon - Haansoft Hangul-dokumentmal - Szablon dokumentu Haansoft Hangul - Modelo de documento do Haansoft Hangul - Document șablon Haansoft Hangul - шаблон документа Haansoft Hangul - Šablóna dokumentu Haansoft Hangul - Predloga dokumenta Haansoft Hangul - Model dokumenti Haansoft Hangul - Haansoft Hangul-dokumentmall - шаблон документа Haansoft Hangul - Mẫu tài liệu Hangul Haansoft - Haansoft Hangul 文档模板 - Haansoft 韓文文件範本 - - - - - - MNG animation - تحريكة MNG - Animacyja MNG - Анимация — MNG - animació MNG - Animace MNG - MNG-animation - MNG-Animation - κινούμενα σχέδια MNG - MNG animation - MNG-animacio - animación MNG - MNG animazioa - MNG-animaatio - MNG teknimyndagerð - animation MNG - beochan MNG - animación MNG - הנפשת MNG - MNG animacija - MNG-animáció - Animasi MNG - Animazione MNG - MNG アニメーション - MNG анимациясы - MNG 동화상 - MNG animacija - MNG animācija - Animasi MNG - MNG-animasjon - MNG-animatie - MNG-animasjon - Animacja MNG - animação MNG - Animação MNG - Animație MNG - анимация MNG - Animácia MNG - Datoteka animacije MNG - Animim MNG - MNG анимација - MNG-animering - анімація MNG - Hoạt ảnh MNG - MNG 动画 - MNG 動畫 - MNG - Multiple-Image Network Graphics - - - - - - - ASF video - ASF مرئي - Videa ASF - Видео — ASF - vídeo ASF - Video ASF - ASF-video - ASF-Video - βίντεο ASF - ASF video - ASF-video - vídeo ASF - ASF bideoa - ASF-video - ASF video - vidéo ASF - físeán ASF - vídeo ASF - וידאו ASF - ASF video - ASF videó - Video ASF - Video ASF - ASF 動画 - ASF ვიდეო - ASF видеосы - ASF 비디오 - ASF vaizdo įrašas - ASF video - ASF-film - ASF-video - ASF-video - Plik wideo ASF - Vídeo ASF - Video ASF - видео ASF - Video ASF - Video datoteka ASF - Video ASF - ASF-video - відеокліп ASF - Ảnh động ASF - ASF 视频 - ASF 視訊 - ASF - Advanced Streaming Format - - - - - - - - - - Windows Media Station file - ملف محطة Windows Media - Fajł Windows Media Station - Файл — Windows Media Station - fitxer Windows Media Station - Soubor Windows Media Station - Windows Media Station-fil - Windows-Media-Streamingbeschreibung - αρχείο Windows Media Station - Windows Media Station file - archivo de emisora de Windows Media - Windows Media Station fitxategia - Windows Media Station-tiedosto - Windows Media Station fíla - fichier Windows Media Station - comhad Windows Media Station - ficheiro de emisora de Windows Media - קובץ תחנה של Windows Media - Windows Media Station fájl - Berkas Windows Media Station - File Windows Media Station - Windows Media Station ファイル - Windows Media Station файлы - Windows 미디어 방송국 파일 - Windows Media Station failas - Windows Media Station datne - Windows Media Station-fil - Windows Media Station-bestand - Windows Media Station-fil - Plik Windows Media Station - Arquivo de estação do Windows Media - Fișier Windows Media Station - файл Windows Media Station - Súbor Windows Media Station - Datoteka Windows Media Station - File Windows Media Station - Windows Media Station-fil - Windows Media Station dosyası - файл Windows Media Station - Tập tin Windows Media Station - Windows 媒体工作站文件 - Windows Media Station 檔 - - - - - - - - - Windows Media video - Windows Media مرئي - Videa Windows Media - Видео — Windows Media - vídeo Windows Media - Video Windows Media - Windows Medie-video - Windows-Media-Video - βίντεο Windows Media - Windows Media video - vídeo de Windows Media - Windows Media bideoa - Windows Media -video - Windows Media video - vidéo Windows Media - físeán Windows Media - vídeo de Windows Media - וידאו של Windows Media - Windows Media video - Windows Media videó - Video Windows Media - Video Windows Media - Windows Media 動画 - Windows Media видеосы - Windows 미디어 오디오 - Windows Media vaizdo įrašas - Windows Media video - Windows Media film - Windows Media-video - Windows Media-video - Plik wideo Windows Media - Vídeo do Windows Media - Video Windows Media - видео Windows Media - Video Windows Media - Video datoteka Windows Media - Video Windows Media - Windows Media-video - відеокліп Windows Media - Ảnh động Windows Media - Windows Media 视频 - Windows Media 視訊 - - - - - AVI video - AVI مرئي - AVI video faylı - Videa AVI - Видео — AVI - vídeo AVI - Video AVI - Fideo AVI - AVI-video - AVI-Video - βίντεο AVI - AVI video - AVI-video - vídeo AVI - AVI bideoa - AVI-video - AVI video - vidéo AVI - físeán AVI - vídeo AVI - וידאו AVI - AVI video - AVI-videó - Video AVI - Video AVI - AVI 動画 - AVI ვიდეო - AVI видеосы - AVI 비디오 - AVI vaizdo įrašas - AVI video - Video AVI - AVI-film - AVI-video - AVI-video - Plik wideo AVI - vídeo AVI - Vídeo AVI - Video AVI - видео AVI - Video AVI - Video datoteka AVI - Video AVI - AVI видео - AVI-video - відеокліп AVI - Ảnh động AVI - AVI 视频 - AVI 視訊 - AVI - Audio Video Interleave - - - - - - - - - - - - - - - - - - - NullSoft video - NullSoft مرئي - Videa NullSoft - Видео — NullSoft - vídeo NullSoft - Video NullSoft - NullSoft-video - NullSoft-Video - βίντεο Nullsoft - NullSoft video - NullSoft-video - vídeo NullSoft - NullSoft bideoa - NullSoft-video - NullSoft video - vidéo NullSoft - físeán NullSoft - vídeo de NullSoft - וידאו של NullSot - NullSoft video - NullSoft videó - Video NullSoft - Video NullSoft - NullSoft 動画 - NullSoft видеосы - 널소프트 비디오 - NullSoft vaizdo įrašas - NullSoft video - Nullsoft-film - NullSoft-video - NullSoft-video - Plik wideo NullSoft - Vídeo do NullSoft - Video NullSoft - видео Nullsoft - Video NullSoft - Video datoteka NullSoft - Video NullSoft - NullSoft-video - відеокліп NullSoft - Ảnh động NullSoft - Nullsoft 视频 - NullSoft 視訊 - - - - - - - SDP multicast stream file - ملف دفق متعدد البث SDP - Šmatadrasny płynievy fajł SDP - Файл за поток — SDP multicast - fitxer de flux de multidifusió SDP - Soubor vícesměrového vysílání proudu SDP - SDP multicast-strømfil - SDP-Multicast-Datenstromdatei - SDP multicast stream file - archivo de flujo multicast SDP - SDP multicast korrontearen fitxategia - SDP-monilähetysvirran tiedosto - SDP margvarpað streymafíla - fichier de flux multidiffusion SDP - comhad shruth ilchraolacháin SDP - ficheiro de fluxo multicast SDP - קובץ שידור בזרימה SDP - SDP multicast műsorfájl - Berkas SDP multicast stream - File stream multicast SDP - SDP マルチキャストストリームファイル - SDP мультикаст ағым файлы - SDP 멀티캐스트 스트림 파일 - SDP daugiaadresio srauto failas - SDP multiraides straumes datne - SDP-multicaststrøm - SDP-multicast-streambestand - SDP multicast straumfil - Plik strumienia multicast SDP - Arquivo de canal multicast SDP - Fișier flux multicast SDP - файл мультикаст-потока SDP - Súbor viacsmerového vysielania prúdu SDP - Pretočni vir večsmernega oddajanja - File stream multicast SDP - SDP multicast stream-fil - файл потокової трансляції SDP - Tập tin luồng truyền một-nhiều SDP - SDP 多播流文件 - SDP multicast 串流檔 - SDP - Session Description Protocol - - - - - - - - - - - - SGI video - SGI مرئي - SGI video faylı - Videa SGI - Видео — SGI - vídeo SGI - Video SGI - Video SGI - SGI-video - SGI-Video - βίντεο SGI - SGI video - SGI-video - vídeo SGI - SGI bideoa - SGI-video - SGI video - vidéo SGI - físeán SGI - vídeo SGI - וידאו SGI - SGI video - SGI-videó - Video SGI - Video SGI - SGI 動画 - SGI видеосы - SGI 비디오 - SGI vaizdo įrašas - SGI video - Video SGI - SGI-film - SGI-video - SGI-video - Plik wideo SGI - vídeo SGI - Vídeo SGI - Video SGI - видео SGI - Video SGI - Video datoteka SGI - Video SGI - SGI видео - SGI-video - відеокліп SGI - Ảnh động SGI - SGI 视频 - SGI 視訊 - - - - - - - eMusic download package - حزمة تنزيل eMusic - pakunak zahruzki eMusic - Пакет за сваляне — eMusic - paquet de descàrrega eMusic - Balíček stahování eMusic - eMusic-hentpakke - eMusic-Download-Paket - πακέτο eMusic - eMusic download package - paquete de descarga eMusic - eMusic deskargaren paketea - eMusic-imurointipaketti - eMusic niðurtøkupakki - paquet de téléchargement eMusic - pacáiste íosluchtú eMusic - paquete de descarga de eMusic - חבילת הורדה של eMusic - eMusic letöltési csomag - paket unduh eMusic - Pacchetto scaricamento eMusic - eMusic ダウンロードパッケージ - eMusic жүктемелер дестесі - eMusic 다운로드 패키지 - eMusic atsiuntimo paketas - eMusic lejupielādes paciņa - eMusic nedlastingspakke - eMusic-downloadpakket - eMusic nedlastingspakke - Pobieralny pakiet eMusic - Pacote de download do eMusic - pachet descărcare eMusic - пакет загрузок eMusic - Balíček sťahovania eMusic - Datoteka paketa eMusic - Paketë shkarkimi eMusic - eMusic-hämtningspaket - пакунок завантаження eMusic - gói nhạc tải xuống eMusic - eMusic 下载包 - eMusic 下載套件 - - - - - - - - KML geographic data - بيانات جغرافية KML - Географски данни — KML - dades geogràfiques KML - Geografická data KML - Geografiske data i KML-format - KML geographische Daten - γεωγραφικά δεδομένα KML - KML geographic data - datos geográficos KML - KML datu geografikoak - KML landafrøðilig dáta - données géographiques KML - sonraí geografacha KML - datos xeográficos KML - מידע גאוגרפי KML - KML geografski podaci - KML földrajzi adatok - Data geografis KML - Dati geografici KML - KML 地理データ - KML географилық ақпараты - KML 지리 정보 데이터 - KML geografiniai duomenys - KML ģeogrāfiskie dati - KML geographic data - Dane geograficzne KML - Dados geográficos KML - Date geografice KML - географические данные KML - Zemepisné údaje KML - Datoteka geografskih podatkov KML - KML geografisk data - географічні дані KML - KML 地理数据 - KML 地理資料 - KML - Keyhole Markup Language - - - - - - KML geographic compressed data - بيانات جغرافية مضغوطة KML - Географски данни — KML, компресирани - dades geogràfiques comprimides KML - Komprimovaná geografická data KML - KML-geografiske komprimerede data - KML geographische komprimierte Daten - γεωγραφικά συμπιεσμένα δεδομένα KML - KML geographic compressed data - datos geográficos comprimidos KML - KML datu geografiko konprimituak - KML landafrøðilig stappað dáta - données géographiques KML compressées - sonraí comhbhrúite geografacha KML - datos xeográficos KML comprimidos - מידע גאוגרפי דחוס KML - KML geografski komprimirani podaci - KML tömörített földrajzi adatok - Data geografis KML terkompresi - Dati geografici KML compressi - KML 地理圧縮データ - KML географиялық сығылған ақпарат - KML 지리 정보 압축 데이터 - KML geografiniai suglaudinti duomenys - KML saspiesti ģeogrāfiskie dati - KML geographic compressed data - Skompresowane dane geograficzne KML - Dados comprimidos geográficos KML - Date geografice comprimate KML - сжатые географические данные KML - Komprimované zemepisné údaje KML - Skrčeni geografski podatki KML - KML geografiskt komprimerat data - стиснуті географічні дані KML - KML 压缩地理数据 - KML 地理壓縮資料 - KML - Keyhole Markup Language - - - - - Citrix ICA settings file - ملف إعدادات Citrix ICA - Fajł naładaŭ Citrix ICA - Настройки — Citrix ICA - fitxer de paràmetres de Citrix ICA - Soubor nastavení Citrix ICA - Citrix ICA-opsætningsfil - Citrix-ICA-Einstellungsdatei - αρχείο ρυθμίσεων Citrix ICA - Citrix ICA settings file - archivo de opciones de Citrix ICA - Citrix ICA ezarpenen fitxategia - Citrix ICA -asetustiedosto - Citrix ICA stillingarfíla - fichier de paramètres ICA Citrix - comhad socruithe Citrix ICA - ficheiro de configuracións de Citrix ICA - קובץ הגדרות של Citrix ICA - Citrix ICA datoteka postavki - Citrix ICA beállításfájl - Berkas penataan Citrix ICA - File impostazioni Citrix ICA - Citrix ICA 設定ファイル - Citrix ICA-ის პარამეტრების ფაილი - Citrix ICA баптаулар файлы - 시트릭스 ICA 설정 파일 - Citrix ICA parametrų failas - Citrix ICA iestatījumu datne - Innstillingsfil for Citrix ICA - Citrix ICA-instellingen - Citrix ICA-innstillingsfil - Plik ustawień Citrix ICA - Arquivo de configurações do Citrix ICA - Fișier de configurări Citrix ICA - файл настроек Citrix ICA - Súbor nastavení Citrix ICA - Nastavitvena datoteka Citrix ICA - File rregullimesh Citrix ICA - Citrix ICA-inställningsfil - файл параметрів ICA Citrix - Tập tin thiết lập ICA Citrix - Citrix ICA 设置文件 - Citrix ICA 設定值檔案 - ICA - Independent Computing Architecture - - - - - - XUL interface document - مستند واجهة XUL - Interfejsny dakument XUL - Документ — интерфейс за XUL - document d'interfície XUL - Dokument rozhraní XUL - XUL-grænsefladedokument - XUL-Oberflächendokument - έγγραφο διεπαφής XUL - XUL interface document - documento de interfaz XUL - XUL interfazearen dokumentua - XUL-käyttöliittymäasiakirja - XUL markamótsskjal - document d'interface XUL - cáipéis chomhéadan XUL - documento de interface XUL - מסמך ממשק XUL - XUL-felületdokumentum - Dokumen antarmuka XUL - Documento interfaccia XUL - XUL インターフェイスドキュメント - XUL интерфейс құжаты - XUL 인터페이스 문서 - XUL sąsajos dokumentas - XUL saskarnes dokuments - XUL-grensesnittdokument - XUL-interface-document - XUL-grensesnitt-dokument - Dokument interfejsu XUL - Documento de interface XUL - Document interfață XUL - документ интерфейса XUL - Dokument rozhrania XUL - Dokument vmesnika XUL - Dokument interfaqe XUL - XUL-gränssnittsdokument - XUL arayüz belgesi - документ інтерфейсу XUL - Tài liệu giao diện XUL - XUL 界面文档 - XUL 介面文件 - XUL - XML User interface markup Language - - - - - - - XPInstall installer module - وحدة مثبت XPInstall - Пакет — инсталация XPInstall - mòdul instal·lador d'XPinstall - Modul instalátoru XPInstall - XPInstall-installationsmodul - XPInstall-Installermodul - XPInstall installer module - módulo del instalador XPInstall - XPInstall instalatzailearen modulua - XPInstall-asennuspaketti - XPInstall innleggjaramótul - module d'installation XPInstall - modúl suiteála XPInstall - Módulo do instalador XPInstall - מודול התקנה של XPInstall - XPInstall telepítőmodul - Modul installer XPInstall - Modulo installatore XPInstall - XPInstall インストーラモジュール - XPInstall орнату модулі - XPInstall 설치 프로그램 모듈 - XPInstall įdiegiklio modulis - XPInstall instalatora modulis - XPInstall installeer module - Moduł instalatora XPInstall - Módulo de instalador XPInstall - Modul de instalare XPInstall - модуль установщика XPInstall - Modul inštalátora XPInstall - modul namestilnika XPInstall - XPInstall-installeringsmodul - модуль засобу встановлення XPInstall - XPInstall 安装工具模块 - XPInstall 安裝程式模組 - - - - - Word 2007 document - مستند Word 2007 - Документ — Word 2007 - document de Word 2007 - Dokument Word 2007 - Word 2007-dokument - Word-2007-Dokument - έγγραφο Word 2007 - Word 2007 document - documento de Word 2007 - Word 2007 dokumentua - Word 2007 -asiakirja - Word 2007 skjal - document Word 2007 - cáipéis Word 2007 - documento de Word 2007 - מסמך Word 2007 - Word 2007 dokument - Word 2007 dokumentum - Dokumen Word 2007 - Documento Word 2007 - Word 2007 ドキュメント - Word 2007 құжаты - 워드 2007 문서 - Word 2007 dokumentas - Word 2007 dokuments - Word 2007-document - Dokument Word 2007 - Documento do Word 2007 - Document Word 2007 - документ Word 2007 - Dokument Word 2007 - Dokument Word 2007 - Word 2007-dokument - документ Word 2007 - Tài liệu Word 2007 - Microsoft Word 2007 文档 - Word 2007 文件 - - - - - - Word 2007 document template - Шаблон за документи — Word 2007 - plantilla de document de Word 2007 - Šablona dokumentu Word 2007 - Word 2007-dokumentskabelon - Word 2007-Dokumentvorlage - πρότυπο έγγραφο Word 2007 - Word 2007 document template - Plantilla de documento de Word 2007 - Word 2007 -asiakirjamalli - modèle de document Word 2007 - Plantilla de documento de Word 2007 - תבנית מסמך של Word 2007 - Word 2007 predložak dokumenta - Word 2007 dokumentumsablon - Templat dokumen Word 2007 - Modello documento Word 2007 - Word 2007 文書テンプレート - Word 2007-ის დოკუმენტის შაბლონი - Word 2007 құжатының үлгісі - 워드 2007 문서 서식 - Word 2007 dokumenta veidne - Word 2007 document sjabloon - Szablon dokumentu Word 2007 - Modelo de documento do Word 2007 - шаблон документа Word 2007 - Predloga dokumenta Word 2007 - Word 2007-dokumentmall - шаблон документа Word 2007 - Word 2007 文档模板 - Word 2007 文件範本 - - - - - - PowerPoint 2007 presentation - عرض تقديمي PowerPoint 2007 - Презентация — PowerPoint 2007 - presentació de PowerPoint 2007 - Prezentace PowerPoint 2007 - PowerPoint 2007-præsentation - PowerPoint-2007-Präsentation - παρουσίαση PowerPoint 2007 - PowerPoint 2007 presentation - presentación de PowerPoint 2007 - PowerPoint 2007 aurkezpena - PowerPoint 2007 -esitys - PowerPoint 2007 framløga - présentation PowerPoint 2007 - láithreoireacht PowerPoint 2007 - presentación de PowerPoint 2007 - מצגת של PowerPoint 2007 - PowerPoint 2007 prezentacija - PowerPoint 2007 prezentáció - Presentasi PowerPoint 2007 - Presentazione standard PowerPoint 2007 - PowerPoint 2007 プレゼンテーション - PowerPoint 2007 презентациясы - 파워포인트 2007 프리젠테이션 - PowerPoint 2007 pateiktis - PowerPoint 2007 prezentācija - PowerPoint 2007-presentatie - Prezentacja PowerPoint 2007 - Apresentação do PowerPoint 2007 - Prezentare PowerPoint 2007 - презентация PowerPoint 2007 - Prezentácia PowerPoint 2007 - Predstavitev Microsoft PowerPoint 2007 - PowerPoint 2007-presentation - презентація PowerPoint 2007 - Trình diễn PowerPoint 2007 - Microsoft PowerPoint 2007 演示文稿 - PowerPoint 2007 簡報 - - - - - - PowerPoint 2007 slide - Кадър — PoerPoint 2007 - dispositiva de PowerPoint 2007 - Snímek PowerPoint 2007 - PowerPoint 2007-slide - PowerPoint 2007-Folie - σλάιντ PowerPoint 2007 - PowerPoint 2007 slide - Diapositiva de PowerPoint 2007 - diapositive PowerPoint 2007 - Diaporama de PowerPoint 2007 - שקופית של PowerPoint 2007 - PowerPoint 2007 slajd - PowerPoint 2007 dia - Slide PowerPoint 2007 - Diapositiva PowerPoint 2007 - PowerPoint 2007 スライド - PowerPoint 2007-ის სლაიდი - PowerPoint 2007 слайды - 파워포인트 2007 슬라이드 - PowerPoint 2007 slaids - PowerPoint 2007 dia - Slajd PowerPoint 2007 - Slide do PowerPoint 2007 - слайд PowerPoint 2007 - Prosojnica PowerPoint 2007 - слайд PowerPoint 2007 - PowerPoint 2007 文稿 - PowerPoint 2007 投影片 - - - - - - PowerPoint 2007 show - عرض PowerPoint 2007 - Презентация-шоу — PowerPoint 2007 - exposició de PowerPoint 2007 - Prezentace PowerPoint 2007 - PowerPoint 2007-dias - PowerPoint-2007-Präsentation - σόου PowerPoint 2007 - PowerPoint 2007 show - exposición de PowerPoint 2007 - PowerPoint 2007 ikuskizuna - PowerPoint 2007 -diaesitys - PowerPoint 2007 framsýning - diaporama PowerPoint 2007 - taispeántas PowerPoint 2007 - Exposición de PowerPoint 2007 - תצוגה של PowerPoint 2007 - PowerPoint 2007 prezentacija - PowerPoint 2007 bemutató - Presentasi PowerPoint 2007 - Solo presentazione PowerPoint 2007 - PowerPoint 2007 プレゼンテーション - PowerPoint 2007 көрсетілімі - 파워포인트 2007 쇼 - PowerPoint 2007 pateiktis - PowerPoint 2007 slīdrāde - PowerPoint 2007 show - Pokaz PowerPoint 2007 - Apresentação do PowerPoint 2007 - Prezentare PowerPoint 2007 - презентация PowerPoint 2007 - Ukážka PowerPoint 2007 - Zagonska predstavitev PowerPoint 2007 - PowerPoint 2007-visning - показ слайдів PowerPoint 2007 - Microsoft PowerPoint 2007 演示文稿 - PowerPoint 2007 展示 - - - - - - PowerPoint 2007 presentation template - Шаблон за презентации — PowerPoint 2007 - plantilla de presentació de PowerPoint 2007 - Šablona prezentace PowerPoint 2007 - PowerPoint 2007-præsentationsskabelon - PowerPoint 2007-Präsentationsvorlage - πρότυπο παρουσίασης PowerPoint 2007 - PowerPoint 2007 presentation template - Plantilla de presentación de PowerPoint 2007 - PowerPoint 2007 -esitysmalli - modèle de présentation PowerPoint 2007 - modelo de presentación de PowerPoint 2007 - תבנית למצגת של PowerPoint 2007 - PowerPoint 2007 predložak prezentacije - PowerPoint 2007 bemutatósablon - Templat presentasi PowerPoint 2007 - Modello presentazione PowerPoint 2007 - PowerPoint 2007 プレゼンテーションテンプレート - PowerPoint 2007-ის პრეზენტაციის შაბლონი - PowerPoint 2007 презентация шаблоны - 파워포인트 2007 프리젠테이션 서식 - PowerPoint 2007 prezentācijas veidne - PowerPoint 2007 presentation sjabloon - Szablon prezentacji PowerPoint 2007 - Modelo de apresentação do PowerPoint 2007 - шаблон презентации PowerPoint 2007 - Predloga predstavitve PowerPoint 2007 - PowerPoint 2007-presentationsmall - шаблон презентації PowerPoint 2007 - PowerPoint 2007 演示文稿模板 - PowerPoint 2007 簡報範本 - - - - - - Excel 2007 spreadsheet - جدول Excel 2007 - Таблица — Excel 2007 - full de càlcul d'Excel 2007 - Sešit Excel 2007 - Excel 2007-regneark - Excel-2007-Tabelle - φύλλο εργασίας Excel 2007 - Excel 2007 spreadsheet - hoja de cálculo de Excel 2007 - Excel 2007 kalkulu-orria - Excel 2007 -taulukko - Excel 2007 rokniark - feuille de calcul Excel 2007 - scarbhileog Excel 2007 - folla de cálculo de Excel 2007 - גליון נתונים של אקסל 2007 - Excel 2007 proračunska tablica - Excel 2007 táblázat - Lembar sebar Excel 2007 - Foglio di calcolo Excel 2007 - Excel 2007 スプレッドシート - Excel 2007-ის ცხრილი - Excel 2007 электрондық кестесі - 엑셀 2007 스프레드시트 - Excel 2007 skaičialentė - Excel 2007 izklājlapa - Excel 2007-rekenblad - Arkusz Excel 2007 - Planilha do Excel 2007 - Foaie de calcul Excel 2007 - электронная таблица Excel 2007 - Zošit Excel 2007 - Razpredelnica Microsoft Excel 2007 - Excel 2007-kalkylblad - ел. таблиця Excel 2007 - Bảng tính Excel 2007 - Microsoft Excel 2007 工作簿 - Excel 2007 試算表 - - - - - - Excel 2007 spreadsheet template - Шаблон за таблици — Excel 2007 - plantilla de full de càlcul d'Excel 2007 - Šablona sešitu Excel 2007 - Excel 2007-regnearksskabelon - Excel 2007-Datenblattvorlage - πρότυπο φύλλου εργασίας Excel 2007 - Excel 2007 spreadsheet template - Plantilla de hoja de cálculo Excel 2007 - Excel 2007 -taulukkomalli - modèle de feuille de calcul Excel 2007 - modelo de folla de cálculo Excel 2007 - תבנית של גיליון נתונים של Excel 2007 - Excel 2007 predložak proračunske tablice - Excel 2007 táblázatsablon - Templat lembar kerja Excel 2007 - Modello foglio di calcolo Excel 2007 - Excel 2007 スプレッドシートテンプレート - Excel 2007-ის ცხრილის შაბლონი - Excel 2007 кесте шаблоны - 엑셀 2007 스프레드쉬트 - Excel 2007 izklājlapas veidne - Excel 2007 spreadsheet sjabloon - Szablon arkusza Excel 2007 - Modelo de planilha do Excel 2007 - шаблон электронной таблицы Excel 2007 - Predloga razpredelnice Excel 2007 - Excel 2007-kalkylarksmall - шаблон електронної таблиці Excel 2007 - Excel 2007 工作表模板 - Excel 2007 試算表範本 - - - - - - T602 document - مستند T602 - Dakument T602 - Документ — T602 - document T602 - Dokument T602 - T602-dokument - T602-Dokument - αρχείο T602 - T602 document - T602-dokumento - documento T602 - T602 dokumentua - T602-asiakirja - T602 skjal - document T602 - cáipéis T602 - documento T602 - מסמך T602 - T602 dokument - T602 dokumentum - Dokumen T602 - Documento T602 - T602 ドキュメント - T602 құжаты - T602 문서 - T602 dokumentas - T602 dokuments - T602-dokument - T602-document - T602-dokument - Dokument T602 - Documento T602 - Document T602 - документ T602 - Dokument T602 - Dokument T602 - Dokument T602 - T602-dokument - документ T602 - Tài liệu T602 - T602 文档 - T602 文件 - - - - - - - - - - Cisco VPN Settings - إعدادات Cisco VPN - Nałady Cisco VPN - Настройки — ВЧМ на Cisco - paràmetres VPN de Cisco - Nastavení Cisco VPN - Cisco VPN-opsætning - Cisco-VPN-Einstellungen - ρυθμίσεις Cisco VPN - Cisco VPN Settings - configuración VPN de Cisco - Cisco VPN ezarpenak - Cisco VPN -asetukset - Cisco VPN stillingar - paramètres VPN Cisco - socruithe VPN Cisco - configuracións de VPN de Cisco - הגדרות של Cisco VPN - Cisco VPN postavke - Cisco VPN beállítások - Penataan Cisco VPN - Impostazioni VPN Cisco - Cisco VPN 設定 - Cisco VPN-ის პარამეტრები - Cisco VPN баптаулары - Cisco VPN 설정 - Cisco VPN parametrai - Cisco VPN iestatījumi - Cisco VPN-innstillinger - Cisco VPN-instellingen - Cisco VPN-innstillingar - Ustawienia VPN Cisco - Configurações de VPN da Cisco - Configurări VPN Cisco - файл настроек Cisco VPN - Nastavenia Cisco VPN - Datoteka nastavitev Cisco VPN - Rregullime VPN Cisco - Cisco VPN-inställningar - параметри VPN Cisco - Thiết lập VPN Cisco - Cisco VPN 设置 - Cisco VPN 設定值 - - - - - - - - - - ICC profile - تشكيلة OCL - Цветови профил — OCL - perfil ICC - Profil ICC - ICC-profil - ICC-Profil - προφίλ ICC - ICC profile - ICC-profilo - perfil ICC - ICC profila - ICC-profiili - ICC umhvarv - profil ICC - próifíl ICC - perfíl ICC - פרופיל ICC - ICC profil - ICC profil - Profil ICC - Profilo ICC - ICC プロファイル - ICC профайлы - ICC 프로필 - ICC profilis - ICC profils - ICC profiel - Profil ICC - Perfil ICC - Profil ICC - профиль ICC - Profil farieb ICC - Datoteka profila ICC - ICC-profil - профіль ICC - ICC 文件 - ICC 設定檔 - - - - - - - - IT 8.7 color calibration file - ملف ضبط ألوان IT 8.7 - Файл за цветово калибриране — IT 8.7 - fitxer de calibratge de color IT 8.7 - Soubor kalibrace barev IT 8.7 - IT 8.7 farvekalibreringsfil - IT 8.7 Farbkalibrierungsdatei - αρχείο ρύθμισης χρώματος ΙΤ 8.7 - IT 8.7 color calibration file - archivo de calibración de color IT 8.7 - IT 8.7 kolore-kalibrazioaren fitxategia - IT 8.7 -värikalibrointitiedosto - IT 8.7 litstillingarfíla - fichier de calibration couleur IT 8.7 - comhad calabraithe dathanna IT 8.7 - ficheiro de calibración de cor IT 8.7 - קובץ כיול צבע IT 8.7 - IT 8.7 datoteka kalibracije boja - IT 8.7 színkalibrációs fájl - Berkas kalibrasi warna IT 8.7 - File calibrazione colore IT 8.7 - IT 8.7 カラーキャリブレーションファイル - IT 8.7 түс баптау файлы - IT 8.7 색 조율 파일 - IT 8.7 spalvų kalibravimo failas - IT 8.7 krāsu kalibrācijas datne - IT 8.7 kleurcalibratie bestand - Plik kalibracji kolorów IT 8.7 - Arquivo de calibração de cor IT 8.7 - Fișier de calibrare a culorii IT 8.7 - файл калибровки цвета IT 8.7 - Umeritvena datoteka barve IT 8.7 - IT 8.7-färgkalibreringsfil - файл калібрування кольорів IT 8.7 - IT 8.7 色彩校准文件 - IT 8.7 色彩校正檔 - - - - - - - - - CCMX color correction file - - - - - - - - - WinHelp help file - - - - - - - - - - - digital photos - الصور الرقمية - ličbavyja zdymki - Цифрови фотографии - fotos digitals - Digitální fotografie - digitale billeder - Digitale Fotos - ψηφιακές φωτογραφίες - digital photos - fotos digitales - argazki digitalak - digivalokuvia - talgildar myndir - photos numériques - grianghraif dhigiteacha - fotos dixitais - תמונות דיגיטליות - digitalne fotografije - digitális fényképek - foto digital - Foto digitali - デジタルフォト - сандық фотосуреттер - 디지털 사진 - skaitmeninės nuotraukos - digitāla fotogrāfija - digitale foto's - digitale fotografi - Zdjęcia cyfrowe - Fotos digitais - fotografii digitale - цифровые фотографии - Digitálne fotografie - digitalne fotografije - Fotografi dixhitale - digitalbilder - цифрові фотографії - ảnh chụp số - 数字化图像 - 數位相片 - - - - - - - - Video CD - Video CD - Videa CD - CD — видео - Video CD - Video CD - Video-cd - Video-CD - Video CD - Video CD - Video-KD - Video CD - Bideo CDa - Video CD - Video CD - CD vidéo - Video CD - Video CD - תקליטור וידאו - Video CD - Video CD - Video CD - Video CD - ビデオ CD - видео CD - 비디오 CD - Vaizdo CD - Video CD - video-CD - Video-CD - Video CD - CD de vídeo - CD video - видеодиск VCD - Video CD - Video CD - CD Video - Video-cd - Video CD - Đĩa CD ảnh động - VCD - Video CD - - - - - - - - Super Video CD - Super Video CD - Super Video CD - CD — супер видео - Super Video CD - Super Video CD - Super Video-cd - Super-Video-CD - Super Video CD - Super Video CD - Super-Video-KD - Super Video CD - Super Bideo CDa - Super Video CD - Super Video CD - Super VCD - Super Video CD - Super vídeo CD - Super Video CD - Super Video CD - Super Video CD - Super Video CD - Super Video CD - スーパービデオ CD - Super Video CD - 수퍼 비디오 CD - Super vaizdo CD - Super Video CD - super-video-CD - Super Video-CD - Super Video CD - CD de Super Vídeo (SVCD) - Super Video CD - компакт-диск Super Video - Super Video CD - Super Video CD - CD Super Video - Super Video CD - Super Video CD - Đĩa CD siêu ảnh động - SVCD - Super Video CD - - - - - - - - video DVD - DVD مرئي - videa DVD - DVD — видео - vídeo DVD - DVD-Video - video-dvd - Video-DVD - βίντεο DVD - video DVD - video-DVD - DVD de vídeo - bideo DVDa - video-DVD - video DVD - DVD vidéo - DVD físe - DVD de vídeo - DVD וידאו - video DVD - video DVD - DVD video - DVD video - ビデオ DVD - ვიდეო DVD - видео DVD - 비디오 CD - vaizdo DVD - video DVD - video-DVD - Video-DVD - DVD-Video - DVD de vídeo - DVD video - видео-DVD - DVD-Video - video DVD - DVD video - video-dvd - відео-DVD - đĩa DVD ảnh động - 视频 DVD - 視訊 DVD - - - - - - - - - - - audio CD - CD سمعي - aŭdyjo CD - CD — аудио - CD d'àudio - Zvukové CD - lyd-cd - Audio-CD - CD ήχου - audio CD - Son-KD - CD de sonido - Audio CDa - ääni-CD - audio CD - CD audio - dlúthdhiosca fuaime - CD de son - תקליטור שמע - hang CD - CD audio - CD audio - オーディオ CD - аудио CD - 오디오 CD - garso CD - audio CD - audio-CD - lyd-CD - CD-Audio - CD de áudio - CD audio - звуковой CD - Zvukové CD - zvočni CD - CD audio - ljud-cd - Müzik CD'si - звуковий CD - đĩa CD âm thanh - 音频 CD - 音訊 CD - - - - - blank CD disc - قرص CD فارغ - čysty dysk CD - CD — празно - disc CD en blanc - Prázdný disk CD - tom cd-disk - Leere CD - κενό CD - blank CD disc - disco CD virgen - CD disko hutsa - tyhjä CD-levy - blonk fløga - CD vierge - dlúthdhiosca folamh - disco de CD en brancho - תקליטור ריק - üres CD-lemez - cakram CD kosong - Disco vuoto CD - ブランク CD ディスク - таза CD дискі - 빈 CD 디스크 - tuščias CD diskas - tukšs CD disks - blanco CD - tom CD-plate - Pusta płyta CD - Disco CD vazio - disc gol CD - чистый компакт-диск - Prázdny disk CD - prazen CD disk - Disk bosh CD - tom cd-skiva - boş CD diski - порожній компакт-диск - đĩa CD trống - 空 CD 光盘 - 空白 CD 光碟 - - - - - blank DVD disc - قرص DVD فارغ - čysty dysk DVD - DVD — празно - disc DVD en blanc - Prázdný disk DVD - tom dvd-disk - Leere DVD - κενό DVD - blank DVD disc - disco DVD virgen - DVD disko hutsa - tyhjä DVD-levy - blonk margfløga - DVD vierge - DVD folamh - disco de DVD en branco - תקליטור DVD ריק - üres DVD-lemez - cakram DVD kosong - Disco vuoto DVD - ブランク DVD ディスク - таза DVD дискі - 빈 DVD 디스크 - tuščias DVD diskas - tukšs DVD disks - blanco DVD - tom DVD-plate - Pusta płyta DVD - Disco DVD vazio - disc gol DVD - чистый диск DVD - Prázdny disk DVD - prazen DVD disk - Disk bosh DVD - tom dvd-skiva - boş DVD diski - порожній диск DVD - đĩa DVD trống - 空 DVD 光盘 - 空白 DVD 光碟 - - - - - blank Blu-ray disc - قرص بلو-راي فارغ - čysty dysk Blu-ray - Blu-ray — празно - disc Blu-Ray en blanc - Prázdný disk Blu-ray - tom Blu-ray-disk - Leeres Blu-Ray-Medium - κενό Blu-ray - blank Blu-ray disc - disco Blu-ray virgen - Blu-ray disko hutsa - tyhjä Blu-ray-levy - blankur Blu-ray diskur - disque Blu-Ray vierge - diosca folamh Blu-Ray - disco Blu-ray en branco - תקליטור בלו־ריי ריק - üres Blu-Ray lemez - cakram Blu-ray kosong - Disco vuoto Blu-ray - ブランク Blu-ray ディスク - таза Blu-ray дискі - 빈 블루레이 디스크 - tuščias Blu-ray diskas - tukšs Blu-ray disks - blanco Blu-ray-disk - tom Blu-Ray-plate - Pusta płyta Blu-ray - Disco Blu-ray vazio - disc gol Blu-ray - чистый диск Blu-ray - Prázdny disk Blu-ray - prazen Blu-Ray disk - Disk bosh Blu-ray - tom Blu-ray-skiva - boş Blue-ray diski - порожній диск Blu-ray - đĩa Blu-ray trống - 空蓝光 DVD - 空白 Blu-ray 光碟 - - - - - blank HD DVD disc - قرص HD DVD فارغ - čysty dysk HD DVD - HD DVD — празно - disc DVD HD en blanc - Prázdný disk HD DVD - tom HD dvd-disk - Leere HD-DVD - κενό HD DVD - blank HD DVD disc - disco HD DVD virgen - HD DVD disko hutsa - tyhjä HD DVD -levy - blankur HD DVD diskur - disque HD-DVD vierge - HD DVD folamh - disco de HD DVD en branco - דיסק HD DVD ריק - üres HD DVD-lemez - cakram HD DVD kosong - Disco vuoto DVD HD - ブランク HD DVD ディスク - таза HD DVD дискі - 빈 HD DVD 디스크 - tuščias HD DVD diskas - tukšs HD DVD disks - blanco HD-DVD - tom HD-DVD-plate - Pusta płyta HD DVD - Disco DVD HD vazio - disc gol HD DVD - чистый диск HD DVD - Prázdny disk HD DVD - prazen HD DVD disk - Disk bosh DVD HD - tom HD DVD-skiva - boş HD DVD diski - порожній диск HD DVD - đĩa DVD HD trống - 空 HD DVD 光盘 - 空白 HD DVD 光碟 - - - - - audio DVD - DVD سمعي - aŭdyjo DVD - DVD — аудио - DVD d'àudio - Zvukové DVD - lyd-dvd - Audio-DVD - DVD ήχου - audio DVD - Son-DVD - DVD de sonido - audio DVDa - ääni-DVD - Ljóð DVD - DVD audio - DVD fuaime - DVD de son - DVD שמע - hang DVD - DVD audio - DVD audio - オーディオ DVD - аудио DVD - 오디오 DVD - garso DVD - audio DVD - audio-DVD - lyd-DVD - DVD-Audio - DVD de áudio - DVD audio - звуковой DVD - Zvukové DVD - zvočni DVD - DVD audio - ljud-dvd - Müzik DVD'si - звуковий DVD - đĩa DVD âm thanh - 音频 DVD - 音訊 DVD - - - - - - - - - Blu-ray video disc - قرص بلو-راي مرئي - Videadysk Blu-ray - Blu-ray — видео - disc de vídeo Blu-Ray - Videodisk Blu-ray - Blu-ray video-disk - Blu-ray-Videoscheibe - δίσκος βίντεο Blu-ray - Blu-ray video disc - disco de vídeo Blu-ray - Blu-ray bideo-diskoa - Blu-ray-videolevy - Blu-ray diskur - disque vidéo Blu-Ray - diosca físe Blu-Ray - disco de vídeo Blu-ray - תקליטור וידאו מסוג בלו־ריי - Blu-ray video disk - Blu-ray videolemez - Cakram video Blu-ray - Disco video Blu-ray - Blu-ray ビデオディスク - Blu-ray ვიდეო დისკი - Blu-ray видео дискі - 블루레이 비디오 디스크 - Blu-ray vaizdo diskas - Blu-ray video disks - Blu-ray-videodisk - Blu-Ray videoplate - Płyta wideo Blu-ray - Disco de vídeo Blu-ray - Disc video Blu-ray - видеодиск Blu-ray - Videodisk Blu-ray - Blu-ray video disk - Disk video Blu-ray - Blu-ray-videoskiva - відеодиск Blu-ray - Đĩa ảnh động Blu-ray - 蓝光视频光盘 - Blu-ray 視訊光碟 - - - - - - - - - HD DVD video disc - قرص HD DVD مرئي - Videadysk HD DVD - HD DVD — видео - disc de vídeo DVD HD - Videodisk HD DVD - HD DVD-videodisk - HD-DVD-Videoscheibe - δίσκος βίντεο HD DVD - HD DVD video disc - disco de vídeo HD DVD - HD DVD bideo-diskoa - HD DVD -videolevy - HD DVD video diskur - disque vidéo HD DVD - diosca físe HD DVD - disco de vídeo HD DVD - תקליטור וידאו HD DVD - HD DVD video disk - HD DVD videolemez - Cakram video HD DVD - Disco video DVD HD - HD DVD ビデオディスク - HD DVD видео дискі - HD DVD 비디오 디스크 - HD DVD vaizdo diskas - HD DVD video disks - HD-DVD-videodisk - HD-DVD-videodisk - Płyta wideo HD DVD - Disco de vídeo HD DVD - Disc video HD DVD - видеодиск HD DVD - Videodisk HD DVD - HD DVD video disk - Disk video DVD HD - HD DVD-videoskiva - відеодиск HD DVD - Đĩa ảnh động DVD HD - HD DVD 视频光盘 - HD DVD 視訊光碟 - - - - - - - - - - e-book reader - Четец на е-книги - lector de llibres electrònics - Čtečka elektronických knih - e-bogslæser - E-Book-Leser - αναγνώστης ηλεκτρονικών βιβλίων - e-book reader - lector de libros electrónicos - e-kirjan lukulaite - lecteur de livre numérique - lector de libros electrónicos - קורא ספרים אלקטרוניים - čitač e-knjiga - e-könyvolvasó - Pembaca e-book - Lettore e-book - 電子書籍リーダー - электронды кітаптарды оқу құрылғысы - 전자책 리더 - e-grāmatu lasītājs - e-book reader - Czytnik e-booków - Leitor de e-book - устройство для чтения электронных книг - Bralnik elektronskih knjig - e-book-läsare - e-kitap okuyucu - пристрій для читання електронних книг - 电子书阅读器 - e-book 閱讀器 - - - - - - - - Picture CD - Picture CD - Picture CD - CD — изображения - Picture CD - Picture CD - Billedcd - Bild-CD - CD εικόνων - Picture CD - Picture CD - Picture CD - Picture CD - Picture CD - CD Picture - Picture CD - Picture CD - תקליטור תמונות - Picture CD - CD Gambar - Picture CD - ピクチャー CD - Picture CD - Picture CD - Paveikslėlių CD - Attēlu CD - foto-CD - Bilete-CD - Picture CD - CD de Fotos - CD cu fotografii - Picture CD - Picture CD - Slikovni CD - Picture CD - Picture CD - Resim CD'si - CD з зображеннями - Đĩa CD ảnh - 柯达 Picture CD - 圖片 CD - - - - - - - - portable audio player - مشغل الملفات المسموعة المحمولة - pieranosny aŭdyjoplayer - Преносим аудио плеър - reproductor d'àudio portàtil - Přenosný zvukový přehrávač - bærbar lydafspiller - Portables Audio-Wiedergabegerät - φορητός αναπαραγωγέας μουσικής - portable audio player - dispositivo de sonido portable - audio erreproduzigailu eramangarria - siirrettävä äänisoitin - leysur ljóðavspælari - lecteur audio portable - seinnteoir iniompartha fuaime - dispositivo de son portábel - נגן מוזיקה נייד - prenosivi audio svirač - hordozható zenelejátszó - pemutar audio portable - Lettore audio portabile - ポータブルオーディオプレイヤー - тасымалы аудио плеер - 휴대용 오디오 플레이어 - nešiojamasis garso leistuvas - portatīvais audio atskaņotājs - draagbare audiospeler - portable audio layer - Przenośny odtwarzacz dźwięku - Reprodutor de áudio portátil - player audio portabil - портативный аудиопроигрыватель - Prenosný hudobný prehrávač - prenosni predvajalnik zvoka - Lexues audio portativ - bärbar ljudspelare - портативний аудіопрогравач - bộ phát nhạc di động - 便携式音频播放器 - 可攜式音訊播放程式 - - - - - software - برنامج - prahrama - Софтуер - programari - Software - software - Software - λογισμικό - software - software - softwarea - ohjelmisto - ritbúnaður - logiciel - bogearraí - software - תכנה - softver - szoftver - peranti lunak - Software - ソフトウェア - პროგრამული უზრუნველყოფა - бағдарламалық қамтама - 소프트웨어 - programinė įranga - programmatūra - software - programvare - Oprogramowanie - Aplicativo - software - программное обеспечение - Softvér - programska oprema - Software - programvara - програмне забезпечення - phần mềm - 软件 - 軟體 - - - - - UNIX software - برنامج يونكس - Софтуер за UNIX - programari UNIX - Software UNIX - UNIX-programmer - UNIX Software - λογισμικό UNIX - UNIX software - software de UNIX - UNIXeko softwarea - UNIX-ohjelmisto - UNIX ritbúnaður - logiciel UNIX - bogearraí UNIX - Software de UNIX - תוכנת UNIX - UNIX softver - UNIX-szoftver - Peranti lunak UNIX - Software UNIX - UNIX ソフトウェア - UNIX бағдарламасы - UNIX 소프트웨어 - UNIX programinė įranga - UNIX programmatūra - UNIX software - Oprogramowanie systemu UNIX - Software UNIX - Software UNIX - программа UNIX - Softvér UNIX - Programska datoteka UNIX - UNIX-programvara - UNIX yazılımı - програмне забезпечення UNIX - UNIX 软件 - UNIX 軟體 - - - - - - - - - - - Windows software - برنامج ويندوز - Софтуер — Windows - programari de Windows - Software Windows - Windowsprogram - Windows-Software - λογισμικό Windows - Windows software - software de Windows - Windows-eko softwarea - Windows-ohjelmisto - Windows ritbúnaður - logiciel Windows - bogearraí Windows - Software de Windows - תוכנה לWindows - Windows softver - Windows-szoftver - Piranti lunak Windows - Software Windows - Windows ソフトウェア - Windows бағдарламасы - Windows 소프트웨어 - Windows programinė įranga - Windows programmatūra - Windows software - Oprogramowanie systemu Windows - Programa do Windows - Software Windows - программа Windows - Softvér Windows - Programska oprema za okolje Windows - Windows-program - програмне забезпечення Windows - Windows 软件 - Windows 軟體 - - - - - - - - - - TriG RDF document - TriG - TriG RDF Graph Triple Language - - - - - \ No newline at end of file diff --git a/Telegram/Resources/qrc/telegram.qrc b/Telegram/Resources/qrc/telegram.qrc index e9ae81043..96d7a0828 100644 --- a/Telegram/Resources/qrc/telegram.qrc +++ b/Telegram/Resources/qrc/telegram.qrc @@ -18,9 +18,6 @@ ../sounds/call_connect.mp3 ../sounds/call_end.mp3 - - qmime/freedesktop.org.xml - ../langs/lang_it.strings ../langs/lang_es.strings diff --git a/Telegram/Resources/qrc/telegram_linux.qrc b/Telegram/Resources/qrc/telegram_linux.qrc deleted file mode 100644 index 0554fa179..000000000 --- a/Telegram/Resources/qrc/telegram_linux.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - ../etc/qt_linux.conf - - diff --git a/Telegram/Resources/scheme.tl b/Telegram/Resources/scheme.tl index c0b41dc95..6db5b301f 100644 --- a/Telegram/Resources/scheme.tl +++ b/Telegram/Resources/scheme.tl @@ -159,14 +159,15 @@ inputMediaUploadedPhoto#2f37e231 flags:# file:InputFile caption:string stickers: inputMediaPhoto#81fa373a flags:# id:InputPhoto caption:string ttl_seconds:flags.0?int = InputMedia; inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; inputMediaContact#a6e45987 phone_number:string first_name:string last_name:string = InputMedia; -inputMediaUploadedDocument#e39621fd flags:# file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector caption:string stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; +inputMediaUploadedDocument#e39621fd flags:# nosound_video:flags.3?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector caption:string stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; inputMediaDocument#5acb668e flags:# id:InputDocument caption:string ttl_seconds:flags.0?int = InputMedia; -inputMediaVenue#2827a81a geo_point:InputGeoPoint title:string address:string provider:string venue_id:string = InputMedia; +inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia; inputMediaGifExternal#4843b0fd url:string q:string = InputMedia; inputMediaPhotoExternal#922aec1 flags:# url:string caption:string ttl_seconds:flags.0?int = InputMedia; inputMediaDocumentExternal#b6f74335 flags:# url:string caption:string ttl_seconds:flags.0?int = InputMedia; inputMediaGame#d33f43f3 id:InputGame = InputMedia; inputMediaInvoice#92153685 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string start_param:string = InputMedia; +inputMediaGeoLive#7b1a118f geo_point:InputGeoPoint period:int = InputMedia; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto; @@ -222,7 +223,7 @@ channel#cb44b1c flags:# creator:flags.0?true left:flags.2?true editor:flags.3?tr channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat; chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector = ChatFull; -channelFull#17f45fcf flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet = ChatFull; +channelFull#76af5481 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; @@ -245,9 +246,10 @@ messageMediaContact#5e7d2f39 phone_number:string first_name:string last_name:str messageMediaUnsupported#9f84f49e = MessageMedia; messageMediaDocument#7c4414d3 flags:# document:flags.0?Document caption:flags.1?string ttl_seconds:flags.2?int = MessageMedia; messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia; -messageMediaVenue#7912b71f geo:GeoPoint title:string address:string provider:string venue_id:string = MessageMedia; +messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia; messageMediaGame#fdb19008 game:Game = MessageMedia; messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia; +messageMediaGeoLive#7c3c2609 geo:GeoPoint period:int = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; messageActionChatCreate#a6638b9a title:string users:Vector = MessageAction; @@ -267,6 +269,7 @@ messageActionPaymentSentMe#8f31b327 flags:# currency:string total_amount:long pa messageActionPaymentSent#40699cd0 currency:string total_amount:long = MessageAction; messageActionPhoneCall#80e11a7f flags:# call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; messageActionScreenshotTaken#4792929b = MessageAction; +messageActionCustomAction#fae69f56 message:string = MessageAction; dialog#e4def5db flags:# pinned:flags.2?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog; @@ -340,6 +343,7 @@ messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector< messages.messages#8c718e87 messages:Vector chats:Vector users:Vector = messages.Messages; messages.messagesSlice#b446ae3 count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.channelMessages#99262e37 flags:# pts:int count:int messages:Vector chats:Vector users:Vector = messages.Messages; +messages.messagesNotModified#74535f21 count:int = messages.Messages; messages.chats#64ff9fd5 chats:Vector = messages.Chats; messages.chatsSlice#9cd81144 count:int chats:Vector = messages.Chats; @@ -352,7 +356,6 @@ inputMessagesFilterEmpty#57e2f66c = MessagesFilter; inputMessagesFilterPhotos#9609a51c = MessagesFilter; inputMessagesFilterVideo#9fc00e65 = MessagesFilter; inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; -inputMessagesFilterPhotoVideoDocuments#d95e73bb = MessagesFilter; inputMessagesFilterDocument#9eddf188 = MessagesFilter; inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; inputMessagesFilterGif#ffc86587 = MessagesFilter; @@ -363,6 +366,8 @@ inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFil inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter; inputMessagesFilterRoundVideo#b549da53 = MessagesFilter; inputMessagesFilterMyMentions#c1f8e69a = MessagesFilter; +inputMessagesFilterGeo#e7026d0d = MessagesFilter; +inputMessagesFilterContacts#e062db83 = MessagesFilter; updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; updateMessageID#4e90bfd6 id:int random_id:long = Update; @@ -429,6 +434,7 @@ updateLangPack#56022f4d difference:LangPackDifference = Update; updateFavedStickers#e511996d = Update; updateChannelReadMessagesContents#89893b45 channel_id:int messages:Vector = Update; updateContactsReset#7084a7be = Update; +updateChannelAvailableMessages#70db6837 channel_id:int available_min_id:int = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; @@ -455,7 +461,7 @@ upload.fileCdnRedirect#ea52fe5a dc_id:int file_token:bytes encryption_key:bytes dcOption#5d8c6cc flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int = DcOption; -config#8df376a4 flags:# phonecalls_enabled:flags.1?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string suggested_lang_code:flags.2?string lang_pack_version:flags.2?int disabled_features:Vector = Config; +config#9c840964 flags:# phonecalls_enabled:flags.1?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string suggested_lang_code:flags.2?string lang_pack_version:flags.2?int disabled_features:Vector = Config; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; @@ -665,6 +671,7 @@ channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter; channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; channels.channelParticipants#f56ee2a8 count:int participants:Vector users:Vector = channels.ChannelParticipants; +channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants; channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector = channels.ChannelParticipant; @@ -680,7 +687,7 @@ messages.savedGifs#2e0709a5 hash:int gifs:Vector = messages.SavedGifs; inputBotInlineMessageMediaAuto#292fed13 flags:# caption:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaGeo#f4a59de1 flags:# geo_point:InputGeoPoint reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; +inputBotInlineMessageMediaGeo#c1b15d65 flags:# geo_point:InputGeoPoint period:int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaVenue#aaafadc8 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaContact#2daf01a7 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; @@ -692,14 +699,14 @@ inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:Input botInlineMessageMediaAuto#a74b15b flags:# caption:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaGeo#3a8fd8b8 flags:# geo:GeoPoint reply_markup:flags.2?ReplyMarkup = BotInlineMessage; +botInlineMessageMediaGeo#b722de65 flags:# geo:GeoPoint period:int reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaVenue#4366232e flags:# geo:GeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaContact#35edb4d4 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineResult#9bebaeb9 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:BotInlineMessage = BotInlineResult; botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; -messages.botResults#ccd3563d flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector cache_time:int = messages.BotResults; +messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector cache_time:int users:Vector = messages.BotResults; exportedMessageLink#1f486803 link:string = ExportedMessageLink; @@ -714,7 +721,7 @@ auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; -messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; +messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; @@ -847,6 +854,8 @@ payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_inf inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; +inputPaymentCredentialsApplePay#aa1c39f payment_data:DataJSON = InputPaymentCredentials; +inputPaymentCredentialsAndroidPay#795667a6 payment_token:DataJSON = InputPaymentCredentials; account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; @@ -903,6 +912,7 @@ channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticip channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; +channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent; @@ -917,6 +927,14 @@ cdnFileHash#77eec38f offset:int limit:int hash:bytes = CdnFileHash; messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers; messages.favedStickers#f37f2f16 hash:int packs:Vector stickers:Vector = messages.FavedStickers; +recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl; +recentMeUrlUser#8dbc3336 url:string user_id:int = RecentMeUrl; +recentMeUrlChat#a01b22f9 url:string chat_id:int = RecentMeUrl; +recentMeUrlChatInvite#eb49081d url:string chat_invite:ChatInvite = RecentMeUrl; +recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl; + +help.recentMeUrls#e0310d7 urls:Vector chats:Vector users:Vector = help.RecentMeUrls; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -992,7 +1010,7 @@ contacts.resetSaved#879537f1 = Bool; messages.getMessages#4222fa74 id:Vector = messages.Messages; messages.getDialogs#191ba9c5 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int = messages.Dialogs; -messages.getHistory#afa92846 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; +messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; messages.search#39e9ea0 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true peer:InputPeer max_id:int = messages.AffectedHistory; @@ -1048,8 +1066,8 @@ messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_p messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool; messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates; messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; -messages.editMessage#ce91e4ca flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; -messages.editInlineBotMessage#130c2c85 flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Bool; +messages.editMessage#5d1b8dd flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true peer:InputPeer id:int message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector geo_point:flags.13?InputGeoPoint = Updates; +messages.editInlineBotMessage#b0e08243 flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true id:InputBotInlineMessageID message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector geo_point:flags.13?InputGeoPoint = Bool; messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer; messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; messages.getPeerDialogs#2d9776b9 peers:Vector = messages.PeerDialogs; @@ -1080,6 +1098,8 @@ messages.sendScreenshotNotification#c97df020 peer:InputPeer reply_to_msg_id:int messages.getFavedStickers#21ce0b0e hash:int = messages.FavedStickers; messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool; messages.getUnreadMentions#46578472 peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; +messages.readMentions#f0189d3 peer:InputPeer = messages.AffectedHistory; +messages.getRecentLocations#249431e2 peer:InputPeer limit:int = messages.Messages; updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; @@ -1108,13 +1128,14 @@ help.getAppChangelog#9010ef6f prev_app_version:string = Updates; help.getTermsOfService#350170f3 = help.TermsOfService; help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; help.getCdnConfig#52029342 = CdnConfig; +help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls; channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory; channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector = Bool; channels.getMessages#93d7b347 channel:InputChannel id:Vector = messages.Messages; -channels.getParticipants#24d98f92 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int = channels.ChannelParticipants; +channels.getParticipants#123e05e9 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:int = channels.ChannelParticipants; channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant; channels.getChannels#a7f6bbb id:Vector = messages.Chats; channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; @@ -1139,6 +1160,8 @@ channels.editBanned#bfd915cd channel:InputChannel user_id:InputUser banned_right channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector max_id:long min_id:long limit:int = channels.AdminLogResults; channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector = Bool; +channels.deleteHistory#af369d42 channel:InputChannel max_id:int = Bool; +channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; @@ -1169,4 +1192,4 @@ langpack.getStrings#2e1ee318 lang_code:string keys:Vector = Vector; -// LAYER 71 +// LAYER 72 diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml index 0f2b36494..912d1a93b 100644 --- a/Telegram/Resources/uwp/AppX/AppxManifest.xml +++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml @@ -12,8 +12,8 @@ Version="1.1.23.0" /> Telegram Desktop - Telegram Messenger LLP - Telegram Desktop official messenger + Pro.cxx + Kepka unofficial Telegram messenger Assets\logo\logo.png @@ -32,7 +32,7 @@ DisplayName="Telegram Desktop" Square150x150Logo="Assets\logo150\logo150.png" Square44x44Logo="Assets\logo44\logo44.png" - Description="Telegram Desktop official messenger" /> + Description="Kepka unofficial Telegram messenger" /> diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Kepka.rc.in similarity index 69% rename from Telegram/Resources/winrc/Telegram.rc rename to Telegram/Resources/winrc/Kepka.rc.in index 385c6336f..f775585fd 100644 --- a/Telegram/Resources/winrc/Telegram.rc +++ b/Telegram/Resources/winrc/Kepka.rc.in @@ -1,6 +1,6 @@ // Microsoft Visual C++ generated resource script. // -#include "resource.h" +#include "@CMAKE_CURRENT_SOURCE_DIR@/Resources/winrc/resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// @@ -26,7 +26,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. -IDI_ICON1 ICON "..\\art\\icon256.ico" +IDI_ICON1 ICON "@CMAKE_CURRENT_SOURCE_DIR@/Resources/art/icon256.ico" ///////////////////////////////////////////////////////////////////////////// // @@ -34,8 +34,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,1,23,0 - PRODUCTVERSION 1,1,23,0 + FILEVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,@PROJECT_VERSION_RC@ + PRODUCTVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,@PROJECT_VERSION_RC@ FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -50,12 +50,12 @@ BEGIN BEGIN BLOCK "040904b0" BEGIN - VALUE "CompanyName", "Telegram Messenger LLP" - VALUE "FileDescription", "Telegram Desktop" - VALUE "FileVersion", "1.1.23.0" - VALUE "LegalCopyright", "Copyright (C) 2014-2017" - VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "1.1.23.0" + VALUE "CompanyName", "@PROJECT_COMPANY_NAME@" + VALUE "FileDescription", "@PROJECT_NAME@" + VALUE "FileVersion", "@PROJECT_VERSION@" + VALUE "LegalCopyright", "Copyright (C) 2014-2019" + VALUE "ProductName", "@PROJECT_NAME@" + VALUE "ProductVersion", "@PROJECT_VERSION@" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc deleted file mode 100644 index ad5bce869..000000000 --- a/Telegram/Resources/winrc/Updater.rc +++ /dev/null @@ -1,72 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource1.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,1,23,0 - PRODUCTVERSION 1,1,23,0 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x0L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "CompanyName", "Telegram Messenger LLP" - VALUE "FileDescription", "Telegram Desktop Updater" - VALUE "FileVersion", "1.1.23.0" - VALUE "LegalCopyright", "Copyright (C) 2014-2017" - VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "1.1.23.0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/Telegram/Resources/winrc/resource1.h b/Telegram/Resources/winrc/resource1.h deleted file mode 100644 index fa4d7c2ea..000000000 --- a/Telegram/Resources/winrc/resource1.h +++ /dev/null @@ -1,14 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by Updater.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/Telegram/SetupFiles/data b/Telegram/SetupFiles/data deleted file mode 100644 index e69de29bb..000000000 diff --git a/Telegram/SetupFiles/log.txt b/Telegram/SetupFiles/log.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/Telegram/SourceFiles/_other/packer.cpp b/Telegram/SourceFiles/_other/packer.cpp deleted file mode 100644 index 4fe9530dc..000000000 --- a/Telegram/SourceFiles/_other/packer.cpp +++ /dev/null @@ -1,539 +0,0 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ -#include "packer.h" - -#include - -#ifdef Q_OS_MAC -//Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin) -#endif - -bool AlphaChannel = false; -quint64 BetaVersion = 0; - -const char *PublicKey = "\ ------BEGIN RSA PUBLIC KEY-----\n\ -MIGJAoGBAMA4ViQrjkPZ9xj0lrer3r23JvxOnrtE8nI69XLGSr+sRERz9YnUptnU\n\ -BZpkIfKaRcl6XzNJiN28cVwO1Ui5JSa814UAiDHzWUqCaXUiUEQ6NmNTneiGx2sQ\n\ -+9PKKlb8mmr3BB9A45ZNwLT6G9AK3+qkZLHojeSA+m84/a6GP4svAgMBAAE=\n\ ------END RSA PUBLIC KEY-----\ -"; - -const char *PublicAlphaKey = "\ ------BEGIN RSA PUBLIC KEY-----\n\ -MIGJAoGBALWu9GGs0HED7KG7BM73CFZ6o0xufKBRQsdnq3lwA8nFQEvmdu+g/I1j\n\ -0LQ+0IQO7GW4jAgzF/4+soPDb6uHQeNFrlVx1JS9DZGhhjZ5rf65yg11nTCIHZCG\n\ -w/CVnbwQOw0g5GBwwFV3r0uTTvy44xx8XXxk+Qknu4eBCsmrAFNnAgMBAAE=\n\ ------END RSA PUBLIC KEY-----\ -"; - -extern const char *PrivateKey; -extern const char *PrivateAlphaKey; -#include "../../../../TelegramPrivate/packer_private.h" // RSA PRIVATE KEYS for update signing -#include "../../../../TelegramPrivate/beta_private.h" // private key for beta version file generation - -QString countBetaVersionSignature(quint64 version); - -// sha1 hash -typedef unsigned char uchar; -typedef unsigned int uint32; -typedef signed int int32; - -namespace{ - -inline uint32 sha1Shift(uint32 v, uint32 shift) { - return ((v << shift) | (v >> (32 - shift))); -} - -void sha1PartHash(uint32 *sha, uint32 *temp) { - uint32 a = sha[0], b = sha[1], c = sha[2], d = sha[3], e = sha[4], round = 0; - -#define _shiftswap(f, v) { \ - uint32 t = sha1Shift(a, 5) + (f) + e + v + temp[round]; \ - e = d; \ - d = c; \ - c = sha1Shift(b, 30); \ - b = a; \ - a = t; \ - ++round; \ - } - -#define _shiftshiftswap(f, v) { \ - temp[round] = sha1Shift((temp[round - 3] ^ temp[round - 8] ^ temp[round - 14] ^ temp[round - 16]), 1); \ - _shiftswap(f, v) \ - } - - while (round < 16) _shiftswap((b & c) | (~b & d), 0x5a827999) - while (round < 20) _shiftshiftswap((b & c) | (~b & d), 0x5a827999) - while (round < 40) _shiftshiftswap(b ^ c ^ d, 0x6ed9eba1) - while (round < 60) _shiftshiftswap((b & c) | (b & d) | (c & d), 0x8f1bbcdc) - while (round < 80) _shiftshiftswap(b ^ c ^ d, 0xca62c1d6) - -#undef _shiftshiftswap -#undef _shiftswap - - sha[0] += a; - sha[1] += b; - sha[2] += c; - sha[3] += d; - sha[4] += e; -} - -} // namespace - -int32 *hashSha1(const void *data, uint32 len, void *dest) { - const uchar *buf = (const uchar *)data; - - uint32 temp[80], block = 0, end; - uint32 sha[5] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0}; - for (end = block + 64; block + 64 <= len; end = block + 64) { - for (uint32 i = 0; block < end; block += 4) { - temp[i++] = (uint32) buf[block + 3] - | (((uint32) buf[block + 2]) << 8) - | (((uint32) buf[block + 1]) << 16) - | (((uint32) buf[block]) << 24); - } - sha1PartHash(sha, temp); - } - - end = len - block; - memset(temp, 0, sizeof(uint32) * 16); - uint32 last = 0; - for (; last < end; ++last) { - temp[last >> 2] |= (uint32)buf[last + block] << ((3 - (last & 0x03)) << 3); - } - temp[last >> 2] |= 0x80 << ((3 - (last & 3)) << 3); - if (end >= 56) { - sha1PartHash(sha, temp); - memset(temp, 0, sizeof(uint32) * 16); - } - temp[15] = len << 3; - sha1PartHash(sha, temp); - - uchar *sha1To = (uchar*)dest; - - for (int32 i = 19; i >= 0; --i) { - sha1To[i] = (sha[i >> 2] >> (((3 - i) & 0x03) << 3)) & 0xFF; - } - - return (int32*)sha1To; -} - -QString BetaSignature; - -int main(int argc, char *argv[]) -{ - QString workDir; - - QString remove; - int version = 0; - bool target32 = false; - QFileInfoList files; - for (int i = 0; i < argc; ++i) { - if (string("-path") == argv[i] && i + 1 < argc) { - QString path = workDir + QString(argv[i + 1]); - QFileInfo info(path); - files.push_back(info); - if (remove.isEmpty()) remove = info.canonicalPath() + "/"; - } else if (string("-target") == argv[i] && i + 1 < argc) { - target32 = (string("mac32") == argv[i + 1]); - } else if (string("-version") == argv[i] && i + 1 < argc) { - version = QString(argv[i + 1]).toInt(); - } else if (string("-alpha") == argv[i]) { - AlphaChannel = true; - } else if (string("-beta") == argv[i] && i + 1 < argc) { - BetaVersion = QString(argv[i + 1]).toULongLong(); - if (BetaVersion > version * 1000ULL && BetaVersion < (version + 1) * 1000ULL) { - AlphaChannel = false; - BetaSignature = countBetaVersionSignature(BetaVersion); - if (BetaSignature.isEmpty()) { - return -1; - } - } else { - cout << "Bad -beta param value passed, should be for the same version: " << version << ", beta: " << BetaVersion << "\n"; - return -1; - } - } - } - - if (files.isEmpty() || remove.isEmpty() || version <= 1016 || version > 999999999) { -#ifdef Q_OS_WIN - cout << "Usage: Packer.exe -path {file} -version {version} OR Packer.exe -path {dir} -version {version}\n"; -#elif defined Q_OS_MAC - cout << "Usage: Packer.app -path {file} -version {version} OR Packer.app -path {dir} -version {version}\n"; -#else - cout << "Usage: Packer -path {file} -version {version} OR Packer -path {dir} -version {version}\n"; -#endif - return -1; - } - - bool hasDirs = true; - while (hasDirs) { - hasDirs = false; - for (QFileInfoList::iterator i = files.begin(); i != files.end(); ++i) { - QFileInfo info(*i); - QString fullPath = info.canonicalFilePath(); - if (info.isDir()) { - hasDirs = true; - files.erase(i); - QDir d = QDir(info.absoluteFilePath()); - QString fullDir = d.canonicalPath(); - QStringList entries = d.entryList(QDir::Files | QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot); - files.append(d.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot)); - break; - } else if (!info.isReadable()) { - cout << "Can't read: " << info.absoluteFilePath().toUtf8().constData() << "\n"; - return -1; - } else if (info.isHidden()) { - hasDirs = true; - files.erase(i); - break; - } - } - } - for (QFileInfoList::iterator i = files.begin(); i != files.end(); ++i) { - QFileInfo info(*i); - if (!info.canonicalFilePath().startsWith(remove)) { - cout << "Can't find '" << remove.toUtf8().constData() << "' in file '" << info.canonicalFilePath().toUtf8().constData() << "' :(\n"; - return -1; - } - } - - QByteArray result; - { - QBuffer buffer(&result); - buffer.open(QIODevice::WriteOnly); - QDataStream stream(&buffer); - stream.setVersion(QDataStream::Qt_5_1); - - if (BetaVersion) { - stream << quint32(0x7FFFFFFF); - stream << quint64(BetaVersion); - } else { - stream << quint32(version); - } - - stream << quint32(files.size()); - cout << "Found " << files.size() << " file" << (files.size() == 1 ? "" : "s") << "..\n"; - for (QFileInfoList::iterator i = files.begin(); i != files.end(); ++i) { - QFileInfo info(*i); - QString fullName = info.canonicalFilePath(); - QString name = fullName.mid(remove.length()); - cout << name.toUtf8().constData() << " (" << info.size() << ")\n"; - - QFile f(fullName); - if (!f.open(QIODevice::ReadOnly)) { - cout << "Can't open '" << fullName.toUtf8().constData() << "' for read..\n"; - return -1; - } - QByteArray inner = f.readAll(); - stream << name << quint32(inner.size()) << inner; -#if defined Q_OS_MAC || defined Q_OS_LINUX - stream << (QFileInfo(fullName).isExecutable() ? true : false); -#endif - } - if (stream.status() != QDataStream::Ok) { - cout << "Stream status is bad: " << stream.status() << "\n"; - return -1; - } - } - - int32 resultSize = result.size(); - cout << "Compression start, size: " << resultSize << "\n"; - - QByteArray compressed, resultCheck; -#ifdef Q_OS_WIN // use Lzma SDK for win - const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header - - compressed.resize(hSize + resultSize + 1024 * 1024); // rsa signature + sha1 + lzma props + max compressed size - - size_t compressedLen = compressed.size() - hSize; - size_t outPropsSize = LZMA_PROPS_SIZE; - uchar *_dest = (uchar*)(compressed.data() + hSize); - size_t *_destLen = &compressedLen; - const uchar *_src = (const uchar*)(result.constData()); - size_t _srcLen = result.size(); - uchar *_outProps = (uchar*)(compressed.data() + hSigLen + hShaLen); - int res = LzmaCompress(_dest, _destLen, _src, _srcLen, _outProps, &outPropsSize, 9, 64 * 1024 * 1024, 4, 0, 2, 273, 2); - if (res != SZ_OK) { - cout << "Error in compression: " << res << "\n"; - return -1; - } - compressed.resize(int(hSize + compressedLen)); - memcpy(compressed.data() + hSigLen + hShaLen + hPropsLen, &resultSize, hOriginalSizeLen); - - cout << "Compressed to size: " << compressedLen << "\n"; - - cout << "Checking uncompressed..\n"; - - int32 resultCheckLen; - memcpy(&resultCheckLen, compressed.constData() + hSigLen + hShaLen + hPropsLen, hOriginalSizeLen); - if (resultCheckLen <= 0 || resultCheckLen > 1024 * 1024 * 1024) { - cout << "Bad result len: " << resultCheckLen << "\n"; - return -1; - } - resultCheck.resize(resultCheckLen); - - size_t resultLen = resultCheck.size(); - SizeT srcLen = compressedLen; - int uncompressRes = LzmaUncompress((uchar*)resultCheck.data(), &resultLen, (const uchar*)(compressed.constData() + hSize), &srcLen, (const uchar*)(compressed.constData() + hSigLen + hShaLen), LZMA_PROPS_SIZE); - if (uncompressRes != SZ_OK) { - cout << "Uncompress failed: " << uncompressRes << "\n"; - return -1; - } - if (resultLen != size_t(result.size())) { - cout << "Uncompress bad size: " << resultLen << ", was: " << result.size() << "\n"; - return -1; - } -#else // use liblzma for others - const int32 hSigLen = 128, hShaLen = 20, hPropsLen = 0, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hOriginalSizeLen; // header - - compressed.resize(hSize + resultSize + 1024 * 1024); // rsa signature + sha1 + lzma props + max compressed size - - size_t compressedLen = compressed.size() - hSize; - - lzma_stream stream = LZMA_STREAM_INIT; - - int preset = 9 | LZMA_PRESET_EXTREME; - lzma_ret ret = lzma_easy_encoder(&stream, preset, LZMA_CHECK_CRC64); - if (ret != LZMA_OK) { - const char *msg; - switch (ret) { - case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; - case LZMA_OPTIONS_ERROR: msg = "Specified preset is not supported"; break; - case LZMA_UNSUPPORTED_CHECK: msg = "Specified integrity check is not supported"; break; - default: msg = "Unknown error, possibly a bug"; break; - } - cout << "Error initializing the encoder: " << msg << " (error code " << ret << ")\n"; - return -1; - } - - stream.avail_in = resultSize; - stream.next_in = (uint8_t*)result.constData(); - stream.avail_out = compressedLen; - stream.next_out = (uint8_t*)(compressed.data() + hSize); - - lzma_ret res = lzma_code(&stream, LZMA_FINISH); - compressedLen -= stream.avail_out; - lzma_end(&stream); - if (res != LZMA_OK && res != LZMA_STREAM_END) { - const char *msg; - switch (res) { - case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; - case LZMA_DATA_ERROR: msg = "File size limits exceeded"; break; - default: msg = "Unknown error, possibly a bug"; break; - } - cout << "Error in compression: " << msg << " (error code " << res << ")\n"; - return -1; - } - - compressed.resize(int(hSize + compressedLen)); - memcpy(compressed.data() + hSigLen + hShaLen, &resultSize, hOriginalSizeLen); - - cout << "Compressed to size: " << compressedLen << "\n"; - - cout << "Checking uncompressed..\n"; - - int32 resultCheckLen; - memcpy(&resultCheckLen, compressed.constData() + hSigLen + hShaLen, hOriginalSizeLen); - if (resultCheckLen <= 0 || resultCheckLen > 1024 * 1024 * 1024) { - cout << "Bad result len: " << resultCheckLen << "\n"; - return -1; - } - resultCheck.resize(resultCheckLen); - - size_t resultLen = resultCheck.size(); - - stream = LZMA_STREAM_INIT; - - ret = lzma_stream_decoder(&stream, UINT64_MAX, LZMA_CONCATENATED); - if (ret != LZMA_OK) { - const char *msg; - switch (ret) { - case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; - case LZMA_OPTIONS_ERROR: msg = "Specified preset is not supported"; break; - case LZMA_UNSUPPORTED_CHECK: msg = "Specified integrity check is not supported"; break; - default: msg = "Unknown error, possibly a bug"; break; - } - cout << "Error initializing the decoder: " << msg << " (error code " << ret << ")\n"; - return -1; - } - - stream.avail_in = compressedLen; - stream.next_in = (uint8_t*)(compressed.constData() + hSize); - stream.avail_out = resultLen; - stream.next_out = (uint8_t*)resultCheck.data(); - - res = lzma_code(&stream, LZMA_FINISH); - if (stream.avail_in) { - cout << "Error in decompression, " << stream.avail_in << " bytes left in _in of " << compressedLen << " whole.\n"; - return -1; - } else if (stream.avail_out) { - cout << "Error in decompression, " << stream.avail_out << " bytes free left in _out of " << resultLen << " whole.\n"; - return -1; - } - lzma_end(&stream); - if (res != LZMA_OK && res != LZMA_STREAM_END) { - const char *msg; - switch (res) { - case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; - case LZMA_FORMAT_ERROR: msg = "The input data is not in the .xz format"; break; - case LZMA_OPTIONS_ERROR: msg = "Unsupported compression options"; break; - case LZMA_DATA_ERROR: msg = "Compressed file is corrupt"; break; - case LZMA_BUF_ERROR: msg = "Compressed data is truncated or otherwise corrupt"; break; - default: msg = "Unknown error, possibly a bug"; break; - } - cout << "Error in decompression: " << msg << " (error code " << res << ")\n"; - return -1; - } -#endif - if (memcmp(result.constData(), resultCheck.constData(), resultLen)) { - cout << "Data differ :(\n"; - return -1; - } - /**/ - result = resultCheck = QByteArray(); - - cout << "Counting SHA1 hash..\n"; - - uchar sha1Buffer[20]; - memcpy(compressed.data() + hSigLen, hashSha1(compressed.constData() + hSigLen + hShaLen, uint32(compressedLen + hPropsLen + hOriginalSizeLen), sha1Buffer), hShaLen); // count sha1 - - uint32 siglen = 0; - - cout << "Signing..\n"; - RSA *prKey = PEM_read_bio_RSAPrivateKey(BIO_new_mem_buf(const_cast((AlphaChannel || BetaVersion) ? PrivateAlphaKey : PrivateKey), -1), 0, 0, 0); - if (!prKey) { - cout << "Could not read RSA private key!\n"; - return -1; - } - if (RSA_size(prKey) != hSigLen) { - cout << "Bad private key, size: " << RSA_size(prKey) << "\n"; - RSA_free(prKey); - return -1; - } - if (RSA_sign(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (uchar*)(compressed.data()), &siglen, prKey) != 1) { // count signature - cout << "Signing failed!\n"; - RSA_free(prKey); - return -1; - } - RSA_free(prKey); - - if (siglen != hSigLen) { - cout << "Bad signature length: " << siglen << "\n"; - return -1; - } - - cout << "Checking signature..\n"; - RSA *pbKey = PEM_read_bio_RSAPublicKey(BIO_new_mem_buf(const_cast((AlphaChannel || BetaVersion) ? PublicAlphaKey : PublicKey), -1), 0, 0, 0); - if (!pbKey) { - cout << "Could not read RSA public key!\n"; - return -1; - } - if (RSA_verify(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (const uchar*)(compressed.constData()), siglen, pbKey) != 1) { // verify signature - RSA_free(pbKey); - cout << "Signature verification failed!\n"; - return -1; - } - cout << "Signature verified!\n"; - RSA_free(pbKey); -#ifdef Q_OS_WIN - QString outName(QString("tupdate%1").arg(BetaVersion ? BetaVersion : version)); -#elif defined Q_OS_MAC - QString outName((target32 ? QString("tmac32upd%1") : QString("tmacupd%1")).arg(BetaVersion ? BetaVersion : version)); -#elif defined Q_OS_LINUX32 - QString outName(QString("tlinux32upd%1").arg(BetaVersion ? BetaVersion : version)); -#elif defined Q_OS_LINUX64 - QString outName(QString("tlinuxupd%1").arg(BetaVersion ? BetaVersion : version)); -#else -#error Unknown platform! -#endif - if (BetaVersion) { - outName += "_" + BetaSignature; - } - QFile out(outName); - if (!out.open(QIODevice::WriteOnly)) { - cout << "Can't open '" << outName.toUtf8().constData() << "' for write..\n"; - return -1; - } - out.write(compressed); - out.close(); - - if (BetaVersion) { - QString keyName(QString("tbeta_%1_key").arg(BetaVersion)); - QFile key(keyName); - if (!key.open(QIODevice::WriteOnly)) { - cout << "Can't open '" << keyName.toUtf8().constData() << "' for write..\n"; - return -1; - } - key.write(BetaSignature.toUtf8()); - key.close(); - } - - cout << "Update file '" << outName.toUtf8().constData() << "' written successfully!\n"; - - return 0; -} - -QString countBetaVersionSignature(quint64 version) { // duplicated in autoupdate.cpp - QByteArray cBetaPrivateKey(BetaPrivateKey); - if (cBetaPrivateKey.isEmpty()) { - cout << "Error: Trying to count beta version signature without beta private key!\n"; - return QString(); - } - - QByteArray signedData = (QLatin1String("TelegramBeta_") + QString::number(version, 16).toLower()).toUtf8(); - - static const int32 shaSize = 20, keySize = 128; - - uchar sha1Buffer[shaSize]; - hashSha1(signedData.constData(), signedData.size(), sha1Buffer); // count sha1 - - uint32 siglen = 0; - - RSA *prKey = PEM_read_bio_RSAPrivateKey(BIO_new_mem_buf(const_cast(cBetaPrivateKey.constData()), -1), 0, 0, 0); - if (!prKey) { - cout << "Error: Could not read beta private key!\n"; - return QString(); - } - if (RSA_size(prKey) != keySize) { - cout << "Error: Bad beta private key size: " << RSA_size(prKey) << "\n"; - RSA_free(prKey); - return QString(); - } - QByteArray signature; - signature.resize(keySize); - if (RSA_sign(NID_sha1, (const uchar*)(sha1Buffer), shaSize, (uchar*)(signature.data()), &siglen, prKey) != 1) { // count signature - cout << "Error: Counting beta version signature failed!\n"; - RSA_free(prKey); - return QString(); - } - RSA_free(prKey); - - if (siglen != keySize) { - cout << "Error: Bad beta version signature length: " << siglen << "\n"; - return QString(); - } - - signature = signature.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); - signature = signature.replace('-', '8').replace('_', 'B'); - return QString::fromUtf8(signature.mid(19, 32)); -} diff --git a/Telegram/SourceFiles/_other/packer.h b/Telegram/SourceFiles/_other/packer.h deleted file mode 100644 index 2cef45d82..000000000 --- a/Telegram/SourceFiles/_other/packer.h +++ /dev/null @@ -1,52 +0,0 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#ifdef Q_OS_WIN // use Lzma SDK for win -#include -#else -#include -#endif - -#include -#include -#include -using std::string; -using std::wstring; -using std::cout; \ No newline at end of file diff --git a/Telegram/SourceFiles/_other/updater.cpp b/Telegram/SourceFiles/_other/updater.cpp deleted file mode 100644 index dbcce3137..000000000 --- a/Telegram/SourceFiles/_other/updater.cpp +++ /dev/null @@ -1,590 +0,0 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ -#include "updater.h" - -bool _debug = false; - -wstring updaterName, updaterDir, updateTo, exeName; - -bool equal(const wstring &a, const wstring &b) { - return !_wcsicmp(a.c_str(), b.c_str()); -} - -void updateError(const WCHAR *msg, DWORD errorCode) { - WCHAR errMsg[2048]; - LPWSTR errorText = NULL, errorTextDefault = L"(Unknown error)"; - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&errorText, 0, 0); - if (!errorText) { - errorText = errorTextDefault; - } - wsprintf(errMsg, L"%s, error code: %d\nError message: %s", msg, errorCode, errorText); - - MessageBox(0, errMsg, L"Update error!", MB_ICONERROR); - - if (errorText != errorTextDefault) { - LocalFree(errorText); - } -} - -HANDLE _logFile = 0; -void openLog() { - if (!_debug || _logFile) return; - wstring logPath = L"DebugLogs"; - if (!CreateDirectory(logPath.c_str(), NULL)) { - DWORD errorCode = GetLastError(); - if (errorCode && errorCode != ERROR_ALREADY_EXISTS) { - updateError(L"Failed to create log directory", errorCode); - return; - } - } - - SYSTEMTIME stLocalTime; - - GetLocalTime(&stLocalTime); - - static const int maxFileLen = MAX_PATH * 10; - WCHAR logName[maxFileLen]; - wsprintf(logName, L"DebugLogs\\%04d%02d%02d_%02d%02d%02d_upd.txt", - stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay, - stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond); - _logFile = CreateFile(logName, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - if (_logFile == INVALID_HANDLE_VALUE) { // :( - updateError(L"Failed to create log file", GetLastError()); - _logFile = 0; - return; - } -} - -void closeLog() { - if (!_logFile) return; - - CloseHandle(_logFile); - _logFile = 0; -} - -void writeLog(const wstring &msg) { - if (!_logFile) return; - - wstring full = msg + L'\n'; - DWORD written = 0; - BOOL result = WriteFile(_logFile, full.c_str(), full.size() * sizeof(wchar_t), &written, 0); - if (!result) { - updateError((L"Failed to write log entry '" + msg + L"'").c_str(), GetLastError()); - closeLog(); - return; - } - BOOL flushr = FlushFileBuffers(_logFile); - if (!flushr) { - updateError((L"Failed to flush log on entry '" + msg + L"'").c_str(), GetLastError()); - closeLog(); - return; - } -} - -void fullClearPath(const wstring &dir) { - WCHAR path[4096]; - memcpy(path, dir.c_str(), (dir.size() + 1) * sizeof(WCHAR)); - path[dir.size() + 1] = 0; - writeLog(L"Fully clearing path '" + dir + L"'.."); - SHFILEOPSTRUCT file_op = { - NULL, - FO_DELETE, - path, - L"", - FOF_NOCONFIRMATION | - FOF_NOERRORUI | - FOF_SILENT, - false, - 0, - L"" - }; - int res = SHFileOperation(&file_op); - if (res) writeLog(L"Error: failed to clear path! :("); -} - -void delFolder() { - wstring delPathOld = L"tupdates\\ready", delPath = L"tupdates\\temp", delFolder = L"tupdates"; - fullClearPath(delPathOld); - fullClearPath(delPath); - RemoveDirectory(delFolder.c_str()); -} - -DWORD versionNum = 0, versionLen = 0, readLen = 0; -WCHAR versionStr[32] = { 0 }; - -bool update() { - writeLog(L"Update started.."); - - wstring updDir = L"tupdates\\temp", readyFilePath = L"tupdates\\temp\\ready", tdataDir = L"tupdates\\temp\\tdata"; - { - HANDLE readyFile = CreateFile(readyFilePath.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); - if (readyFile != INVALID_HANDLE_VALUE) { - CloseHandle(readyFile); - } else { - updDir = L"tupdates\\ready"; // old - tdataDir = L"tupdates\\ready\\tdata"; - } - } - - HANDLE versionFile = CreateFile((tdataDir + L"\\version").c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); - if (versionFile != INVALID_HANDLE_VALUE) { - if (!ReadFile(versionFile, &versionNum, sizeof(DWORD), &readLen, NULL) || readLen != sizeof(DWORD)) { - versionNum = 0; - } else { - if (versionNum == 0x7FFFFFFF) { // beta version - - } else if (!ReadFile(versionFile, &versionLen, sizeof(DWORD), &readLen, NULL) || readLen != sizeof(DWORD) || versionLen > 63) { - versionNum = 0; - } else if (!ReadFile(versionFile, versionStr, versionLen, &readLen, NULL) || readLen != versionLen) { - versionNum = 0; - } - } - CloseHandle(versionFile); - writeLog(L"Version file read."); - } else { - writeLog(L"Could not open version file to update registry :("); - } - - deque dirs; - dirs.push_back(updDir); - - deque from, to, forcedirs; - - do { - wstring dir = dirs.front(); - dirs.pop_front(); - - wstring toDir = updateTo; - if (dir.size() > updDir.size() + 1) { - toDir += (dir.substr(updDir.size() + 1) + L"\\"); - forcedirs.push_back(toDir); - writeLog(L"Parsing dir '" + toDir + L"' in update tree.."); - } - - WIN32_FIND_DATA findData; - HANDLE findHandle = FindFirstFileEx((dir + L"\\*").c_str(), FindExInfoStandard, &findData, FindExSearchNameMatch, 0, 0); - if (findHandle == INVALID_HANDLE_VALUE) { - DWORD errorCode = GetLastError(); - if (errorCode == ERROR_PATH_NOT_FOUND) { // no update is ready - return true; - } - writeLog(L"Error: failed to find update files :("); - updateError(L"Failed to find update files", errorCode); - delFolder(); - return false; - } - - do { - wstring fname = dir + L"\\" + findData.cFileName; - if (fname.substr(0, tdataDir.size()) == tdataDir && (fname.size() <= tdataDir.size() || fname.at(tdataDir.size()) == '/')) { - writeLog(L"Skipped 'tdata' path '" + fname + L"'"); - } else if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - if (findData.cFileName != wstring(L".") && findData.cFileName != wstring(L"..")) { - dirs.push_back(fname); - writeLog(L"Added dir '" + fname + L"' in update tree.."); - } - } else { - wstring tofname = updateTo + fname.substr(updDir.size() + 1); - if (equal(tofname, updaterName)) { // bad update - has Updater.exe - delete all dir - writeLog(L"Error: bad update, has Updater.exe! '" + tofname + L"' equal '" + updaterName + L"'"); - delFolder(); - return false; - } else if (equal(tofname, updateTo + L"Telegram.exe") && exeName != L"Telegram.exe") { - wstring fullBinaryPath = updateTo + exeName; - writeLog(L"Target binary found: '" + tofname + L"', changing to '" + fullBinaryPath + L"'"); - tofname = fullBinaryPath; - } - if (equal(fname, readyFilePath)) { - writeLog(L"Skipped ready file '" + fname + L"'"); - } else { - from.push_back(fname); - to.push_back(tofname); - writeLog(L"Added file '" + fname + L"' to be copied to '" + tofname + L"'"); - } - } - } while (FindNextFile(findHandle, &findData)); - DWORD errorCode = GetLastError(); - if (errorCode && errorCode != ERROR_NO_MORE_FILES) { // everything is found - writeLog(L"Error: failed to find next update file :("); - updateError(L"Failed to find next update file", errorCode); - delFolder(); - return false; - } - FindClose(findHandle); - } while (!dirs.empty()); - - for (size_t i = 0; i < forcedirs.size(); ++i) { - wstring forcedir = forcedirs[i]; - writeLog(L"Forcing dir '" + forcedir + L"'.."); - if (!forcedir.empty() && !CreateDirectory(forcedir.c_str(), NULL)) { - DWORD errorCode = GetLastError(); - if (errorCode && errorCode != ERROR_ALREADY_EXISTS) { - writeLog(L"Error: failed to create dir '" + forcedir + L"'.."); - updateError(L"Failed to create directory", errorCode); - delFolder(); - return false; - } - writeLog(L"Already exists!"); - } - } - - for (size_t i = 0; i < from.size(); ++i) { - wstring fname = from[i], tofname = to[i]; - BOOL copyResult; - do { - writeLog(L"Copying file '" + fname + L"' to '" + tofname + L"'.."); - int copyTries = 0; - do { - copyResult = CopyFile(fname.c_str(), tofname.c_str(), FALSE); - if (!copyResult) { - ++copyTries; - Sleep(100); - } else { - break; - } - } while (copyTries < 100); - if (!copyResult) { - writeLog(L"Error: failed to copy, asking to retry.."); - WCHAR errMsg[2048]; - wsprintf(errMsg, L"Failed to update Telegram :(\n%s is not accessible.", tofname.c_str()); - if (MessageBox(0, errMsg, L"Update error!", MB_ICONERROR | MB_RETRYCANCEL) != IDRETRY) { - delFolder(); - return false; - } - } - } while (!copyResult); - } - - writeLog(L"Update succeed! Clearing folder.."); - delFolder(); - return true; -} - -void updateRegistry() { - if (versionNum && versionNum != 0x7FFFFFFF) { - writeLog(L"Updating registry.."); - versionStr[versionLen / 2] = 0; - HKEY rkey; - LSTATUS status = RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{53F49750-6209-4FBF-9CA8-7A333C87D1ED}_is1", 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &rkey); - if (status == ERROR_SUCCESS) { - writeLog(L"Checking registry install location.."); - static const int bufSize = 4096; - DWORD locationType, locationSize = bufSize * 2; - WCHAR locationStr[bufSize], exp[bufSize]; - if (RegQueryValueEx(rkey, L"InstallLocation", 0, &locationType, (BYTE*)locationStr, &locationSize) == ERROR_SUCCESS) { - locationSize /= 2; - if (locationStr[locationSize - 1]) { - locationStr[locationSize++] = 0; - } - if (locationType == REG_EXPAND_SZ) { - DWORD copy = ExpandEnvironmentStrings(locationStr, exp, bufSize); - if (copy <= bufSize) { - memcpy(locationStr, exp, copy * sizeof(WCHAR)); - } - } - if (locationType == REG_EXPAND_SZ || locationType == REG_SZ) { - if (PathCanonicalize(exp, locationStr)) { - memcpy(locationStr, exp, bufSize * sizeof(WCHAR)); - if (GetFullPathName(L".", bufSize, exp, 0) < bufSize) { - wstring installpath = locationStr, mypath = exp; - if (installpath == mypath + L"\\" || true) { // always update reg info, if we found it - WCHAR nameStr[bufSize], dateStr[bufSize], publisherStr[bufSize], icongroupStr[bufSize]; - SYSTEMTIME stLocalTime; - GetLocalTime(&stLocalTime); - RegSetValueEx(rkey, L"DisplayVersion", 0, REG_SZ, (BYTE*)versionStr, ((versionLen / 2) + 1) * sizeof(WCHAR)); - wsprintf(nameStr, L"Telegram Desktop version %s", versionStr); - RegSetValueEx(rkey, L"DisplayName", 0, REG_SZ, (BYTE*)nameStr, (wcslen(nameStr) + 1) * sizeof(WCHAR)); - wsprintf(publisherStr, L"Telegram Messenger LLP"); - RegSetValueEx(rkey, L"Publisher", 0, REG_SZ, (BYTE*)publisherStr, (wcslen(publisherStr) + 1) * sizeof(WCHAR)); - wsprintf(icongroupStr, L"Telegram Desktop"); - RegSetValueEx(rkey, L"Inno Setup: Icon Group", 0, REG_SZ, (BYTE*)icongroupStr, (wcslen(icongroupStr) + 1) * sizeof(WCHAR)); - wsprintf(dateStr, L"%04d%02d%02d", stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay); - RegSetValueEx(rkey, L"InstallDate", 0, REG_SZ, (BYTE*)dateStr, (wcslen(dateStr) + 1) * sizeof(WCHAR)); - - WCHAR *appURL = L"https://desktop.telegram.org"; - RegSetValueEx(rkey, L"HelpLink", 0, REG_SZ, (BYTE*)appURL, (wcslen(appURL) + 1) * sizeof(WCHAR)); - RegSetValueEx(rkey, L"URLInfoAbout", 0, REG_SZ, (BYTE*)appURL, (wcslen(appURL) + 1) * sizeof(WCHAR)); - RegSetValueEx(rkey, L"URLUpdateInfo", 0, REG_SZ, (BYTE*)appURL, (wcslen(appURL) + 1) * sizeof(WCHAR)); - } - } - } - } - } - RegCloseKey(rkey); - } - } -} - -int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdParamarg, int cmdShow) { - openLog(); - - _oldWndExceptionFilter = SetUnhandledExceptionFilter(_exceptionFilter); -// CAPIHook apiHook("kernel32.dll", "SetUnhandledExceptionFilter", (PROC)RedirectedSetUnhandledExceptionFilter); - - writeLog(L"Updaters started.."); - - LPWSTR *args; - int argsCount; - - bool needupdate = false, autostart = false, debug = false, writeprotected = false, startintray = false, testmode = false; - args = CommandLineToArgvW(GetCommandLine(), &argsCount); - if (args) { - for (int i = 1; i < argsCount; ++i) { - if (equal(args[i], L"-update")) { - needupdate = true; - } else if (equal(args[i], L"-autostart")) { - autostart = true; - } else if (equal(args[i], L"-debug")) { - debug = _debug = true; - openLog(); - } else if (equal(args[i], L"-startintray")) { - startintray = true; - } else if (equal(args[i], L"-testmode")) { - testmode = true; - } else if (equal(args[i], L"-writeprotected") && ++i < argsCount) { - writeprotected = true; - updateTo = args[i]; - for (int i = 0, l = updateTo.size(); i < l; ++i) { - if (updateTo[i] == L'/') { - updateTo[i] = L'\\'; - } - } - } else if (equal(args[i], L"-exename") && ++i < argsCount) { - exeName = args[i]; - for (int i = 0, l = exeName.size(); i < l; ++i) { - if (exeName[i] == L'/' || exeName[i] == L'\\') { - exeName = L"Telegram.exe"; - break; - } - } - } - } - if (exeName.empty()) { - exeName = L"Telegram.exe"; - } - if (needupdate) writeLog(L"Need to update!"); - if (autostart) writeLog(L"From autostart!"); - if (writeprotected) writeLog(L"Write Protected folder!"); - - updaterName = args[0]; - writeLog(L"Updater name is: " + updaterName); - if (updaterName.size() > 11) { - if (equal(updaterName.substr(updaterName.size() - 11), L"Updater.exe")) { - updaterDir = updaterName.substr(0, updaterName.size() - 11); - writeLog(L"Updater dir is: " + updaterDir); - if (!writeprotected) { - updateTo = updaterDir; - } - writeLog(L"Update to: " + updateTo); - if (needupdate && update()) { - updateRegistry(); - } - if (writeprotected) { // if we can't clear all tupdates\ready (Updater.exe is there) - clear only version - if (DeleteFile(L"tupdates\\temp\\tdata\\version") || DeleteFile(L"tupdates\\ready\\tdata\\version")) { - writeLog(L"Version file deleted!"); - } else { - writeLog(L"Error: could not delete version file"); - } - } - } else { - writeLog(L"Error: bad exe name!"); - } - } else { - writeLog(L"Error: short exe name!"); - } - LocalFree(args); - } else { - writeLog(L"Error: No command line arguments!"); - } - - wstring targs; - if (autostart) targs += L" -autostart"; - if (debug) targs += L" -debug"; - if (startintray) targs += L" -startintray"; - if (testmode) targs += L" -testmode"; - - bool executed = false; - if (writeprotected) { // run un-elevated - writeLog(L"Trying to run un-elevated by temp.lnk"); - - HRESULT hres = CoInitialize(0); - if (SUCCEEDED(hres)) { - IShellLink* psl; - HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl); - if (SUCCEEDED(hres)) { - IPersistFile* ppf; - - wstring exe = updateTo + exeName, dir = updateTo; - psl->SetArguments((targs.size() ? targs.substr(1) : targs).c_str()); - psl->SetPath(exe.c_str()); - psl->SetWorkingDirectory(dir.c_str()); - psl->SetDescription(L""); - - hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf); - - if (SUCCEEDED(hres)) { - wstring lnk = L"tupdates\\temp\\temp.lnk"; - hres = ppf->Save(lnk.c_str(), TRUE); - if (!SUCCEEDED(hres)) { - lnk = L"tupdates\\ready\\temp.lnk"; // old - hres = ppf->Save(lnk.c_str(), TRUE); - } - ppf->Release(); - - if (SUCCEEDED(hres)) { - writeLog(L"Executing un-elevated through link.."); - ShellExecute(0, 0, L"explorer.exe", lnk.c_str(), 0, SW_SHOWNORMAL); - executed = true; - } else { - writeLog(L"Error: ppf->Save failed"); - } - } else { - writeLog(L"Error: Could not create interface IID_IPersistFile"); - } - psl->Release(); - } else { - writeLog(L"Error: could not create instance of IID_IShellLink"); - } - CoUninitialize(); - } else { - writeLog(L"Error: Could not initialize COM"); - } - } - if (!executed) { - ShellExecute(0, 0, (updateTo + exeName).c_str(), (L"-noupdate" + targs).c_str(), 0, SW_SHOWNORMAL); - } - - writeLog(L"Executed '" + exeName + L"', closing log and quitting.."); - closeLog(); - - return 0; -} - -static const WCHAR *_programName = L"Telegram Desktop"; // folder in APPDATA, if current path is unavailable for writing -static const WCHAR *_exeName = L"Updater.exe"; - -LPTOP_LEVEL_EXCEPTION_FILTER _oldWndExceptionFilter = 0; - -typedef BOOL (FAR STDAPICALLTYPE *t_miniDumpWriteDump)( - _In_ HANDLE hProcess, - _In_ DWORD ProcessId, - _In_ HANDLE hFile, - _In_ MINIDUMP_TYPE DumpType, - _In_opt_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, - _In_opt_ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, - _In_opt_ PMINIDUMP_CALLBACK_INFORMATION CallbackParam -); -t_miniDumpWriteDump miniDumpWriteDump = 0; - -HANDLE _generateDumpFileAtPath(const WCHAR *path) { - static const int maxFileLen = MAX_PATH * 10; - - WCHAR szPath[maxFileLen]; - wsprintf(szPath, L"%stdata\\", path); - if (!CreateDirectory(szPath, NULL)) { - if (GetLastError() != ERROR_ALREADY_EXISTS) { - return 0; - } - } - wsprintf(szPath, L"%sdumps\\", path); - if (!CreateDirectory(szPath, NULL)) { - if (GetLastError() != ERROR_ALREADY_EXISTS) { - return 0; - } - } - - WCHAR szFileName[maxFileLen]; - WCHAR szExeName[maxFileLen]; - - wcscpy_s(szExeName, _exeName); - WCHAR *dotFrom = wcschr(szExeName, WCHAR(L'.')); - if (dotFrom) { - wsprintf(dotFrom, L""); - } - - SYSTEMTIME stLocalTime; - - GetLocalTime(&stLocalTime); - - wsprintf(szFileName, L"%s%s-%s-%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp", - szPath, szExeName, updaterVersionStr, - stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay, - stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond, - GetCurrentProcessId(), GetCurrentThreadId()); - return CreateFile(szFileName, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0); -} - -void _generateDump(EXCEPTION_POINTERS* pExceptionPointers) { - static const int maxFileLen = MAX_PATH * 10; - - closeLog(); - - HMODULE hDll = LoadLibrary(L"DBGHELP.DLL"); - if (!hDll) return; - - miniDumpWriteDump = (t_miniDumpWriteDump)GetProcAddress(hDll, "MiniDumpWriteDump"); - if (!miniDumpWriteDump) return; - - HANDLE hDumpFile = 0; - - WCHAR szPath[maxFileLen]; - DWORD len = GetModuleFileName(GetModuleHandle(0), szPath, maxFileLen); - if (!len) return; - - WCHAR *pathEnd = szPath + len; - - if (!_wcsicmp(pathEnd - wcslen(_exeName), _exeName)) { - wsprintf(pathEnd - wcslen(_exeName), L""); - hDumpFile = _generateDumpFileAtPath(szPath); - } - if (!hDumpFile || hDumpFile == INVALID_HANDLE_VALUE) { - WCHAR wstrPath[maxFileLen]; - DWORD wstrPathLen; - if (wstrPathLen = GetEnvironmentVariable(L"APPDATA", wstrPath, maxFileLen)) { - wsprintf(wstrPath + wstrPathLen, L"\\%s\\", _programName); - hDumpFile = _generateDumpFileAtPath(wstrPath); - } - } - - if (!hDumpFile || hDumpFile == INVALID_HANDLE_VALUE) { - return; - } - - MINIDUMP_EXCEPTION_INFORMATION ExpParam = {0}; - ExpParam.ThreadId = GetCurrentThreadId(); - ExpParam.ExceptionPointers = pExceptionPointers; - ExpParam.ClientPointers = TRUE; - - miniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpWithDataSegs, &ExpParam, NULL, NULL); -} - -LONG CALLBACK _exceptionFilter(EXCEPTION_POINTERS* pExceptionPointers) { - _generateDump(pExceptionPointers); - return _oldWndExceptionFilter ? (*_oldWndExceptionFilter)(pExceptionPointers) : EXCEPTION_CONTINUE_SEARCH; -} - -// see http://www.codeproject.com/Articles/154686/SetUnhandledExceptionFilter-and-the-C-C-Runtime-Li -LPTOP_LEVEL_EXCEPTION_FILTER WINAPI RedirectedSetUnhandledExceptionFilter(_In_opt_ LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter) { - // When the CRT calls SetUnhandledExceptionFilter with NULL parameter - // our handler will not get removed. - _oldWndExceptionFilter = lpTopLevelExceptionFilter; - return 0; -} diff --git a/Telegram/SourceFiles/_other/updater.h b/Telegram/SourceFiles/_other/updater.h deleted file mode 100644 index bf28ab672..000000000 --- a/Telegram/SourceFiles/_other/updater.h +++ /dev/null @@ -1,46 +0,0 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ -#pragma once - -#include -#include - -#pragma warning(push) -#pragma warning(disable:4091) -#include -#include -#pragma warning(pop) - -#include -#include - -#include -#include - -using std::deque; -using std::wstring; - -extern LPTOP_LEVEL_EXCEPTION_FILTER _oldWndExceptionFilter; -LONG CALLBACK _exceptionFilter(EXCEPTION_POINTERS* pExceptionPointers); -LPTOP_LEVEL_EXCEPTION_FILTER WINAPI RedirectedSetUnhandledExceptionFilter(_In_opt_ LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter); - -static int updaterVersion = 1000; -static const WCHAR *updaterVersionStr = L"0.1.0"; diff --git a/Telegram/SourceFiles/_other/updater_linux.cpp b/Telegram/SourceFiles/_other/updater_linux.cpp deleted file mode 100644 index 2e09dd70d..000000000 --- a/Telegram/SourceFiles/_other/updater_linux.cpp +++ /dev/null @@ -1,476 +0,0 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using std::string; -using std::deque; -using std::cout; - -bool do_mkdir(const char *path) { // from http://stackoverflow.com/questions/675039/how-can-i-create-directory-tree-in-c-linux - struct stat statbuf; - if (stat(path, &statbuf) != 0) { - /* Directory does not exist. EEXIST for race condition */ - if (mkdir(path, S_IRWXU) != 0 && errno != EEXIST) return false; - } else if (!S_ISDIR(statbuf.st_mode)) { - errno = ENOTDIR; - return false; - } - - return true; -} - -bool _debug = false; -string updaterDir; -string updaterName; -string workDir; -string exeName; -string exePath; - -FILE *_logFile = 0; -void openLog() { - if (!_debug || _logFile) return; - - if (!do_mkdir((workDir + "DebugLogs").c_str())) { - return; - } - - time_t timer; - - time(&timer); - struct tm *t = localtime(&timer); - - static const int maxFileLen = 65536; - char logName[maxFileLen]; - sprintf(logName, "%sDebugLogs/%04d%02d%02d_%02d%02d%02d_upd.txt", workDir.c_str(), - t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); - _logFile = fopen(logName, "w"); -} - -void closeLog() { - if (!_logFile) return; - - fclose(_logFile); - _logFile = 0; -} - -void writeLog(const char *format, ...) { - if (!_logFile) { - return; - } - - va_list args; - va_start(args, format); - vfprintf(_logFile, format, args); - fprintf(_logFile, "\n"); - fflush(_logFile); - va_end(args); -} - -bool copyFile(const char *from, const char *to) { - FILE *ffrom = fopen(from, "rb"), *fto = fopen(to, "wb"); - if (!ffrom) { - if (fto) fclose(fto); - return false; - } - if (!fto) { - fclose(ffrom); - return false; - } - static const int BufSize = 65536; - char buf[BufSize]; - while (size_t size = fread(buf, 1, BufSize, ffrom)) { - fwrite(buf, 1, size, fto); - } - - struct stat fst; // from http://stackoverflow.com/questions/5486774/keeping-fileowner-and-permissions-after-copying-file-in-c - //let's say this wont fail since you already worked OK on that fp - if (fstat(fileno(ffrom), &fst) != 0) { - fclose(ffrom); - fclose(fto); - return false; - } - //update to the same uid/gid - if (fchown(fileno(fto), fst.st_uid, fst.st_gid) != 0) { - fclose(ffrom); - fclose(fto); - return false; - } - //update the permissions - if (fchmod(fileno(fto), fst.st_mode) != 0) { - fclose(ffrom); - fclose(fto); - return false; - } - - fclose(ffrom); - fclose(fto); - - return true; -} - -bool remove_directory(const string &path) { // from http://stackoverflow.com/questions/2256945/removing-a-non-empty-directory-programmatically-in-c-or-c - DIR *d = opendir(path.c_str()); - writeLog("Removing dir '%s'", path.c_str()); - - if (!d) { - writeLog("Could not open dir '%s'", path.c_str()); - return (errno == ENOENT); - } - - while (struct dirent *p = readdir(d)) { - /* Skip the names "." and ".." as we don't want to recurse on them. */ - if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..")) continue; - - string fname = path + '/' + p->d_name; - struct stat statbuf; - writeLog("Trying to get stat() for '%s'", fname.c_str()); - if (!stat(fname.c_str(), &statbuf)) { - if (S_ISDIR(statbuf.st_mode)) { - if (!remove_directory(fname.c_str())) { - closedir(d); - return false; - } - } else { - writeLog("Unlinking file '%s'", fname.c_str()); - if (unlink(fname.c_str())) { - writeLog("Failed to unlink '%s'", fname.c_str()); - closedir(d); - return false; - } - } - } else { - writeLog("Failed to call stat() on '%s'", fname.c_str()); - } - } - closedir(d); - - writeLog("Finally removing dir '%s'", path.c_str()); - return !rmdir(path.c_str()); -} - -bool mkpath(const char *path) { - int status = 0, pathsize = strlen(path) + 1; - char *copypath = new char[pathsize]; - memcpy(copypath, path, pathsize); - - char *pp = copypath, *sp; - while (status == 0 && (sp = strchr(pp, '/')) != 0) { - if (sp != pp) { - /* Neither root nor double slash in path */ - *sp = '\0'; - if (!do_mkdir(copypath)) { - delete[] copypath; - return false; - } - *sp = '/'; - } - pp = sp + 1; - } - delete[] copypath; - return do_mkdir(path); -} - -bool equal(string a, string b) { - std::transform(a.begin(), a.end(), a.begin(), ::tolower); - std::transform(b.begin(), b.end(), b.begin(), ::tolower); - return a == b; -} - -void delFolder() { - string delPathOld = workDir + "tupdates/ready", delPath = workDir + "tupdates/temp", delFolder = workDir + "tupdates"; - writeLog("Fully clearing old path '%s'..", delPathOld.c_str()); - if (!remove_directory(delPathOld)) { - writeLog("Failed to clear old path! :( New path was used?.."); - } - writeLog("Fully clearing path '%s'..", delPath.c_str()); - if (!remove_directory(delPath)) { - writeLog("Error: failed to clear path! :("); - } - rmdir(delFolder.c_str()); -} - -bool update() { - writeLog("Update started.."); - - string updDir = workDir + "tupdates/temp", readyFilePath = workDir + "tupdates/temp/ready", tdataDir = workDir + "tupdates/temp/tdata"; - { - FILE *readyFile = fopen(readyFilePath.c_str(), "rb"); - if (readyFile) { - fclose(readyFile); - writeLog("Ready file found! Using new path '%s'..", updDir.c_str()); - } else { - updDir = workDir + "tupdates/ready"; // old - tdataDir = workDir + "tupdates/ready/tdata"; - writeLog("Ready file not found! Using old path '%s'..", updDir.c_str()); - } - } - - deque dirs; - dirs.push_back(updDir); - - deque from, to, forcedirs; - - do { - string dir = dirs.front(); - dirs.pop_front(); - - string toDir = exePath; - if (dir.size() > updDir.size() + 1) { - toDir += (dir.substr(updDir.size() + 1) + '/'); - forcedirs.push_back(toDir); - writeLog("Parsing dir '%s' in update tree..", toDir.c_str()); - } - - DIR *d = opendir(dir.c_str()); - if (!d) { - writeLog("Failed to open dir %s", dir.c_str()); - return false; - } - - while (struct dirent *p = readdir(d)) { - /* Skip the names "." and ".." as we don't want to recurse on them. */ - if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..")) continue; - - string fname = dir + '/' + p->d_name; - struct stat statbuf; - if (fname.substr(0, tdataDir.size()) == tdataDir && (fname.size() <= tdataDir.size() || fname.at(tdataDir.size()) == '/')) { - writeLog("Skipping 'tdata' path '%s'", fname.c_str()); - } else if (!stat(fname.c_str(), &statbuf)) { - if (S_ISDIR(statbuf.st_mode)) { - dirs.push_back(fname); - writeLog("Added dir '%s' in update tree..", fname.c_str()); - } else { - string tofname = exePath + fname.substr(updDir.size() + 1); - if (equal(tofname, updaterName)) { // bad update - has Updater - delete all dir - writeLog("Error: bad update, has Updater! '%s' equal '%s'", tofname.c_str(), updaterName.c_str()); - delFolder(); - return false; - } else if (equal(tofname, exePath + "Telegram") && exeName != "Telegram") { - string fullBinaryPath = exePath + exeName; - writeLog("Target binary found: '%s', changing to '%s'", tofname.c_str(), fullBinaryPath.c_str()); - tofname = fullBinaryPath; - } - if (fname == readyFilePath) { - writeLog("Skipped ready file '%s'", fname.c_str()); - } else { - from.push_back(fname); - to.push_back(tofname); - writeLog("Added file '%s' to be copied to '%s'", fname.c_str(), tofname.c_str()); - } - } - } else { - writeLog("Could not get stat() for file %s", fname.c_str()); - } - } - closedir(d); - } while (!dirs.empty()); - - for (size_t i = 0; i < forcedirs.size(); ++i) { - string forcedir = forcedirs[i]; - writeLog("Forcing dir '%s'..", forcedir.c_str()); - if (!forcedir.empty() && !mkpath(forcedir.c_str())) { - writeLog("Error: failed to create dir '%s'..", forcedir.c_str()); - delFolder(); - return false; - } - } - - for (size_t i = 0; i < from.size(); ++i) { - string fname = from[i], tofname = to[i]; - writeLog("Copying file '%s' to '%s'..", fname.c_str(), tofname.c_str()); - int copyTries = 0, triesLimit = 30; - do { - if (!copyFile(fname.c_str(), tofname.c_str())) { - ++copyTries; - usleep(100000); - } else { - break; - } - } while (copyTries < triesLimit); - if (copyTries == triesLimit) { - writeLog("Error: failed to copy, asking to retry.."); - delFolder(); - return false; - } - } - - writeLog("Update succeed! Clearing folder.."); - delFolder(); - return true; -} - -string CurrentExecutablePath(int argc, char *argv[]) { - constexpr auto kMaxPath = 1024; - char result[kMaxPath] = { 0 }; - auto count = readlink("/proc/self/exe", result, kMaxPath); - if (count > 0) { - return string(result); - } - - // Fallback to the first command line argument. - return argc ? string(argv[0]) : string(); -} - -int main(int argc, char *argv[]) { - bool needupdate = true, autostart = false, debug = false, tosettings = false, startintray = false, testmode = false; - - char *key = 0, *crashreport = 0; - for (int i = 1; i < argc; ++i) { - if (equal(argv[i], "-noupdate")) { - needupdate = false; - } else if (equal(argv[i], "-autostart")) { - autostart = true; - } else if (equal(argv[i], "-debug")) { - debug = _debug = true; - } else if (equal(argv[i], "-startintray")) { - startintray = true; - } else if (equal(argv[i], "-testmode")) { - testmode = true; - } else if (equal(argv[i], "-tosettings")) { - tosettings = true; - } else if (equal(argv[i], "-key") && ++i < argc) { - key = argv[i]; - } else if (equal(argv[i], "-workpath") && ++i < argc) { - workDir = argv[i]; - } else if (equal(argv[i], "-crashreport") && ++i < argc) { - crashreport = argv[i]; - } else if (equal(argv[i], "-exename") && ++i < argc) { - exeName = argv[i]; - } else if (equal(argv[i], "-exepath") && ++i < argc) { - exePath = argv[i]; - } - } - if (exeName.empty() || exeName.find('/') != string::npos) { - exeName = "Telegram"; - } - openLog(); - - writeLog("Updater started.."); - for (int i = 0; i < argc; ++i) { - writeLog("Argument: '%s'", argv[i]); - } - if (needupdate) writeLog("Need to update!"); - if (autostart) writeLog("From autostart!"); - - updaterName = CurrentExecutablePath(argc, argv); - writeLog("Updater binary full path is: %s", updaterName.c_str()); - if (exePath.empty()) { - writeLog("Executable path is not specified :("); - } else { - writeLog("Executable path: %s", exePath.c_str()); - } - if (updaterName.size() >= 7) { - if (equal(updaterName.substr(updaterName.size() - 7), "Updater")) { - updaterDir = updaterName.substr(0, updaterName.size() - 7); - writeLog("Updater binary dir is: %s", updaterDir.c_str()); - if (exePath.empty()) { - exePath = updaterDir; - writeLog("Using updater binary dir.", exePath.c_str()); - } - if (needupdate) { - if (workDir.empty()) { // old app launched, update prepared in tupdates/ready (not in tupdates/temp) - writeLog("No workdir, trying to figure it out"); - struct passwd *pw = getpwuid(getuid()); - if (pw && pw->pw_dir && strlen(pw->pw_dir)) { - string tryDir = pw->pw_dir + string("/.TelegramDesktop/"); - struct stat statbuf; - writeLog("Trying to use '%s' as workDir, getting stat() for tupdates/ready", tryDir.c_str()); - if (!stat((tryDir + "tupdates/ready").c_str(), &statbuf)) { - writeLog("Stat got"); - if (S_ISDIR(statbuf.st_mode)) { - writeLog("It is directory, using home work dir"); - workDir = tryDir; - } - } - } - if (workDir.empty()) { - workDir = exePath; - - struct stat statbuf; - writeLog("Trying to use current as workDir, getting stat() for tupdates/ready"); - if (!stat("tupdates/ready", &statbuf)) { - writeLog("Stat got"); - if (S_ISDIR(statbuf.st_mode)) { - writeLog("It is directory, using current dir"); - workDir = string(); - } - } - } - } else { - writeLog("Passed workpath is '%s'", workDir.c_str()); - } - update(); - } - } else { - writeLog("Error: bad exe name!"); - } - } else { - writeLog("Error: short exe name!"); - } - - static const int MaxLen = 65536, MaxArgsCount = 128; - - char path[MaxLen] = {0}; - string fullBinaryPath = exePath + exeName; - strcpy(path, fullBinaryPath.c_str()); - - char *args[MaxArgsCount] = {0}, p_noupdate[] = "-noupdate", p_autostart[] = "-autostart", p_debug[] = "-debug", p_tosettings[] = "-tosettings", p_key[] = "-key", p_startintray[] = "-startintray", p_testmode[] = "-testmode"; - int argIndex = 0; - args[argIndex++] = path; - if (crashreport) { - args[argIndex++] = crashreport; - } else { - args[argIndex++] = p_noupdate; - if (autostart) args[argIndex++] = p_autostart; - if (debug) args[argIndex++] = p_debug; - if (startintray) args[argIndex++] = p_startintray; - if (testmode) args[argIndex++] = p_testmode; - if (tosettings) args[argIndex++] = p_tosettings; - if (key) { - args[argIndex++] = p_key; - args[argIndex++] = key; - } - } - pid_t pid = fork(); - switch (pid) { - case -1: writeLog("fork() failed!"); return 1; - case 0: execv(path, args); return 1; - } - - writeLog("Executed Telegram, closing log and quitting.."); - closeLog(); - - return 0; -} diff --git a/Telegram/SourceFiles/_other/updater_osx.m b/Telegram/SourceFiles/_other/updater_osx.m deleted file mode 100644 index b2b9d0b03..000000000 --- a/Telegram/SourceFiles/_other/updater_osx.m +++ /dev/null @@ -1,272 +0,0 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ -#import - -NSString *appName = @"Telegram.app"; -NSString *appDir = nil; -NSString *workDir = nil; -NSString *crashReportArg = nil; - -#ifdef _DEBUG -BOOL _debug = YES; -#else -BOOL _debug = NO; -#endif - -NSFileHandle *_logFile = nil; -void openLog() { - if (!_debug || _logFile) return; - NSString *logDir = [workDir stringByAppendingString:@"DebugLogs"]; - if (![[NSFileManager defaultManager] createDirectoryAtPath:logDir withIntermediateDirectories:YES attributes:nil error:nil]) { - return; - } - - NSDateFormatter *fmt = [[NSDateFormatter alloc] initWithDateFormat:@"DebugLogs/%Y%m%d_%H%M%S_upd.txt" allowNaturalLanguage:NO]; - NSString *logPath = [workDir stringByAppendingString:[fmt stringFromDate:[NSDate date]]]; - [[NSFileManager defaultManager] createFileAtPath:logPath contents:nil attributes:nil]; - _logFile = [NSFileHandle fileHandleForWritingAtPath:logPath]; -} - -void closeLog() { - if (!_logFile) return; - - [_logFile closeFile]; -} - -void writeLog(NSString *msg) { - if (!_logFile) return; - - [_logFile writeData:[[msg stringByAppendingString:@"\n"] dataUsingEncoding:NSUTF8StringEncoding]]; - [_logFile synchronizeFile]; -} - -void delFolder() { - writeLog([@"Fully clearing old path: " stringByAppendingString:[workDir stringByAppendingString:@"tupdates/ready"]]); - if (![[NSFileManager defaultManager] removeItemAtPath:[workDir stringByAppendingString:@"tupdates/ready"] error:nil]) { - writeLog(@"Failed to clear old path! :( New path was used?.."); - } - writeLog([@"Fully clearing new path: " stringByAppendingString:[workDir stringByAppendingString:@"tupdates/temp"]]); - if (![[NSFileManager defaultManager] removeItemAtPath:[workDir stringByAppendingString:@"tupdates/temp"] error:nil]) { - writeLog(@"Error: failed to clear new path! :("); - } - rmdir([[workDir stringByAppendingString:@"tupdates"] fileSystemRepresentation]); -} - -int main(int argc, const char * argv[]) { - NSString *path = [[NSBundle mainBundle] bundlePath]; - if (!path) { - return -1; - } - NSRange range = [path rangeOfString:@".app/" options:NSBackwardsSearch]; - if (range.location == NSNotFound) { - return -1; - } - path = [path substringToIndex:range.location > 0 ? range.location : 0]; - - range = [path rangeOfString:@"/" options:NSBackwardsSearch]; - NSString *appRealName = (range.location == NSNotFound) ? path : [path substringFromIndex:range.location + 1]; - appRealName = [[NSArray arrayWithObjects:appRealName, @".app", nil] componentsJoinedByString:@""]; - appDir = (range.location == NSNotFound) ? @"" : [path substringToIndex:range.location + 1]; - NSString *appDirFull = [appDir stringByAppendingString:appRealName]; - - openLog(); - pid_t procId = 0; - BOOL update = YES, toSettings = NO, autoStart = NO, startInTray = NO, testMode = NO; - NSString *key = nil; - for (int i = 0; i < argc; ++i) { - if ([@"-workpath" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) { - if (++i < argc) { - workDir = [NSString stringWithUTF8String:argv[i]]; - } - } else if ([@"-procid" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) { - if (++i < argc) { - NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; - [formatter setNumberStyle:NSNumberFormatterDecimalStyle]; - procId = [[formatter numberFromString:[NSString stringWithUTF8String:argv[i]]] intValue]; - } - } else if ([@"-crashreport" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) { - if (++i < argc) { - crashReportArg = [NSString stringWithUTF8String:argv[i]]; - } - } else if ([@"-noupdate" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) { - update = NO; - } else if ([@"-tosettings" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) { - toSettings = YES; - } else if ([@"-autostart" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) { - autoStart = YES; - } else if ([@"-debug" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) { - _debug = YES; - } else if ([@"-startintray" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) { - startInTray = YES; - } else if ([@"-testmode" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) { - testMode = YES; - } else if ([@"-key" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) { - if (++i < argc) key = [NSString stringWithUTF8String:argv[i]]; - } - } - if (!workDir) workDir = appDir; - openLog(); - NSMutableArray *argsArr = [[NSMutableArray alloc] initWithCapacity:argc]; - for (int i = 0; i < argc; ++i) { - [argsArr addObject:[NSString stringWithUTF8String:argv[i]]]; - } - writeLog([[NSArray arrayWithObjects:@"Arguments: '", [argsArr componentsJoinedByString:@"' '"], @"'..", nil] componentsJoinedByString:@""]); - if (key) writeLog([@"Key: " stringByAppendingString:key]); - if (toSettings) writeLog(@"To Settings!"); - - if (procId) { - NSRunningApplication *app = [NSRunningApplication runningApplicationWithProcessIdentifier:procId]; - for (int i = 0; i < 5 && app != nil && ![app isTerminated]; ++i) { - usleep(200000); - app = [NSRunningApplication runningApplicationWithProcessIdentifier:procId]; - } - if (app) [app forceTerminate]; - app = [NSRunningApplication runningApplicationWithProcessIdentifier:procId]; - for (int i = 0; i < 5 && app != nil && ![app isTerminated]; ++i) { - usleep(200000); - app = [NSRunningApplication runningApplicationWithProcessIdentifier:procId]; - } - } - - if (update) { - NSFileManager *fileManager = [NSFileManager defaultManager]; - NSString *readyFilePath = [workDir stringByAppendingString:@"tupdates/temp/ready"]; - NSString *srcDir = [workDir stringByAppendingString:@"tupdates/temp/"], *srcEnum = [workDir stringByAppendingString:@"tupdates/temp"]; - if ([fileManager fileExistsAtPath:readyFilePath]) { - writeLog([@"Ready file found! Using new path: " stringByAppendingString: srcEnum]); - } else { - srcDir = [workDir stringByAppendingString:@"tupdates/ready/"]; // old - srcEnum = [workDir stringByAppendingString:@"tupdates/ready"]; - writeLog([@"Ready file not found! Using old path: " stringByAppendingString: srcEnum]); - } - - writeLog([@"Starting update files iteration, path: " stringByAppendingString: srcEnum]); - - // Take the Updater (this currently running binary) from the place where it was placed by Telegram - // and copy it to the folder with the new version of the app (ready), - // so it won't be deleted when we will clear the "Telegram.app/Contents" folder. - NSString *oldVersionUpdaterPath = [appDirFull stringByAppendingString: @"/Contents/Frameworks/Updater" ]; - NSString *newVersionUpdaterPath = [srcEnum stringByAppendingString:[[NSArray arrayWithObjects:@"/", appName, @"/Contents/Frameworks/Updater", nil] componentsJoinedByString:@""]]; - writeLog([[NSArray arrayWithObjects: @"Copying Updater from old path ", oldVersionUpdaterPath, @" to new path ", newVersionUpdaterPath, nil] componentsJoinedByString:@""]); - if (![fileManager fileExistsAtPath:newVersionUpdaterPath]) { - if (![fileManager copyItemAtPath:oldVersionUpdaterPath toPath:newVersionUpdaterPath error:nil]) { - writeLog([[NSArray arrayWithObjects: @"Failed to copy file from ", oldVersionUpdaterPath, @" to ", newVersionUpdaterPath, nil] componentsJoinedByString:@""]); - delFolder(); - return -1; - } - } - - - NSString *contentsPath = [appDirFull stringByAppendingString: @"/Contents"]; - writeLog([[NSArray arrayWithObjects: @"Clearing dir ", contentsPath, nil] componentsJoinedByString:@""]); - if (![fileManager removeItemAtPath:contentsPath error:nil]) { - writeLog([@"Failed to clear path for directory " stringByAppendingString:contentsPath]); - delFolder(); - return -1; - } - - NSArray *keys = [NSArray arrayWithObject:NSURLIsDirectoryKey]; - NSDirectoryEnumerator *enumerator = [fileManager - enumeratorAtURL:[NSURL fileURLWithPath:srcEnum] - includingPropertiesForKeys:keys - options:0 - errorHandler:^(NSURL *url, NSError *error) { - writeLog([[[@"Error in enumerating " stringByAppendingString:[url absoluteString]] stringByAppendingString: @" error is: "] stringByAppendingString: [error description]]); - return NO; - }]; - for (NSURL *url in enumerator) { - NSString *srcPath = [url path]; - writeLog([@"Handling file " stringByAppendingString:srcPath]); - NSRange r = [srcPath rangeOfString:srcDir]; - if (r.location != 0) { - writeLog([@"Bad file found, no base path " stringByAppendingString:srcPath]); - delFolder(); - break; - } - NSString *pathPart = [srcPath substringFromIndex:r.length]; - r = [pathPart rangeOfString:appName]; - if (r.location != 0) { - writeLog([@"Skipping not app file " stringByAppendingString:srcPath]); - continue; - } - NSString *dstPath = [appDirFull stringByAppendingString:[pathPart substringFromIndex:r.length]]; - NSError *error; - NSNumber *isDirectory = nil; - if (![url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:&error]) { - writeLog([@"Failed to get IsDirectory for file " stringByAppendingString:[url path]]); - delFolder(); - break; - } - if ([isDirectory boolValue]) { - writeLog([[NSArray arrayWithObjects: @"Copying dir ", srcPath, @" to ", dstPath, nil] componentsJoinedByString:@""]); - if (![fileManager createDirectoryAtPath:dstPath withIntermediateDirectories:YES attributes:nil error:nil]) { - writeLog([@"Failed to force path for directory " stringByAppendingString:dstPath]); - delFolder(); - break; - } - } else if ([srcPath isEqualToString:readyFilePath]) { - writeLog([[NSArray arrayWithObjects: @"Skipping ready file ", srcPath, nil] componentsJoinedByString:@""]); - } else if ([fileManager fileExistsAtPath:dstPath]) { - if (![[NSData dataWithContentsOfFile:srcPath] writeToFile:dstPath atomically:YES]) { - writeLog([@"Failed to edit file " stringByAppendingString:dstPath]); - delFolder(); - break; - } - } else { - if (![fileManager copyItemAtPath:srcPath toPath:dstPath error:nil]) { - writeLog([@"Failed to copy file to " stringByAppendingString:dstPath]); - delFolder(); - break; - } - } - } - delFolder(); - } - - NSString *appPath = [[NSArray arrayWithObjects:appDir, appRealName, nil] componentsJoinedByString:@""]; - NSMutableArray *args = [[NSMutableArray alloc] initWithObjects: crashReportArg ? crashReportArg : @"-noupdate", nil]; - if (!crashReportArg) { - if (toSettings) [args addObject:@"-tosettings"]; - if (_debug) [args addObject:@"-debug"]; - if (startInTray) [args addObject:@"-startintray"]; - if (testMode) [args addObject:@"-testmode"]; - if (autoStart) [args addObject:@"-autostart"]; - if (key) { - [args addObject:@"-key"]; - [args addObject:key]; - } - } - writeLog([[NSArray arrayWithObjects:@"Running application '", appPath, @"' with args '", [args componentsJoinedByString:@"' '"], @"'..", nil] componentsJoinedByString:@""]); - NSError *error = nil; - NSRunningApplication *result = [[NSWorkspace sharedWorkspace] - launchApplicationAtURL:[NSURL fileURLWithPath:appPath] - options:NSWorkspaceLaunchDefault - configuration:[NSDictionary - dictionaryWithObject:args - forKey:NSWorkspaceLaunchConfigurationArguments] - error:&error]; - if (!result) { - writeLog([@"Could not run application, error: " stringByAppendingString:error ? [error localizedDescription] : @"(nil)"]); - } - closeLog(); - return result ? 0 : -1; -} - diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 72dc4655a..98699ab14 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -1,46 +1,48 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "apiwrap.h" +#include "application.h" +#include "auth_session.h" +#include "base/algorithm.h" // for_each_apply +#include "boxes/confirm_box.h" +#include "chat_helpers/message_field.h" +#include "chat_helpers/stickers.h" #include "data/data_drafts.h" -#include "observer_peer.h" +#include "history/history_widget.h" #include "lang/lang_keys.h" -#include "application.h" +#include "mainwidget.h" #include "mainwindow.h" #include "messenger.h" -#include "mainwidget.h" -#include "history/history_widget.h" +#include "observer_peer.h" #include "storage/localstorage.h" -#include "auth_session.h" -#include "boxes/confirm_box.h" -#include "window/themes/window_theme.h" #include "window/notifications_manager.h" -#include "chat_helpers/message_field.h" -#include "chat_helpers/stickers.h" +#include "window/themes/window_theme.h" namespace { constexpr auto kReloadChannelMembersTimeout = 1000; // 1 second wait before reload members in channel after adding constexpr auto kSaveCloudDraftTimeout = 1000; // save draft to the cloud with 1 sec extra delay -constexpr auto kSaveDraftBeforeQuitTimeout = 1500; // give the app 1.5 secs to save drafts to cloud when quitting constexpr auto kSmallDelayMs = 5; constexpr auto kStickersUpdateTimeout = 3600000; // update not more than once in an hour constexpr auto kUnreadMentionsPreloadIfLess = 5; @@ -49,12 +51,11 @@ constexpr auto kUnreadMentionsNextRequestLimit = 100; } // namespace -ApiWrap::ApiWrap(not_null session) -: _session(session) -, _messageDataResolveDelayed([this] { resolveMessageDatas(); }) -, _webPagesTimer([this] { resolveWebPages(); }) -, _draftsSaveTimer([this] { saveDraftsToCloud(); }) { -} +ApiWrap::ApiWrap(not_null session) + : _session(session) + , _messageDataResolveDelayed([this] { resolveMessageDatas(); }) + , _webPagesTimer([this] { resolveWebPages(); }) + , _draftsSaveTimer([this] { saveDraftsToCloud(); }) {} void ApiWrap::start() { Window::Theme::Background()->start(); @@ -65,24 +66,29 @@ void ApiWrap::requestAppChangelogs() { auto oldAppVersion = Local::oldMapVersion(); if (oldAppVersion > 0 && oldAppVersion < AppVersion) { _changelogSubscription = subscribe(_session->data().moreChatsLoaded(), [this, oldAppVersion] { - auto oldVersionString = qsl("%1.%2.%3").arg(oldAppVersion / 1000000).arg((oldAppVersion % 1000000) / 1000).arg(oldAppVersion % 1000); - request(MTPhelp_GetAppChangelog(MTP_string(oldVersionString))).done([this, oldAppVersion](const MTPUpdates &result) { - applyUpdates(result); - - auto resultEmpty = true; - switch (result.type()) { - case mtpc_updateShortMessage: - case mtpc_updateShortChatMessage: - case mtpc_updateShort: resultEmpty = false; break; - case mtpc_updatesCombined: resultEmpty = result.c_updatesCombined().vupdates.v.isEmpty(); break; - case mtpc_updates: resultEmpty = result.c_updates().vupdates.v.isEmpty(); break; - case mtpc_updatesTooLong: - case mtpc_updateShortSentMessage: LOG(("API Error: Bad updates type in app changelog.")); break; - } - if (resultEmpty) { - addLocalChangelogs(oldAppVersion); - } - }).send(); + auto oldVersionString = qsl("%1.%2.%3") + .arg(oldAppVersion / 1000000) + .arg((oldAppVersion % 1000000) / 1000) + .arg(oldAppVersion % 1000); + request(MTPhelp_GetAppChangelog(MTP_string(oldVersionString))) + .done([this, oldAppVersion](const MTPUpdates &result) { + applyUpdates(result); + + auto resultEmpty = true; + switch (result.type()) { + case mtpc_updateShortMessage: + case mtpc_updateShortChatMessage: + case mtpc_updateShort: resultEmpty = false; break; + case mtpc_updatesCombined: resultEmpty = result.c_updatesCombined().vupdates.v.isEmpty(); break; + case mtpc_updates: resultEmpty = result.c_updates().vupdates.v.isEmpty(); break; + case mtpc_updatesTooLong: + case mtpc_updateShortSentMessage: LOG(("API Error: Bad updates type in app changelog.")); break; + } + if (resultEmpty) { + addLocalChangelogs(oldAppVersion); + } + }) + .send(); unsubscribe(base::take(_changelogSubscription)); }); } @@ -90,38 +96,19 @@ void ApiWrap::requestAppChangelogs() { void ApiWrap::addLocalChangelogs(int oldAppVersion) { auto addedSome = false; - auto addLocalChangelog = [this, &addedSome](const QString &text) { - auto textWithEntities = TextWithEntities { text }; + auto addLocalChangelog = [&addedSome](const QString &text) { + auto textWithEntities = TextWithEntities{text}; TextUtilities::ParseEntities(textWithEntities, TextParseLinks); App::wnd()->serviceNotification(textWithEntities, MTP_messageMediaEmpty(), unixtime()); addedSome = true; }; - if (cAlphaVersion() || cBetaVersion()) { - auto addLocalAlphaChangelog = [this, oldAppVersion, addLocalChangelog](int changeVersion, const char *changes) { - if (oldAppVersion < changeVersion) { - auto changeVersionString = QString::number(changeVersion / 1000000) + '.' + QString::number((changeVersion % 1000000) / 1000) + ((changeVersion % 1000) ? ('.' + QString::number(changeVersion % 1000)) : QString()); - auto text = qsl("New in version %1:\n\n").arg(changeVersionString) + QString::fromUtf8(changes).trimmed(); - addLocalChangelog(text); - } - }; - addLocalAlphaChangelog(1001008, "\xE2\x80\x94 Toggle night mode in the main menu.\n"); - addLocalAlphaChangelog(1001010, "\xE2\x80\x94 Filter added to channel and supergroup event log.\n\xE2\x80\x94 Search by username in privacy exceptions editor fixed.\n\xE2\x80\x94 Adding admins in channels fixed."); - addLocalAlphaChangelog(1001011, "\xE2\x80\x94 Send **bold** and __italic__ text in your messages (in addition to already supported `monospace` and ```multiline monospace```).\n\xE2\x80\x94 Search in channel and supergroup admin event log.\n\xE2\x80\x94 Ban members from right click menu in supergroup admin event log."); - addLocalAlphaChangelog(1001012, "\xE2\x80\x94 Click on forwarded messages bar to change the recipient chat in case you chose a wrong one first.\n\xE2\x80\x94 Quickly share posts from channels and media messages from bots.\n\xE2\x80\x94 Search in large supergroup members by name.\n\xE2\x80\x94 Search in channel members by name if you're a channel admin.\n\xE2\x80\x94 Copy links to messages in public supergroups."); - addLocalAlphaChangelog(1001014, "\xE2\x80\x94 Bug fixes and other minor improvements."); -#ifdef Q_OS_WIN - addLocalAlphaChangelog(1001023, "\xE2\x80\x94 See the message author photo and name while searching specific chat messages.\n\xE2\x80\x94 Fix \"Send To\" menu action on Windows."); -#else // Q_OS_WIN - addLocalAlphaChangelog(1001023, "\xE2\x80\x94 See the message author photo and name while searching specific chat messages."); -#endif // Q_OS_WIN - } - if (!addedSome) { - auto text = lng_new_version_wrap(lt_version, str_const_toString(AppVersionStr), lt_changes, lang(lng_new_version_minor), lt_link, qsl("https://desktop.telegram.org/changelog")).trimmed(); - addLocalChangelog(text); - } + auto text = lng_new_version_wrap(lt_version, str_const_toString(AppVersionStr), lt_changes, + lang(lng_new_version_minor), lt_link, lang(lng_url_changelog)) + .trimmed(); + addLocalChangelog(text); } -void ApiWrap::applyUpdates(const MTPUpdates &updates, uint64 sentMessageRandomId) { +void ApiWrap::applyUpdates(const MTPUpdates &updates, quint64 sentMessageRandomId) { App::main()->feedUpdates(updates, sentMessageRandomId); } @@ -160,9 +147,12 @@ void ApiWrap::resolveMessageDatas() { auto ids = collectMessageIds(_messageDataRequests); if (!ids.isEmpty()) { - auto requestId = request(MTPmessages_GetMessages(MTP_vector(ids))).done([this](const MTPmessages_Messages &result, mtpRequestId requestId) { - gotMessageDatas(nullptr, result, requestId); - }).after(kSmallDelayMs).send(); + auto requestId = request(MTPmessages_GetMessages(MTP_vector(ids))) + .done([this](const MTPmessages_Messages &result, mtpRequestId requestId) { + gotMessageDatas(nullptr, result, requestId); + }) + .after(kSmallDelayMs) + .send(); for (auto &request : _messageDataRequests) { if (request.requestId > 0) continue; request.requestId = requestId; @@ -175,9 +165,13 @@ void ApiWrap::resolveMessageDatas() { } auto ids = collectMessageIds(j.value()); if (!ids.isEmpty()) { - auto requestId = request(MTPchannels_GetMessages(j.key()->inputChannel, MTP_vector(ids))).done([this, channel = j.key()](const MTPmessages_Messages &result, mtpRequestId requestId) { - gotMessageDatas(channel, result, requestId); - }).after(kSmallDelayMs).send(); + auto requestId = + request(MTPchannels_GetMessages(j.key()->inputChannel, MTP_vector(ids))) + .done([this, channel = j.key()](const MTPmessages_Messages &result, mtpRequestId requestId) { + gotMessageDatas(channel, result, requestId); + }) + .after(kSmallDelayMs) + .send(); for (auto &request : *j) { if (request.requestId > 0) continue; @@ -209,7 +203,9 @@ void ApiWrap::gotMessageDatas(ChannelData *channel, const MTPmessages_Messages & if (channel) { channel->ptsReceived(d.vpts.v); } else { - LOG(("App Error: received messages.channelMessages when no channel was passed! (ApiWrap::gotDependencyItem)")); + LOG( + ("App Error: received messages.channelMessages when no channel was passed! " + "(ApiWrap::gotDependencyItem)")); } App::feedUsers(d.vusers); App::feedChats(d.vchats); @@ -220,9 +216,7 @@ void ApiWrap::gotMessageDatas(ChannelData *channel, const MTPmessages_Messages & if (requests) { for (auto i = requests->begin(); i != requests->cend();) { if (i.value().requestId == requestId) { - for_const (auto &callback, i.value().callbacks) { - callback(channel, i.key()); - } + for_const (auto &callback, i.value().callbacks) { callback(channel, i.key()); } i = requests->erase(i); } else { ++i; @@ -238,21 +232,28 @@ void ApiWrap::requestFullPeer(PeerData *peer) { if (!peer || _fullPeerRequests.contains(peer)) return; auto sendRequest = [this, peer] { - auto failHandler = [this, peer](const RPCError &error) { - _fullPeerRequests.remove(peer); - }; + auto failHandler = [this, peer](const RPCError &error) { _fullPeerRequests.remove(peer); }; if (auto user = peer->asUser()) { - return request(MTPusers_GetFullUser(user->inputUser)).done([this, user](const MTPUserFull &result, mtpRequestId requestId) { - gotUserFull(user, result, requestId); - }).fail(failHandler).send(); + return request(MTPusers_GetFullUser(user->inputUser)) + .done([this, user](const MTPUserFull &result, mtpRequestId requestId) { + gotUserFull(user, result, requestId); + }) + .fail(failHandler) + .send(); } else if (auto chat = peer->asChat()) { - return request(MTPmessages_GetFullChat(chat->inputChat)).done([this, peer](const MTPmessages_ChatFull &result, mtpRequestId requestId) { - gotChatFull(peer, result, requestId); - }).fail(failHandler).send(); + return request(MTPmessages_GetFullChat(chat->inputChat)) + .done([this, peer](const MTPmessages_ChatFull &result, mtpRequestId requestId) { + gotChatFull(peer, result, requestId); + }) + .fail(failHandler) + .send(); } else if (auto channel = peer->asChannel()) { - return request(MTPchannels_GetFullChannel(channel->inputChannel)).done([this, peer](const MTPmessages_ChatFull &result, mtpRequestId requestId) { - gotChatFull(peer, result, requestId); - }).fail(failHandler).send(); + return request(MTPchannels_GetFullChannel(channel->inputChannel)) + .done([this, peer](const MTPmessages_ChatFull &result, mtpRequestId requestId) { + gotChatFull(peer, result, requestId); + }) + .fail(failHandler) + .send(); } return 0; }; @@ -274,9 +275,11 @@ void ApiWrap::gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mt auto &vc = d.vchats.v; auto badVersion = false; if (peer->isChat()) { - badVersion = (!vc.isEmpty() && vc[0].type() == mtpc_chat && vc[0].c_chat().vversion.v < peer->asChat()->version); + badVersion = + (!vc.isEmpty() && vc[0].type() == mtpc_chat && vc[0].c_chat().vversion.v < peer->asChat()->version); } else if (peer->isChannel()) { - badVersion = (!vc.isEmpty() && vc[0].type() == mtpc_channel && vc[0].c_channel().vversion.v < peer->asChannel()->version); + badVersion = (!vc.isEmpty() && vc[0].type() == mtpc_channel && + vc[0].c_channel().vversion.v < peer->asChannel()->version); } App::feedUsers(d.vusers); @@ -307,7 +310,9 @@ void ApiWrap::gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mt } else { chat->photoId = 0; } - chat->setInviteLink((f.vexported_invite.type() == mtpc_chatInviteExported) ? qs(f.vexported_invite.c_chatInviteExported().vlink) : QString()); + chat->setInviteLink((f.vexported_invite.type() == mtpc_chatInviteExported) ? + qs(f.vexported_invite.c_chatInviteExported().vlink) : + QString()); chat->fullUpdated(); notifySettingReceived(MTP_inputNotifyPeer(peer->input), f.vnotify_settings); @@ -374,7 +379,9 @@ void ApiWrap::gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mt channel->setAdminsCount(f.has_admins_count() ? f.vadmins_count.v : 0); channel->setRestrictedCount(f.has_banned_count() ? f.vbanned_count.v : 0); channel->setKickedCount(f.has_kicked_count() ? f.vkicked_count.v : 0); - channel->setInviteLink((f.vexported_invite.type() == mtpc_chatInviteExported) ? qs(f.vexported_invite.c_chatInviteExported().vlink) : QString()); + channel->setInviteLink((f.vexported_invite.type() == mtpc_chatInviteExported) ? + qs(f.vexported_invite.c_chatInviteExported().vlink) : + QString()); if (auto h = App::historyLoaded(channel->id)) { if (h->inboxReadBefore < f.vread_inbox_max_id.v + 1) { h->setUnreadCount(f.vunread_count.v); @@ -382,19 +389,22 @@ void ApiWrap::gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mt } accumulate_max(h->outboxReadBefore, f.vread_outbox_max_id.v + 1); } + if (f.has_pinned_msg_id()) { + channel->setPinnedMessageId(f.vpinned_msg_id.v); + } else { + channel->clearPinnedMessage(); + } if (channel->isMegagroup()) { - if (f.has_pinned_msg_id()) { - channel->mgInfo->pinnedMsgId = f.vpinned_msg_id.v; - } else { - channel->mgInfo->pinnedMsgId = 0; - } - auto stickersChanged = (canEditStickers != channel->canEditStickers()); auto stickerSet = (f.has_stickerset() ? &f.vstickerset.c_stickerSet() : nullptr); auto newSetId = (stickerSet ? stickerSet->vid.v : 0); - auto oldSetId = (channel->mgInfo->stickerSet.type() == mtpc_inputStickerSetID) ? channel->mgInfo->stickerSet.c_inputStickerSetID().vid.v : 0; + auto oldSetId = (channel->mgInfo->stickerSet.type() == mtpc_inputStickerSetID) ? + channel->mgInfo->stickerSet.c_inputStickerSetID().vid.v : + 0; if (oldSetId != newSetId) { - channel->mgInfo->stickerSet = stickerSet ? MTP_inputStickerSetID(stickerSet->vid, stickerSet->vaccess_hash) : MTP_inputStickerSetEmpty(); + channel->mgInfo->stickerSet = stickerSet ? + MTP_inputStickerSetID(stickerSet->vid, stickerSet->vaccess_hash) : + MTP_inputStickerSetEmpty(); stickersChanged = true; } if (stickersChanged) { @@ -403,8 +413,7 @@ void ApiWrap::gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mt } channel->fullUpdated(); - if (canViewAdmins != channel->canViewAdmins() - || canViewMembers != channel->canViewMembers()) { + if (canViewAdmins != channel->canViewAdmins() || canViewMembers != channel->canViewMembers()) { Notify::peerUpdatedDelayed(channel, Notify::PeerUpdate::Flag::ChannelRightsChanged); } @@ -434,7 +443,8 @@ void ApiWrap::gotUserFull(UserData *user, const MTPUserFull &result, mtpRequestI if (d.has_profile_photo()) { App::feedPhoto(d.vprofile_photo); } - App::feedUserLink(MTP_int(peerToUser(user->id)), d.vlink.c_contacts_link().vmy_link, d.vlink.c_contacts_link().vforeign_link); + App::feedUserLink(MTP_int(peerToUser(user->id)), d.vlink.c_contacts_link().vmy_link, + d.vlink.c_contacts_link().vforeign_link); if (App::main()) { notifySettingReceived(MTP_inputNotifyPeer(user->input), d.vnotify_settings); } @@ -445,7 +455,9 @@ void ApiWrap::gotUserFull(UserData *user, const MTPUserFull &result, mtpRequestI user->setBotInfoVersion(-1); } user->setBlockStatus(d.is_blocked() ? UserData::BlockStatus::Blocked : UserData::BlockStatus::NotBlocked); - user->setCallsStatus(d.is_phone_calls_private() ? UserData::CallsStatus::Private : d.is_phone_calls_available() ? UserData::CallsStatus::Enabled : UserData::CallsStatus::Disabled); + user->setCallsStatus(d.is_phone_calls_private() ? UserData::CallsStatus::Private : + d.is_phone_calls_available() ? UserData::CallsStatus::Enabled : + UserData::CallsStatus::Disabled); user->setAbout(d.has_about() ? qs(d.vabout) : QString()); user->setCommonChatsCount(d.vcommon_chats_count.v); user->fullUpdated(); @@ -463,9 +475,7 @@ void ApiWrap::requestPeer(PeerData *peer) { if (!peer || _fullPeerRequests.contains(peer) || _peerRequests.contains(peer)) return; auto sendRequest = [this, peer] { - auto failHandler = [this, peer](const RPCError &error) { - _peerRequests.remove(peer); - }; + auto failHandler = [this, peer](const RPCError &error) { _peerRequests.remove(peer); }; auto chatHandler = [this, peer](const MTPmessages_Chats &result) { _peerRequests.remove(peer); @@ -475,7 +485,8 @@ void ApiWrap::requestPeer(PeerData *peer) { if (auto chat = peer->asChat()) { badVersion = (!v.isEmpty() && v[0].type() == mtpc_chat && v[0].c_chat().vversion.v < chat->version); } else if (auto channel = peer->asChannel()) { - badVersion = (!v.isEmpty() && v[0].type() == mtpc_channel && v[0].c_channel().vversion.v < channel->version); + badVersion = + (!v.isEmpty() && v[0].type() == mtpc_channel && v[0].c_channel().vversion.v < channel->version); } auto chat = App::feedChats(*chats); if (chat == peer) { @@ -491,14 +502,23 @@ void ApiWrap::requestPeer(PeerData *peer) { } }; if (auto user = peer->asUser()) { - return request(MTPusers_GetUsers(MTP_vector(1, user->inputUser))).done([this, user](const MTPVector &result) { - _peerRequests.remove(user); - App::feedUsers(result); - }).fail(failHandler).send(); + return request(MTPusers_GetUsers(MTP_vector(1, user->inputUser))) + .done([this, user](const MTPVector &result) { + _peerRequests.remove(user); + App::feedUsers(result); + }) + .fail(failHandler) + .send(); } else if (auto chat = peer->asChat()) { - return request(MTPmessages_GetChats(MTP_vector(1, chat->inputChat))).done(chatHandler).fail(failHandler).send(); + return request(MTPmessages_GetChats(MTP_vector(1, chat->inputChat))) + .done(chatHandler) + .fail(failHandler) + .send(); } else if (auto channel = peer->asChannel()) { - return request(MTPchannels_GetChannels(MTP_vector(1, channel->inputChannel))).done(chatHandler).fail(failHandler).send(); + return request(MTPchannels_GetChannels(MTP_vector(1, channel->inputChannel))) + .done(chatHandler) + .fail(failHandler) + .send(); } return 0; }; @@ -507,14 +527,14 @@ void ApiWrap::requestPeer(PeerData *peer) { } } -void ApiWrap::requestPeers(const QList &peers) { +void ApiWrap::requestPeers(const QList &peers) { QVector chats; QVector channels; QVector users; chats.reserve(peers.size()); channels.reserve(peers.size()); users.reserve(peers.size()); - for (QList::const_iterator i = peers.cbegin(), e = peers.cend(); i != e; ++i) { + for (QList::const_iterator i = peers.cbegin(), e = peers.cend(); i != e; ++i) { if (!*i || _fullPeerRequests.contains(*i) || _peerRequests.contains(*i)) continue; if ((*i)->isUser()) { users.push_back((*i)->asUser()->inputUser); @@ -524,7 +544,7 @@ void ApiWrap::requestPeers(const QList &peers) { channels.push_back((*i)->asChannel()->inputChannel); } } - auto handleChats = [this](const MTPmessages_Chats &result) { + auto handleChats = [](const MTPmessages_Chats &result) { if (auto chats = Api::getChatsFromMessagesChats(result)) { App::feedChats(*chats); } @@ -536,9 +556,9 @@ void ApiWrap::requestPeers(const QList &peers) { request(MTPchannels_GetChannels(MTP_vector(channels))).done(handleChats).send(); } if (!users.isEmpty()) { - request(MTPusers_GetUsers(MTP_vector(users))).done([this](const MTPVector &result) { - App::feedUsers(result); - }).send(); + request(MTPusers_GetUsers(MTP_vector(users))) + .done([](const MTPVector &result) { App::feedUsers(result); }) + .send(); } } @@ -548,7 +568,8 @@ void ApiWrap::requestLastParticipants(ChannelData *channel, bool fromStart) { } auto needAdmins = channel->canViewAdmins(); - auto adminsOutdated = (channel->mgInfo->lastParticipantsStatus & MegagroupInfo::LastParticipantsAdminsOutdated) != 0; + auto adminsOutdated = + (channel->mgInfo->lastParticipantsStatus & MegagroupInfo::LastParticipantsAdminsOutdated) != 0; if ((needAdmins && adminsOutdated) || channel->lastParticipantsCountOutdated()) { fromStart = true; } @@ -561,13 +582,20 @@ void ApiWrap::requestLastParticipants(ChannelData *channel, bool fromStart) { } } - auto requestId = request(MTPchannels_GetParticipants(channel->inputChannel, MTP_channelParticipantsRecent(), MTP_int(fromStart ? 0 : channel->mgInfo->lastParticipants.size()), MTP_int(Global::ChatSizeMax()))).done([this, channel](const MTPchannels_ChannelParticipants &result, mtpRequestId requestId) { - lastParticipantsDone(channel, result, requestId); - }).fail([this, channel](const RPCError &error, mtpRequestId requestId) { - if (_participantsRequests.value(channel) == requestId || _participantsRequests.value(channel) == -requestId) { - _participantsRequests.remove(channel); - } - }).send(); + auto requestId = + request(MTPchannels_GetParticipants(channel->inputChannel, MTP_channelParticipantsRecent(), + MTP_int(fromStart ? 0 : channel->mgInfo->lastParticipants.size()), + MTP_int(Global::ChatSizeMax()), MTP_int(0))) + .done([this, channel](const MTPchannels_ChannelParticipants &result, mtpRequestId requestId) { + lastParticipantsDone(channel, result, requestId); + }) + .fail([this, channel](const RPCError &error, mtpRequestId requestId) { + if (_participantsRequests.value(channel) == requestId || + _participantsRequests.value(channel) == -requestId) { + _participantsRequests.remove(channel); + } + }) + .send(); _participantsRequests.insert(channel, fromStart ? requestId : -requestId); } @@ -577,18 +605,23 @@ void ApiWrap::requestBots(ChannelData *channel) { return; } - auto requestId = request(MTPchannels_GetParticipants(channel->inputChannel, MTP_channelParticipantsBots(), MTP_int(0), MTP_int(Global::ChatSizeMax()))).done([this, channel](const MTPchannels_ChannelParticipants &result, mtpRequestId requestId) { - lastParticipantsDone(channel, result, requestId); - }).fail([this, channel](const RPCError &error, mtpRequestId requestId) { - if (_botsRequests.value(channel) == requestId) { - _botsRequests.remove(channel); - } - }).send(); + auto requestId = request(MTPchannels_GetParticipants(channel->inputChannel, MTP_channelParticipantsBots(), + MTP_int(0), MTP_int(Global::ChatSizeMax()), MTP_int(0))) + .done([this, channel](const MTPchannels_ChannelParticipants &result, mtpRequestId requestId) { + lastParticipantsDone(channel, result, requestId); + }) + .fail([this, channel](const RPCError &error, mtpRequestId requestId) { + if (_botsRequests.value(channel) == requestId) { + _botsRequests.remove(channel); + } + }) + .send(); _botsRequests.insert(channel, requestId); } -void ApiWrap::lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelParticipants &result, mtpRequestId requestId) { +void ApiWrap::lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelParticipants &result, + mtpRequestId requestId) { bool bots = (_botsRequests.value(peer) == requestId), fromStart = false; if (bots) { _botsRequests.remove(peer); @@ -637,11 +670,11 @@ void ApiWrap::lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelP userId = participant.c_channelParticipantAdmin().vuser_id.v; adminCanEdit = participant.c_channelParticipantAdmin().is_can_edit(); adminRights = participant.c_channelParticipantAdmin().vadmin_rights; - break; + break; case mtpc_channelParticipantBanned: userId = participant.c_channelParticipantBanned().vuser_id.v; restrictedRights = participant.c_channelParticipantBanned().vbanned_rights; - break; + break; case mtpc_channelParticipantCreator: userId = participant.c_channelParticipantCreator().vuser_id.v; break; } if (!userId) { @@ -655,7 +688,7 @@ void ApiWrap::lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelP if (bots) { if (u->botInfo) { peer->mgInfo->bots.insert(u); - botStatus = 2;// (botStatus > 0/* || !i.key()->botInfo->readsAllHistory*/) ? 2 : 1; + botStatus = 2; // (botStatus > 0/* || !i.key()->botInfo->readsAllHistory*/) ? 2 : 1; if (!u->botInfo->inited) { needBotsInfos = true; } @@ -667,9 +700,9 @@ void ApiWrap::lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelP if (peer->mgInfo->lastParticipants.indexOf(u) < 0) { peer->mgInfo->lastParticipants.push_back(u); if (adminRights.c_channelAdminRights().vflags.v) { - peer->mgInfo->lastAdmins.insert(u, MegagroupInfo::Admin { adminRights, adminCanEdit }); + peer->mgInfo->lastAdmins.insert(u, MegagroupInfo::Admin{adminRights, adminCanEdit}); } else if (restrictedRights.c_channelBannedRights().vflags.v != 0) { - peer->mgInfo->lastRestricted.insert(u, MegagroupInfo::Restricted { restrictedRights }); + peer->mgInfo->lastRestricted.insert(u, MegagroupInfo::Restricted{restrictedRights}); } if (u->botInfo) { peer->mgInfo->bots.insert(u); @@ -687,7 +720,7 @@ void ApiWrap::lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelP if (!keyboardBotFound) { h->clearLastKeyboard(); } - int newMembersCount = qMax(d.vcount.v, v.count()); + int newMembersCount = std::max(d.vcount.v, v.count()); if (newMembersCount > peer->membersCount()) { peer->setMembersCount(newMembersCount); } @@ -709,46 +742,50 @@ void ApiWrap::requestSelfParticipant(ChannelData *channel) { return; } - auto requestId = request(MTPchannels_GetParticipant(channel->inputChannel, MTP_inputUserSelf())).done([this, channel](const MTPchannels_ChannelParticipant &result) { - _selfParticipantRequests.remove(channel); - if (result.type() != mtpc_channels_channelParticipant) { - LOG(("API Error: unknown type in gotSelfParticipant (%1)").arg(result.type())); - channel->inviter = -1; - if (App::main()) App::main()->onSelfParticipantUpdated(channel); - return; - } - - auto &p = result.c_channels_channelParticipant(); - App::feedUsers(p.vusers); - - switch (p.vparticipant.type()) { - case mtpc_channelParticipantSelf: { - auto &d = p.vparticipant.c_channelParticipantSelf(); - channel->inviter = d.vinviter_id.v; - channel->inviteDate = date(d.vdate); - } break; - case mtpc_channelParticipantCreator: { - auto &d = p.vparticipant.c_channelParticipantCreator(); - channel->inviter = _session->userId(); - channel->inviteDate = date(MTP_int(channel->date)); - if (channel->mgInfo) { - channel->mgInfo->creator = App::self(); - } - } break; - case mtpc_channelParticipantAdmin: { - auto &d = p.vparticipant.c_channelParticipantAdmin(); - channel->inviter = d.vinviter_id.v; - channel->inviteDate = date(d.vdate); - } break; - } - - if (App::main()) App::main()->onSelfParticipantUpdated(channel); - }).fail([this, channel](const RPCError &error) { - _selfParticipantRequests.remove(channel); - if (error.type() == qstr("USER_NOT_PARTICIPANT")) { - channel->inviter = -1; - } - }).after(kSmallDelayMs).send(); + auto requestId = request(MTPchannels_GetParticipant(channel->inputChannel, MTP_inputUserSelf())) + .done([this, channel](const MTPchannels_ChannelParticipant &result) { + _selfParticipantRequests.remove(channel); + if (result.type() != mtpc_channels_channelParticipant) { + LOG(("API Error: unknown type in gotSelfParticipant (%1)").arg(result.type())); + channel->inviter = -1; + if (App::main()) App::main()->onSelfParticipantUpdated(channel); + return; + } + + auto &p = result.c_channels_channelParticipant(); + App::feedUsers(p.vusers); + + switch (p.vparticipant.type()) { + case mtpc_channelParticipantSelf: { + auto &d = p.vparticipant.c_channelParticipantSelf(); + channel->inviter = d.vinviter_id.v; + channel->inviteDate = date(d.vdate); + } break; + case mtpc_channelParticipantCreator: { + auto &d = p.vparticipant.c_channelParticipantCreator(); + channel->inviter = _session->userId(); + channel->inviteDate = date(MTP_int(channel->date)); + if (channel->mgInfo) { + channel->mgInfo->creator = App::self(); + } + } break; + case mtpc_channelParticipantAdmin: { + auto &d = p.vparticipant.c_channelParticipantAdmin(); + channel->inviter = d.vinviter_id.v; + channel->inviteDate = date(d.vdate); + } break; + } + + if (App::main()) App::main()->onSelfParticipantUpdated(channel); + }) + .fail([this, channel](const RPCError &error) { + _selfParticipantRequests.remove(channel); + if (error.type() == qstr("USER_NOT_PARTICIPANT")) { + channel->inviter = -1; + } + }) + .after(kSmallDelayMs) + .send(); _selfParticipantRequests.insert(channel, requestId); } @@ -759,14 +796,15 @@ void ApiWrap::kickParticipant(PeerData *peer, UserData *user, const MTPChannelBa if (auto channel = peer->asChannel()) { auto rights = ChannelData::KickedRestrictedRights(); - auto requestId = request(MTPchannels_EditBanned(channel->inputChannel, user->inputUser, rights)).done([this, channel, user, currentRights, rights](const MTPUpdates &result) { - applyUpdates(result); + auto requestId = request(MTPchannels_EditBanned(channel->inputChannel, user->inputUser, rights)) + .done([this, channel, user, currentRights, rights](const MTPUpdates &result) { + applyUpdates(result); - _kickRequests.remove(KickRequest(channel, user)); - channel->applyEditBanned(user, currentRights, rights); - }).fail([this, kick](const RPCError &error) { - _kickRequests.remove(kick); - }).send(); + _kickRequests.remove(KickRequest(channel, user)); + channel->applyEditBanned(user, currentRights, rights); + }) + .fail([this, kick](const RPCError &error) { _kickRequests.remove(kick); }) + .send(); _kickRequests.insert(kick, requestId); } @@ -777,26 +815,28 @@ void ApiWrap::unblockParticipant(PeerData *peer, UserData *user) { if (_kickRequests.contains(kick)) return; if (auto channel = peer->asChannel()) { - auto requestId = request(MTPchannels_EditBanned(channel->inputChannel, user->inputUser, MTP_channelBannedRights(MTP_flags(0), MTP_int(0)))).done([this, peer, user](const MTPUpdates &result) { - applyUpdates(result); - - _kickRequests.remove(KickRequest(peer, user)); - if (auto channel = peer->asMegagroup()) { - if (channel->kickedCount() > 0) { - channel->setKickedCount(channel->kickedCount() - 1); - } else { - channel->updateFullForced(); - } - } - }).fail([this, kick](const RPCError &error) { - _kickRequests.remove(kick); - }).send(); + auto requestId = request(MTPchannels_EditBanned(channel->inputChannel, user->inputUser, + MTP_channelBannedRights(MTP_flags(0), MTP_int(0)))) + .done([this, peer, user](const MTPUpdates &result) { + applyUpdates(result); + + _kickRequests.remove(KickRequest(peer, user)); + if (auto channel = peer->asMegagroup()) { + if (channel->kickedCount() > 0) { + channel->setKickedCount(channel->kickedCount() - 1); + } else { + channel->updateFullForced(); + } + } + }) + .fail([this, kick](const RPCError &error) { _kickRequests.remove(kick); }) + .send(); _kickRequests.insert(kick, requestId); } } -void ApiWrap::scheduleStickerSetRequest(uint64 setId, uint64 access) { +void ApiWrap::scheduleStickerSetRequest(quint64 setId, quint64 access) { if (!_stickerSetRequests.contains(setId)) { _stickerSetRequests.insert(setId, qMakePair(access, 0)); } @@ -808,11 +848,12 @@ void ApiWrap::requestStickerSets() { if (i.value().second) continue; auto waitMs = (j == e) ? 0 : kSmallDelayMs; - i.value().second = request(MTPmessages_GetStickerSet(MTP_inputStickerSetID(MTP_long(i.key()), MTP_long(i.value().first)))).done([this, setId = i.key()](const MTPmessages_StickerSet &result) { - gotStickerSet(setId, result); - }).fail([this, setId = i.key()](const RPCError &error) { - _stickerSetRequests.remove(setId); - }).after(waitMs).send(); + i.value().second = + request(MTPmessages_GetStickerSet(MTP_inputStickerSetID(MTP_long(i.key()), MTP_long(i.value().first)))) + .done([this, setId = i.key()](const MTPmessages_StickerSet &result) { gotStickerSet(setId, result); }) + .fail([this, setId = i.key()](const RPCError &error) { _stickerSetRequests.remove(setId); }) + .after(waitMs) + .send(); } } @@ -823,7 +864,8 @@ void ApiWrap::saveStickerSets(const Stickers::Order &localOrder, const Stickers: request(base::take(_stickersReorderRequestId)).cancel(); request(base::take(_stickersClearRecentRequestId)).cancel(); - auto writeInstalled = true, writeRecent = false, writeCloudRecent = false, writeFaved = false, writeArchived = false; + auto writeInstalled = true, writeRecent = false, writeCloudRecent = false, writeFaved = false, + writeArchived = false; auto &recent = cGetRecentStickers(); auto &sets = Global::RefStickerSets(); @@ -841,11 +883,11 @@ void ApiWrap::saveStickerSets(const Stickers::Order &localOrder, const Stickers: writeRecent = true; } - _stickersClearRecentRequestId = request(MTPmessages_ClearRecentStickers(MTP_flags(0))).done([this](const MTPBool &result) { - _stickersClearRecentRequestId = 0; - }).fail([this](const RPCError &error) { - _stickersClearRecentRequestId = 0; - }).send(); + _stickersClearRecentRequestId = + request(MTPmessages_ClearRecentStickers(MTP_flags(0))) + .done([this](const MTPBool &result) { _stickersClearRecentRequestId = 0; }) + .fail([this](const RPCError &error) { _stickersClearRecentRequestId = 0; }) + .send(); continue; } @@ -860,19 +902,26 @@ void ApiWrap::saveStickerSets(const Stickers::Order &localOrder, const Stickers: } } if (!(it->flags & MTPDstickerSet::Flag::f_archived)) { - MTPInputStickerSet setId = (it->id && it->access) ? MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access)) : MTP_inputStickerSetShortName(MTP_string(it->shortName)); - - auto requestId = request(MTPmessages_UninstallStickerSet(setId)).done([this](const MTPBool &result, mtpRequestId requestId) { - stickerSetDisenabled(requestId); - }).fail([this](const RPCError &error, mtpRequestId requestId) { - stickerSetDisenabled(requestId); - }).after(kSmallDelayMs).send(); + MTPInputStickerSet setId = (it->id && it->access) ? + MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access)) : + MTP_inputStickerSetShortName(MTP_string(it->shortName)); + + auto requestId = request(MTPmessages_UninstallStickerSet(setId)) + .done([this](const MTPBool &result, mtpRequestId requestId) { + stickerSetDisenabled(requestId); + }) + .fail([this](const RPCError &error, mtpRequestId requestId) { + stickerSetDisenabled(requestId); + }) + .after(kSmallDelayMs) + .send(); _stickerSetDisenableRequests.insert(requestId); int removeIndex = Global::StickerSetsOrder().indexOf(it->id); if (removeIndex >= 0) Global::RefStickerSetsOrder().removeAt(removeIndex); - if (!(it->flags & MTPDstickerSet_ClientFlag::f_featured) && !(it->flags & MTPDstickerSet_ClientFlag::f_special)) { + if (!(it->flags & MTPDstickerSet_ClientFlag::f_featured) && + !(it->flags & MTPDstickerSet_ClientFlag::f_special)) { sets.erase(it); } else { if (it->flags & MTPDstickerSet::Flag::f_archived) { @@ -897,13 +946,18 @@ void ApiWrap::saveStickerSets(const Stickers::Order &localOrder, const Stickers: auto it = sets.find(setId); if (it != sets.cend()) { if ((it->flags & MTPDstickerSet::Flag::f_archived) && !localRemoved.contains(it->id)) { - MTPInputStickerSet mtpSetId = (it->id && it->access) ? MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access)) : MTP_inputStickerSetShortName(MTP_string(it->shortName)); - - auto requestId = request(MTPmessages_InstallStickerSet(mtpSetId, MTP_boolFalse())).done([this](const MTPmessages_StickerSetInstallResult &result, mtpRequestId requestId) { - stickerSetDisenabled(requestId); - }).fail([this](const RPCError &error, mtpRequestId requestId) { - stickerSetDisenabled(requestId); - }).after(kSmallDelayMs).send(); + MTPInputStickerSet mtpSetId = (it->id && it->access) ? + MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access)) : + MTP_inputStickerSetShortName(MTP_string(it->shortName)); + + auto requestId = request(MTPmessages_InstallStickerSet(mtpSetId, MTP_boolFalse())) + .done([this](const MTPmessages_StickerSetInstallResult &result, + mtpRequestId requestId) { stickerSetDisenabled(requestId); }) + .fail([this](const RPCError &error, mtpRequestId requestId) { + stickerSetDisenabled(requestId); + }) + .after(kSmallDelayMs) + .send(); _stickerSetDisenableRequests.insert(requestId); @@ -915,10 +969,8 @@ void ApiWrap::saveStickerSets(const Stickers::Order &localOrder, const Stickers: } } for (auto it = sets.begin(); it != sets.cend();) { - if ((it->flags & MTPDstickerSet_ClientFlag::f_featured) - || (it->flags & MTPDstickerSet::Flag::f_installed) - || (it->flags & MTPDstickerSet::Flag::f_archived) - || (it->flags & MTPDstickerSet_ClientFlag::f_special)) { + if ((it->flags & MTPDstickerSet_ClientFlag::f_featured) || (it->flags & MTPDstickerSet::Flag::f_installed) || + (it->flags & MTPDstickerSet::Flag::f_archived) || (it->flags & MTPDstickerSet_ClientFlag::f_special)) { ++it; } else { it = sets.erase(it); @@ -932,7 +984,7 @@ void ApiWrap::saveStickerSets(const Stickers::Order &localOrder, const Stickers: if (writeFaved) Local::writeFavedStickers(); Auth().data().stickersUpdated().notify(true); - if (_stickerSetDisenableRequests.isEmpty()) { + if (_stickerSetDisenableRequests.empty()) { stickersSaveOrder(); } else { requestSendDelayed(); @@ -940,8 +992,8 @@ void ApiWrap::saveStickerSets(const Stickers::Order &localOrder, const Stickers: } void ApiWrap::stickerSetDisenabled(mtpRequestId requestId) { - _stickerSetDisenableRequests.remove(requestId); - if (_stickerSetDisenableRequests.isEmpty()) { + _stickerSetDisenableRequests.erase(requestId); + if (_stickerSetDisenableRequests.empty()) { stickersSaveOrder(); } }; @@ -950,15 +1002,18 @@ void ApiWrap::joinChannel(ChannelData *channel) { if (channel->amIn()) { Notify::peerUpdatedDelayed(channel, Notify::PeerUpdate::Flag::ChannelAmIn); } else if (!_channelAmInRequests.contains(channel)) { - auto requestId = request(MTPchannels_JoinChannel(channel->inputChannel)).done([this, channel](const MTPUpdates &result) { - _channelAmInRequests.remove(channel); - applyUpdates(result); - }).fail([this, channel](const RPCError &error) { - if (error.type() == qstr("CHANNELS_TOO_MUCH")) { - Ui::show(Box(lang(lng_join_channel_error))); - } - _channelAmInRequests.remove(channel); - }).send(); + auto requestId = request(MTPchannels_JoinChannel(channel->inputChannel)) + .done([this, channel](const MTPUpdates &result) { + _channelAmInRequests.remove(channel); + applyUpdates(result); + }) + .fail([this, channel](const RPCError &error) { + if (error.type() == qstr("CHANNELS_TOO_MUCH")) { + Ui::show(Box(lang(lng_join_channel_error))); + } + _channelAmInRequests.remove(channel); + }) + .send(); _channelAmInRequests.insert(channel, requestId); } @@ -968,12 +1023,13 @@ void ApiWrap::leaveChannel(ChannelData *channel) { if (!channel->amIn()) { Notify::peerUpdatedDelayed(channel, Notify::PeerUpdate::Flag::ChannelAmIn); } else if (!_channelAmInRequests.contains(channel)) { - auto requestId = request(MTPchannels_LeaveChannel(channel->inputChannel)).done([this, channel](const MTPUpdates &result) { - _channelAmInRequests.remove(channel); - applyUpdates(result); - }).fail([this, channel](const RPCError &error) { - _channelAmInRequests.remove(channel); - }).send(); + auto requestId = request(MTPchannels_LeaveChannel(channel->inputChannel)) + .done([this, channel](const MTPUpdates &result) { + _channelAmInRequests.remove(channel); + applyUpdates(result); + }) + .fail([this, channel](const RPCError &error) { _channelAmInRequests.remove(channel); }) + .send(); _channelAmInRequests.insert(channel, requestId); } @@ -983,12 +1039,13 @@ void ApiWrap::blockUser(UserData *user) { if (user->isBlocked()) { Notify::peerUpdatedDelayed(user, Notify::PeerUpdate::Flag::UserIsBlocked); } else if (!_blockRequests.contains(user)) { - auto requestId = request(MTPcontacts_Block(user->inputUser)).done([this, user](const MTPBool &result) { - _blockRequests.remove(user); - user->setBlockStatus(UserData::BlockStatus::Blocked); - }).fail([this, user](const RPCError &error) { - _blockRequests.remove(user); - }).send(); + auto requestId = request(MTPcontacts_Block(user->inputUser)) + .done([this, user](const MTPBool &result) { + _blockRequests.remove(user); + user->setBlockStatus(UserData::BlockStatus::Blocked); + }) + .fail([this, user](const RPCError &error) { _blockRequests.remove(user); }) + .send(); _blockRequests.insert(user, requestId); } @@ -998,12 +1055,13 @@ void ApiWrap::unblockUser(UserData *user) { if (!user->isBlocked()) { Notify::peerUpdatedDelayed(user, Notify::PeerUpdate::Flag::UserIsBlocked); } else if (!_blockRequests.contains(user)) { - auto requestId = request(MTPcontacts_Unblock(user->inputUser)).done([this, user](const MTPBool &result) { - _blockRequests.remove(user); - user->setBlockStatus(UserData::BlockStatus::NotBlocked); - }).fail([this, user](const RPCError &error) { - _blockRequests.remove(user); - }).send(); + auto requestId = request(MTPcontacts_Unblock(user->inputUser)) + .done([this, user](const MTPBool &result) { + _blockRequests.remove(user); + user->setBlockStatus(UserData::BlockStatus::NotBlocked); + }) + .fail([this, user](const RPCError &error) { _blockRequests.remove(user); }) + .send(); _blockRequests.insert(user, requestId); } @@ -1015,19 +1073,27 @@ void ApiWrap::exportInviteLink(PeerData *peer) { } auto sendRequest = [this, peer] { - auto exportFail = [this, peer](const RPCError &error) { - _exportInviteRequests.remove(peer); - }; + auto exportFail = [this, peer](const RPCError &error) { _exportInviteRequests.remove(peer); }; if (auto chat = peer->asChat()) { - return request(MTPmessages_ExportChatInvite(chat->inputChat)).done([this, chat](const MTPExportedChatInvite &result) { - _exportInviteRequests.remove(chat); - chat->setInviteLink((result.type() == mtpc_chatInviteExported) ? qs(result.c_chatInviteExported().vlink) : QString()); - }).fail(exportFail).send(); + return request(MTPmessages_ExportChatInvite(chat->inputChat)) + .done([this, chat](const MTPExportedChatInvite &result) { + _exportInviteRequests.remove(chat); + chat->setInviteLink((result.type() == mtpc_chatInviteExported) ? + qs(result.c_chatInviteExported().vlink) : + QString()); + }) + .fail(exportFail) + .send(); } else if (auto channel = peer->asChannel()) { - return request(MTPchannels_ExportInvite(channel->inputChannel)).done([this, channel](const MTPExportedChatInvite &result) { - _exportInviteRequests.remove(channel); - channel->setInviteLink((result.type() == mtpc_chatInviteExported) ? qs(result.c_chatInviteExported().vlink) : QString()); - }).fail(exportFail).send(); + return request(MTPchannels_ExportInvite(channel->inputChannel)) + .done([this, channel](const MTPExportedChatInvite &result) { + _exportInviteRequests.remove(channel); + channel->setInviteLink((result.type() == mtpc_chatInviteExported) ? + qs(result.c_chatInviteExported().vlink) : + QString()); + }) + .fail(exportFail) + .send(); } return 0; }; @@ -1040,13 +1106,16 @@ void ApiWrap::requestNotifySetting(PeerData *peer) { if (_notifySettingRequests.contains(peer)) return; auto notifyPeer = MTP_inputNotifyPeer(peer->input); - auto requestId = request(MTPaccount_GetNotifySettings(notifyPeer)).done([this, notifyPeer, peer](const MTPPeerNotifySettings &result) { - notifySettingReceived(notifyPeer, result); - _notifySettingRequests.remove(peer); - }).fail([this, notifyPeer, peer](const RPCError &error) { - notifySettingReceived(notifyPeer, MTP_peerNotifySettingsEmpty()); - _notifySettingRequests.remove(peer); - }).send(); + auto requestId = request(MTPaccount_GetNotifySettings(notifyPeer)) + .done([this, notifyPeer, peer](const MTPPeerNotifySettings &result) { + notifySettingReceived(notifyPeer, result); + _notifySettingRequests.remove(peer); + }) + .fail([this, notifyPeer, peer](const RPCError &error) { + notifySettingReceived(notifyPeer, MTP_peerNotifySettingsEmpty()); + _notifySettingRequests.remove(peer); + }) + .send(); _notifySettingRequests.insert(peer, requestId); } @@ -1066,15 +1135,16 @@ void ApiWrap::savePrivacy(const MTPInputPrivacyKey &key, QVector(std::move(rules)))).done([this, keyTypeId](const MTPaccount_PrivacyRules &result) { - Expects(result.type() == mtpc_account_privacyRules); - auto &rules = result.c_account_privacyRules(); - App::feedUsers(rules.vusers); - _privacySaveRequests.remove(keyTypeId); - handlePrivacyChange(keyTypeId, rules.vrules); - }).fail([this, keyTypeId](const RPCError &error) { - _privacySaveRequests.remove(keyTypeId); - }).send(); + auto requestId = request(MTPaccount_SetPrivacy(key, MTP_vector(std::move(rules)))) + .done([this, keyTypeId](const MTPaccount_PrivacyRules &result) { + Expects(result.type() == mtpc_account_privacyRules); + auto &rules = result.c_account_privacyRules(); + App::feedUsers(rules.vusers); + _privacySaveRequests.remove(keyTypeId); + handlePrivacyChange(keyTypeId, rules.vrules); + }) + .fail([this, keyTypeId](const RPCError &error) { _privacySaveRequests.remove(keyTypeId); }) + .send(); _privacySaveRequests.insert(keyTypeId, requestId); } @@ -1091,7 +1161,8 @@ void ApiWrap::handlePrivacyChange(mtpTypeId keyTypeId, const MTPVectorisSelf() || user->loadedStatus != PeerData::FullLoaded) { return; } @@ -1146,30 +1217,33 @@ void ApiWrap::handlePrivacyChange(mtpTypeId keyTypeId, const MTPVector &result) { - _contactsStatusesRequestId = 0; - for_const (auto &item, result.v) { - Assert(item.type() == mtpc_contactStatus); - auto &data = item.c_contactStatus(); - if (auto user = App::userLoaded(data.vuser_id.v)) { - auto oldOnlineTill = user->onlineTill; - auto newOnlineTill = onlineTillFromStatus(data.vstatus, oldOnlineTill); - if (oldOnlineTill != newOnlineTill) { - user->onlineTill = newOnlineTill; - Notify::peerUpdatedDelayed(user, Notify::PeerUpdate::Flag::UserOnlineChanged); - } - } - } - }).fail([this](const RPCError &error) { - _contactsStatusesRequestId = 0; - }).send(); + _contactsStatusesRequestId = + request(MTPcontacts_GetStatuses()) + .done([this](const MTPVector &result) { + _contactsStatusesRequestId = 0; + for_const (auto &item, result.v) { + Assert(item.type() == mtpc_contactStatus); + auto &data = item.c_contactStatus(); + if (auto user = App::userLoaded(data.vuser_id.v)) { + auto oldOnlineTill = user->onlineTill; + auto newOnlineTill = onlineTillFromStatus(data.vstatus, oldOnlineTill); + if (oldOnlineTill != newOnlineTill) { + user->onlineTill = newOnlineTill; + Notify::peerUpdatedDelayed(user, Notify::PeerUpdate::Flag::UserOnlineChanged); + } + } + } + }) + .fail([this](const RPCError &error) { _contactsStatusesRequestId = 0; }) + .send(); } } int ApiWrap::onlineTillFromStatus(const MTPUserStatus &status, int currentOnlineTill) { switch (status.type()) { case mtpc_userStatusEmpty: return 0; - case mtpc_userStatusRecently: return (currentOnlineTill > -10) ? -2 : currentOnlineTill; // don't modify pseudo-online + case mtpc_userStatusRecently: + return (currentOnlineTill > -10) ? -2 : currentOnlineTill; // don't modify pseudo-online case mtpc_userStatusLastWeek: return -3; case mtpc_userStatusLastMonth: return -4; case mtpc_userStatusOffline: return status.c_userStatusOffline().vwas_online.v; @@ -1201,32 +1275,38 @@ void ApiWrap::saveDraftsToCloud() { if (!textWithTags.tags.isEmpty()) { flags |= MTPmessages_SaveDraft::Flag::f_entities; } - auto entities = TextUtilities::EntitiesToMTP(ConvertTextTagsToEntities(textWithTags.tags), TextUtilities::ConvertOption::SkipLocal); - - cloudDraft->saveRequestId = request(MTPmessages_SaveDraft(MTP_flags(flags), MTP_int(cloudDraft->msgId), history->peer->input, MTP_string(textWithTags.text), entities)).done([this, history](const MTPBool &result, mtpRequestId requestId) { - if (auto cloudDraft = history->cloudDraft()) { - if (cloudDraft->saveRequestId == requestId) { - cloudDraft->saveRequestId = 0; - history->draftSavedToCloud(); - } - } - auto i = _draftsSaveRequestIds.find(history); - if (i != _draftsSaveRequestIds.cend() && i.value() == requestId) { - _draftsSaveRequestIds.remove(history); - checkQuitPreventFinished(); - } - }).fail([this, history](const RPCError &error, mtpRequestId requestId) { - if (auto cloudDraft = history->cloudDraft()) { - if (cloudDraft->saveRequestId == requestId) { - history->clearCloudDraft(); - } - } - auto i = _draftsSaveRequestIds.find(history); - if (i != _draftsSaveRequestIds.cend() && i.value() == requestId) { - _draftsSaveRequestIds.remove(history); - checkQuitPreventFinished(); - } - }).send(); + auto entities = TextUtilities::EntitiesToMTP(ConvertTextTagsToEntities(textWithTags.tags), + TextUtilities::ConvertOption::SkipLocal); + + cloudDraft->saveRequestId = + request(MTPmessages_SaveDraft(MTP_flags(flags), MTP_int(cloudDraft->msgId), history->peer->input, + MTP_string(textWithTags.text), entities)) + .done([this, history](const MTPBool &result, mtpRequestId requestId) { + if (auto cloudDraft = history->cloudDraft()) { + if (cloudDraft->saveRequestId == requestId) { + cloudDraft->saveRequestId = 0; + history->draftSavedToCloud(); + } + } + auto i = _draftsSaveRequestIds.find(history); + if (i != _draftsSaveRequestIds.cend() && i.value() == requestId) { + _draftsSaveRequestIds.remove(history); + checkQuitPreventFinished(); + } + }) + .fail([this, history](const RPCError &error, mtpRequestId requestId) { + if (auto cloudDraft = history->cloudDraft()) { + if (cloudDraft->saveRequestId == requestId) { + history->clearCloudDraft(); + } + } + auto i = _draftsSaveRequestIds.find(history); + if (i != _draftsSaveRequestIds.cend() && i.value() == requestId) { + _draftsSaveRequestIds.remove(history); + checkQuitPreventFinished(); + } + }) + .send(); i.value() = cloudDraft->saveRequestId; } @@ -1259,11 +1339,15 @@ PeerData *ApiWrap::notifySettingReceived(MTPInputNotifyPeer notifyPeer, const MT case mtpc_inputNotifyPeer: { auto &peer = notifyPeer.c_inputNotifyPeer().vpeer; switch (peer.type()) { - case mtpc_inputPeerEmpty: App::main()->applyNotifySetting(MTP_notifyPeer(MTP_peerUser(MTP_int(0))), settings); break; + case mtpc_inputPeerEmpty: + App::main()->applyNotifySetting(MTP_notifyPeer(MTP_peerUser(MTP_int(0))), settings); + break; case mtpc_inputPeerSelf: requestedPeer = App::self(); break; case mtpc_inputPeerUser: requestedPeer = App::user(peerFromUser(peer.c_inputPeerUser().vuser_id)); break; case mtpc_inputPeerChat: requestedPeer = App::chat(peerFromChat(peer.c_inputPeerChat().vchat_id)); break; - case mtpc_inputPeerChannel: requestedPeer = App::channel(peerFromChannel(peer.c_inputPeerChannel().vchannel_id)); break; + case mtpc_inputPeerChannel: + requestedPeer = App::channel(peerFromChannel(peer.c_inputPeerChannel().vchannel_id)); + break; } if (requestedPeer) { App::main()->applyNotifySetting(MTP_notifyPeer(peerToMTP(requestedPeer->id)), settings); @@ -1274,7 +1358,7 @@ PeerData *ApiWrap::notifySettingReceived(MTPInputNotifyPeer notifyPeer, const MT return requestedPeer; } -void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result) { +void ApiWrap::gotStickerSet(quint64 setId, const MTPmessages_StickerSet &result) { _stickerSetRequests.remove(setId); Stickers::FeedSetFull(result); } @@ -1302,18 +1386,18 @@ void ApiWrap::clearWebPageRequests() { void ApiWrap::resolveWebPages() { auto ids = QVector(); // temp_req_id = -1 - using IndexAndMessageIds = QPair>; - using MessageIdsByChannel = QMap; + using IndexAndMessageIds = QPair>; + using MessageIdsByChannel = QMap; MessageIdsByChannel idsByChannel; // temp_req_id = -index - 2 auto &items = App::webPageItems(); ids.reserve(_webPagesPending.size()); - int32 t = unixtime(), m = INT_MAX; + qint32 t = unixtime(), m = INT_MAX; for (auto i = _webPagesPending.begin(); i != _webPagesPending.cend(); ++i) { if (i.value() > 0) continue; if (i.key()->pendingTill <= t) { auto j = items.constFind(i.key()); - if (j != items.cend() && !j.value().isEmpty()) { + if (j != items.cend() && !j.value().empty()) { for_const (auto item, j.value()) { if (item->id > 0) { if (item->channelId() == NoChannel) { @@ -1323,7 +1407,9 @@ void ApiWrap::resolveWebPages() { auto channel = item->history()->peer->asChannel(); auto channelMap = idsByChannel.find(channel); if (channelMap == idsByChannel.cend()) { - channelMap = idsByChannel.insert(channel, IndexAndMessageIds(idsByChannel.size(), QVector(1, MTP_int(item->id)))); + channelMap = idsByChannel.insert( + channel, + IndexAndMessageIds(idsByChannel.size(), QVector(1, MTP_int(item->id)))); } else { channelMap.value().second.push_back(MTP_int(item->id)); } @@ -1334,21 +1420,28 @@ void ApiWrap::resolveWebPages() { } } } else { - m = qMin(m, i.key()->pendingTill - t); + m = std::min(m, i.key()->pendingTill - t); } } auto requestId = mtpRequestId(0); if (!ids.isEmpty()) { - requestId = request(MTPmessages_GetMessages(MTP_vector(ids))).done([this](const MTPmessages_Messages &result, mtpRequestId requestId) { - gotWebPages(nullptr, result, requestId); - }).after(kSmallDelayMs).send(); + requestId = request(MTPmessages_GetMessages(MTP_vector(ids))) + .done([this](const MTPmessages_Messages &result, mtpRequestId requestId) { + gotWebPages(nullptr, result, requestId); + }) + .after(kSmallDelayMs) + .send(); } QVector reqsByIndex(idsByChannel.size(), 0); for (auto i = idsByChannel.cbegin(), e = idsByChannel.cend(); i != e; ++i) { - reqsByIndex[i.value().first] = request(MTPchannels_GetMessages(i.key()->inputChannel, MTP_vector(i.value().second))).done([this, channel = i.key()](const MTPmessages_Messages &result, mtpRequestId requestId) { - gotWebPages(channel, result, requestId); - }).after(kSmallDelayMs).send(); + reqsByIndex[i.value().first] = + request(MTPchannels_GetMessages(i.key()->inputChannel, MTP_vector(i.value().second))) + .done([this, channel = i.key()](const MTPmessages_Messages &result, mtpRequestId requestId) { + gotWebPages(channel, result, requestId); + }) + .after(kSmallDelayMs) + .send(); } if (requestId || !reqsByIndex.isEmpty()) { for (auto &pendingRequestId : _webPagesPending) { @@ -1369,9 +1462,7 @@ void ApiWrap::resolveWebPages() { } void ApiWrap::requestParticipantsCountDelayed(ChannelData *channel) { - _participantsCountRequestTimer.call(kReloadChannelMembersTimeout, [this, channel] { - channel->updateFullForced(); - }); + _participantsCountRequestTimer.call(kReloadChannelMembersTimeout, [channel] { channel->updateFullForced(); }); } void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs, mtpRequestId req) { @@ -1405,13 +1496,17 @@ void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs } if (!v) return; - QMap msgsIds; // copied from feedMsgs - for (int32 i = 0, l = v->size(); i < l; ++i) { + QMap msgsIds; // copied from feedMsgs + for (qint32 i = 0, l = v->size(); i < l; ++i) { const auto &msg(v->at(i)); switch (msg.type()) { - case mtpc_message: msgsIds.insert((uint64(uint32(msg.c_message().vid.v)) << 32) | uint64(i), i); break; - case mtpc_messageEmpty: msgsIds.insert((uint64(uint32(msg.c_messageEmpty().vid.v)) << 32) | uint64(i), i); break; - case mtpc_messageService: msgsIds.insert((uint64(uint32(msg.c_messageService().vid.v)) << 32) | uint64(i), i); break; + case mtpc_message: msgsIds.insert((quint64(quint32(msg.c_message().vid.v)) << 32) | quint64(i), i); break; + case mtpc_messageEmpty: + msgsIds.insert((quint64(quint32(msg.c_messageEmpty().vid.v)) << 32) | quint64(i), i); + break; + case mtpc_messageService: + msgsIds.insert((quint64(quint32(msg.c_messageService().vid.v)) << 32) | quint64(i), i); + break; } } @@ -1428,9 +1523,7 @@ void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs i.key()->pendingTill = -1; auto j = items.constFind(i.key()); if (j != items.cend()) { - for_const (auto item, j.value()) { - item->setPendingInitDimensions(); - } + for_const (auto item, j.value()) { item->setPendingInitDimensions(); } } } i = _webPagesPending.erase(i); @@ -1444,17 +1537,16 @@ void ApiWrap::stickersSaveOrder() { if (_stickersOrder.size() > 1) { QVector mtpOrder; mtpOrder.reserve(_stickersOrder.size()); - for_const (auto setId, _stickersOrder) { - mtpOrder.push_back(MTP_long(setId)); - } + for_const (auto setId, _stickersOrder) { mtpOrder.push_back(MTP_long(setId)); } - _stickersReorderRequestId = request(MTPmessages_ReorderStickerSets(MTP_flags(0), MTP_vector(mtpOrder))).done([this](const MTPBool &result) { - _stickersReorderRequestId = 0; - }).fail([this](const RPCError &error) { - _stickersReorderRequestId = 0; - Global::SetLastStickersUpdate(0); - updateStickers(); - }).send(); + _stickersReorderRequestId = request(MTPmessages_ReorderStickerSets(MTP_flags(0), MTP_vector(mtpOrder))) + .done([this](const MTPBool &result) { _stickersReorderRequestId = 0; }) + .fail([this](const RPCError &error) { + _stickersReorderRequestId = 0; + Global::SetLastStickersUpdate(0); + updateStickers(); + }) + .send(); } } @@ -1467,7 +1559,7 @@ void ApiWrap::updateStickers() { requestSavedGifs(now); } -void ApiWrap::setGroupStickerSet(not_null megagroup, const MTPInputStickerSet &set) { +void ApiWrap::setGroupStickerSet(not_null megagroup, const MTPInputStickerSet &set) { Expects(megagroup->mgInfo != nullptr); megagroup->mgInfo->stickerSet = set; request(MTPchannels_SetStickers(megagroup->inputChannel, set)).send(); @@ -1490,14 +1582,18 @@ void ApiWrap::requestStickers(TimeId now) { case mtpc_messages_allStickers: { auto &d = result.c_messages_allStickers(); Stickers::SetsReceived(d.vsets.v, d.vhash.v); - } return; + } + return; default: Unexpected("Type in ApiWrap::stickersDone()"); } }; - _stickersUpdateRequest = request(MTPmessages_GetAllStickers(MTP_int(Local::countStickersHash(true)))).done(onDone).fail([this, onDone](const RPCError &error) { - LOG(("App Fail: Failed to get stickers!")); - onDone(MTP_messages_allStickersNotModified()); - }).send(); + _stickersUpdateRequest = request(MTPmessages_GetAllStickers(MTP_int(Local::countStickersHash(true)))) + .done(onDone) + .fail([onDone](const RPCError &error) { + LOG(("App Fail: Failed to get stickers!")); + onDone(MTP_messages_allStickersNotModified()); + }) + .send(); } void ApiWrap::requestRecentStickers(TimeId now) { @@ -1515,15 +1611,21 @@ void ApiWrap::requestRecentStickers(TimeId now) { case mtpc_messages_recentStickersNotModified: return; case mtpc_messages_recentStickers: { auto &d = result.c_messages_recentStickers(); - Stickers::SpecialSetReceived(Stickers::CloudRecentSetId, lang(lng_recent_stickers), d.vstickers.v, d.vhash.v); - } return; + Stickers::SpecialSetReceived(Stickers::CloudRecentSetId, lang(lng_recent_stickers), d.vstickers.v, + d.vhash.v); + } + return; default: Unexpected("Type in ApiWrap::recentStickersDone()"); } }; - _recentStickersUpdateRequest = request(MTPmessages_GetRecentStickers(MTP_flags(0), MTP_int(Local::countRecentStickersHash()))).done(onDone).fail([this, onDone](const RPCError &error) { - LOG(("App Fail: Failed to get recent stickers!")); - onDone(MTP_messages_recentStickersNotModified()); - }).send(); + _recentStickersUpdateRequest = + request(MTPmessages_GetRecentStickers(MTP_flags(0), MTP_int(Local::countRecentStickersHash()))) + .done(onDone) + .fail([onDone](const RPCError &error) { + LOG(("App Fail: Failed to get recent stickers!")); + onDone(MTP_messages_recentStickersNotModified()); + }) + .send(); } void ApiWrap::requestFavedStickers(TimeId now) { @@ -1541,19 +1643,25 @@ void ApiWrap::requestFavedStickers(TimeId now) { case mtpc_messages_favedStickersNotModified: return; case mtpc_messages_favedStickers: { auto &d = result.c_messages_favedStickers(); - Stickers::SpecialSetReceived(Stickers::FavedSetId, lang(lng_faved_stickers), d.vstickers.v, d.vhash.v, d.vpacks.v); - } return; + Stickers::SpecialSetReceived(Stickers::FavedSetId, lang(lng_faved_stickers), d.vstickers.v, d.vhash.v, + d.vpacks.v); + } + return; default: Unexpected("Type in ApiWrap::favedStickersDone()"); } }; - _favedStickersUpdateRequest = request(MTPmessages_GetFavedStickers(MTP_int(Local::countFavedStickersHash()))).done(onDone).fail([this, onDone](const RPCError &error) { - LOG(("App Fail: Failed to get faved stickers!")); - onDone(MTP_messages_favedStickersNotModified()); - }).send(); + _favedStickersUpdateRequest = request(MTPmessages_GetFavedStickers(MTP_int(Local::countFavedStickersHash()))) + .done(onDone) + .fail([onDone](const RPCError &error) { + LOG(("App Fail: Failed to get faved stickers!")); + onDone(MTP_messages_favedStickersNotModified()); + }) + .send(); } void ApiWrap::requestFeaturedStickers(TimeId now) { - if (Global::LastFeaturedStickersUpdate() != 0 && now < Global::LastFeaturedStickersUpdate() + kStickersUpdateTimeout) { + if (Global::LastFeaturedStickersUpdate() != 0 && + now < Global::LastFeaturedStickersUpdate() + kStickersUpdateTimeout) { return; } if (_featuredStickersUpdateRequest) { @@ -1568,14 +1676,19 @@ void ApiWrap::requestFeaturedStickers(TimeId now) { case mtpc_messages_featuredStickers: { auto &d = result.c_messages_featuredStickers(); Stickers::FeaturedSetsReceived(d.vsets.v, d.vunread.v, d.vhash.v); - } return; + } + return; default: Unexpected("Type in ApiWrap::featuredStickersDone()"); } }; - _featuredStickersUpdateRequest = request(MTPmessages_GetFeaturedStickers(MTP_int(Local::countFeaturedStickersHash()))).done(onDone).fail([this, onDone](const RPCError &error) { - LOG(("App Fail: Failed to get featured stickers!")); - onDone(MTP_messages_featuredStickersNotModified()); - }).send(); + _featuredStickersUpdateRequest = + request(MTPmessages_GetFeaturedStickers(MTP_int(Local::countFeaturedStickersHash()))) + .done(onDone) + .fail([onDone](const RPCError &error) { + LOG(("App Fail: Failed to get featured stickers!")); + onDone(MTP_messages_featuredStickersNotModified()); + }) + .send(); } void ApiWrap::requestSavedGifs(TimeId now) { @@ -1594,14 +1707,18 @@ void ApiWrap::requestSavedGifs(TimeId now) { case mtpc_messages_savedGifs: { auto &d = result.c_messages_savedGifs(); Stickers::GifsReceived(d.vgifs.v, d.vhash.v); - } return; + } + return; default: Unexpected("Type in ApiWrap::savedGifsDone()"); } }; - _savedGifsUpdateRequest = request(MTPmessages_GetSavedGifs(MTP_int(Local::countSavedGifsHash()))).done(onDone).fail([this, onDone](const RPCError &error) { - LOG(("App Fail: Failed to get saved gifs!")); - onDone(MTP_messages_savedGifsNotModified()); - }).send(); + _savedGifsUpdateRequest = request(MTPmessages_GetSavedGifs(MTP_int(Local::countSavedGifsHash()))) + .done(onDone) + .fail([onDone](const RPCError &error) { + LOG(("App Fail: Failed to get saved gifs!")); + onDone(MTP_messages_savedGifsNotModified()); + }) + .send(); } void ApiWrap::applyUpdatesNoPtsCheck(const MTPUpdates &updates) { @@ -1609,13 +1726,22 @@ void ApiWrap::applyUpdatesNoPtsCheck(const MTPUpdates &updates) { case mtpc_updateShortMessage: { auto &d = updates.c_updateShortMessage(); auto flags = mtpCastFlags(d.vflags.v) | MTPDmessage::Flag::f_from_id; - App::histories().addNewMessage(MTP_message(MTP_flags(flags), d.vid, d.is_out() ? MTP_int(Auth().userId()) : d.vuser_id, MTP_peerUser(d.is_out() ? d.vuser_id : MTP_int(Auth().userId())), d.vfwd_from, d.vvia_bot_id, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities, MTPint(), MTPint(), MTPstring()), NewMessageUnread); + App::histories().addNewMessage( + MTP_message(MTP_flags(flags), d.vid, d.is_out() ? MTP_int(Auth().userId()) : d.vuser_id, + MTP_peerUser(d.is_out() ? d.vuser_id : MTP_int(Auth().userId())), d.vfwd_from, d.vvia_bot_id, + d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, + d.has_entities() ? d.ventities : MTPnullEntities, MTPint(), MTPint(), MTPstring()), + NewMessageUnread); } break; case mtpc_updateShortChatMessage: { auto &d = updates.c_updateShortChatMessage(); auto flags = mtpCastFlags(d.vflags.v) | MTPDmessage::Flag::f_from_id; - App::histories().addNewMessage(MTP_message(MTP_flags(flags), d.vid, d.vfrom_id, MTP_peerChat(d.vchat_id), d.vfwd_from, d.vvia_bot_id, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities, MTPint(), MTPint(), MTPstring()), NewMessageUnread); + App::histories().addNewMessage( + MTP_message(MTP_flags(flags), d.vid, d.vfrom_id, MTP_peerChat(d.vchat_id), d.vfwd_from, d.vvia_bot_id, + d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, + d.has_entities() ? d.ventities : MTPnullEntities, MTPint(), MTPint(), MTPstring()), + NewMessageUnread); } break; case mtpc_updateShortSentMessage: { @@ -1725,49 +1851,54 @@ void ApiWrap::applyUpdateNoPtsCheck(const MTPUpdate &update) { } } -void ApiWrap::jumpToDate(not_null peer, const QDate &date) { +void ApiWrap::jumpToDate(not_null peer, const QDate &date) { // API returns a message with date <= offset_date. // So we request a message with offset_date = desired_date - 1 and add_offset = -1. // This should give us the first message with date >= desired_date. auto offset_date = static_cast(QDateTime(date).toTime_t()) - 1; auto add_offset = -1; auto limit = 1; - request(MTPmessages_GetHistory(peer->input, MTP_int(0), MTP_int(offset_date), MTP_int(add_offset), MTP_int(limit), MTP_int(0), MTP_int(0))).done([peer](const MTPmessages_Messages &result) { - auto getMessagesList = [&result, peer]() -> const QVector* { - auto handleMessages = [](auto &messages) { - App::feedUsers(messages.vusers); - App::feedChats(messages.vchats); - return &messages.vmessages.v; - }; - switch (result.type()) { - case mtpc_messages_messages: return handleMessages(result.c_messages_messages()); - case mtpc_messages_messagesSlice: return handleMessages(result.c_messages_messagesSlice()); - case mtpc_messages_channelMessages: { - auto &messages = result.c_messages_channelMessages(); - if (peer && peer->isChannel()) { - peer->asChannel()->ptsReceived(messages.vpts.v); - } else { - LOG(("API Error: received messages.channelMessages when no channel was passed! (MainWidget::showJumpToDate)")); - } - return handleMessages(messages); - } break; - } - return nullptr; - }; - - if (auto list = getMessagesList()) { - App::feedMsgs(*list, NewMessageExisting); - for (auto &message : *list) { - auto id = idFromMessage(message); - Ui::showPeerHistory(peer, id); - return; - } - } - Ui::showPeerHistory(peer, ShowAtUnreadMsgId); - }).send(); -} - -void ApiWrap::preloadEnoughUnreadMentions(not_null history) { + request(MTPmessages_GetHistory(peer->input, MTP_int(0), MTP_int(offset_date), MTP_int(add_offset), MTP_int(limit), + MTP_int(0), MTP_int(0), MTP_int(0))) + .done([peer](const MTPmessages_Messages &result) { + auto getMessagesList = [&result, peer]() -> const QVector * { + auto handleMessages = [](auto &messages) { + App::feedUsers(messages.vusers); + App::feedChats(messages.vchats); + return &messages.vmessages.v; + }; + switch (result.type()) { + case mtpc_messages_messages: return handleMessages(result.c_messages_messages()); + case mtpc_messages_messagesSlice: return handleMessages(result.c_messages_messagesSlice()); + case mtpc_messages_channelMessages: { + auto &messages = result.c_messages_channelMessages(); + if (peer && peer->isChannel()) { + peer->asChannel()->ptsReceived(messages.vpts.v); + } else { + LOG( + ("API Error: received messages.channelMessages when no channel was passed! " + "(MainWidget::showJumpToDate)")); + } + return handleMessages(messages); + } break; + } + return nullptr; + }; + + if (auto list = getMessagesList()) { + App::feedMsgs(*list, NewMessageExisting); + for (auto &message : *list) { + auto id = idFromMessage(message); + Ui::showPeerHistory(peer, id); + return; + } + } + Ui::showPeerHistory(peer, ShowAtUnreadMsgId); + }) + .send(); +} + +void ApiWrap::preloadEnoughUnreadMentions(not_null history) { auto fullCount = history->getUnreadMentionsCount(); auto loadedCount = history->getUnreadMentionsLoadedCount(); auto allLoaded = (fullCount >= 0) ? (loadedCount >= fullCount) : false; @@ -1782,12 +1913,14 @@ void ApiWrap::preloadEnoughUnreadMentions(not_null history) { auto addOffset = loadedCount ? -(limit + 1) : -limit; auto maxId = 0; auto minId = 0; - auto requestId = request(MTPmessages_GetUnreadMentions(history->peer->input, MTP_int(offsetId), MTP_int(addOffset), MTP_int(limit), MTP_int(maxId), MTP_int(minId))).done([this, history](const MTPmessages_Messages &result) { - _unreadMentionsRequests.remove(history); - history->addUnreadMentionsSlice(result); - }).fail([this, history](const RPCError &error) { - _unreadMentionsRequests.remove(history); - }).send(); + auto requestId = request(MTPmessages_GetUnreadMentions(history->peer->input, MTP_int(offsetId), MTP_int(addOffset), + MTP_int(limit), MTP_int(maxId), MTP_int(minId))) + .done([this, history](const MTPmessages_Messages &result) { + _unreadMentionsRequests.remove(history); + history->addUnreadMentionsSlice(result); + }) + .fail([this, history](const RPCError &error) { _unreadMentionsRequests.remove(history); }) + .send(); _unreadMentionsRequests.emplace(history, requestId); } @@ -1803,90 +1936,88 @@ void ApiWrap::checkForUnreadMentions(const base::flat_set &possiblyReadMe } } -void ApiWrap::cancelEditChatAdmins(not_null chat) { - _chatAdminsEnabledRequests.take(chat) - | requestCanceller(); +void ApiWrap::cancelEditChatAdmins(not_null chat) { + _chatAdminsEnabledRequests.take(chat) | requestCanceller(); - _chatAdminsSaveRequests.take(chat) - | base::for_each_apply(requestCanceller()); + _chatAdminsSaveRequests.take(chat) | base::for_each_apply(requestCanceller()); _chatAdminsToSave.remove(chat); } -void ApiWrap::editChatAdmins( - not_null chat, - bool adminsEnabled, - base::flat_set> &&admins) { +void ApiWrap::editChatAdmins(not_null chat, bool adminsEnabled, + base::flat_set> &&admins) { cancelEditChatAdmins(chat); if (adminsEnabled) { _chatAdminsToSave.emplace(chat, std::move(admins)); } - auto requestId = request(MTPmessages_ToggleChatAdmins(chat->inputChat, MTP_bool(adminsEnabled))).done([this, chat](const MTPUpdates &updates) { - _chatAdminsEnabledRequests.remove(chat); - applyUpdates(updates); - saveChatAdmins(chat); - }).fail([this, chat](const RPCError &error) { - _chatAdminsEnabledRequests.remove(chat); - if (error.type() == qstr("CHAT_NOT_MODIFIED")) { - saveChatAdmins(chat); - } - }).send(); + auto requestId = request(MTPmessages_ToggleChatAdmins(chat->inputChat, MTP_bool(adminsEnabled))) + .done([this, chat](const MTPUpdates &updates) { + _chatAdminsEnabledRequests.remove(chat); + applyUpdates(updates); + saveChatAdmins(chat); + }) + .fail([this, chat](const RPCError &error) { + _chatAdminsEnabledRequests.remove(chat); + if (error.type() == qstr("CHAT_NOT_MODIFIED")) { + saveChatAdmins(chat); + } + }) + .send(); _chatAdminsEnabledRequests.emplace(chat, requestId); } -void ApiWrap::saveChatAdmins(not_null chat) { +void ApiWrap::saveChatAdmins(not_null chat) { if (!_chatAdminsToSave.contains(chat)) { return; } - auto requestId = request(MTPmessages_GetFullChat(chat->inputChat)).done([this, chat](const MTPmessages_ChatFull &result) { - _chatAdminsEnabledRequests.remove(chat); - processFullPeer(chat, result); - sendSaveChatAdminsRequests(chat); - }).fail([this, chat](const RPCError &error) { - _chatAdminsEnabledRequests.remove(chat); - _chatAdminsToSave.remove(chat); - }).send(); + auto requestId = request(MTPmessages_GetFullChat(chat->inputChat)) + .done([this, chat](const MTPmessages_ChatFull &result) { + _chatAdminsEnabledRequests.remove(chat); + processFullPeer(chat, result); + sendSaveChatAdminsRequests(chat); + }) + .fail([this, chat](const RPCError &error) { + _chatAdminsEnabledRequests.remove(chat); + _chatAdminsToSave.remove(chat); + }) + .send(); _chatAdminsEnabledRequests.emplace(chat, requestId); } -void ApiWrap::sendSaveChatAdminsRequests(not_null chat) { - auto editOne = [this, chat](not_null user, bool admin) { - auto requestId = request(MTPmessages_EditChatAdmin( - chat->inputChat, - user->inputUser, - MTP_bool(admin))) - .done([this, chat, user, admin]( - const MTPBool &result, - mtpRequestId requestId) { - _chatAdminsSaveRequests[chat].remove(requestId); - if (_chatAdminsSaveRequests[chat].empty()) { - _chatAdminsSaveRequests.remove(chat); - Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::AdminsChanged); - } - if (mtpIsTrue(result)) { - if (admin) { - if (chat->noParticipantInfo()) { - requestFullPeer(chat); - } else { - chat->admins.insert(user); - } - } else { - chat->admins.remove(user); - } - } - }).fail([this, chat]( - const RPCError &error, - mtpRequestId requestId) { - _chatAdminsSaveRequests[chat].remove(requestId); - if (_chatAdminsSaveRequests[chat].empty()) { - _chatAdminsSaveRequests.remove(chat); - } - chat->invalidateParticipants(); - if (error.type() == qstr("USER_RESTRICTED")) { - Ui::show(Box(lang(lng_cant_do_this))); - } - }).canWait(5).send(); +void ApiWrap::sendSaveChatAdminsRequests(not_null chat) { + auto editOne = [this, chat](not_null user, bool admin) { + auto requestId = request(MTPmessages_EditChatAdmin(chat->inputChat, user->inputUser, MTP_bool(admin))) + .done([this, chat, user, admin](const MTPBool &result, mtpRequestId requestId) { + _chatAdminsSaveRequests[chat].remove(requestId); + if (_chatAdminsSaveRequests[chat].empty()) { + _chatAdminsSaveRequests.remove(chat); + Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::AdminsChanged); + } + if (mtpIsTrue(result)) { + if (admin) { + if (chat->noParticipantInfo()) { + requestFullPeer(chat); + } else { + chat->admins.insert(user); + } + } else { + chat->admins.erase(user); + } + } + }) + .fail([this, chat](const RPCError &error, mtpRequestId requestId) { + _chatAdminsSaveRequests[chat].remove(requestId); + if (_chatAdminsSaveRequests[chat].empty()) { + _chatAdminsSaveRequests.remove(chat); + } + chat->invalidateParticipants(); + if (error.type() == qstr("USER_RESTRICTED")) { + Ui::show(Box(lang(lng_cant_do_this))); + } + }) + .canWait(5) + .send(); _chatAdminsSaveRequests[chat].insert(requestId); }; @@ -1897,11 +2028,11 @@ void ApiWrap::sendSaveChatAdminsRequests(not_null chat) { Assert(!!admins); auto toRemove = chat->admins; - auto toAppoint = std::vector>(); + auto toAppoint = std::vector>(); if (!admins->empty()) { toAppoint.reserve(admins->size()); for (auto user : *admins) { - if (!toRemove.remove(user) && user->id != peerFromUser(chat->creator)) { + if (!toRemove.erase(user) && user->id != peerFromUser(chat->creator)) { toAppoint.push_back(user); } } diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index 7b7a94b8f..9bc9352f1 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -1,30 +1,36 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once +#include "base/flat_map.h" +#include "base/flat_set.h" #include "base/timer.h" #include "core/single_timer.h" +#include "facades.h" +#include "mtproto/core_types.h" +#include "mtproto/rpc_sender.h" #include "mtproto/sender.h" -#include "base/flat_map.h" -#include "base/flat_set.h" +#include class AuthSession; @@ -40,19 +46,21 @@ inline const MTPVector *getChatsFromMessagesChats(const MTPmessages_Cha } // namespace Api +class History; + class ApiWrap : private MTP::Sender, private base::Subscriber { public: - ApiWrap(not_null session); + ApiWrap(not_null session); void start(); - void applyUpdates(const MTPUpdates &updates, uint64 sentMessageRandomId = 0); + void applyUpdates(const MTPUpdates &updates, quint64 sentMessageRandomId = 0); - using RequestMessageDataCallback = base::lambda; + using RequestMessageDataCallback = Fn; void requestMessageData(ChannelData *channel, MsgId msgId, RequestMessageDataCallback callback); void requestFullPeer(PeerData *peer); void requestPeer(PeerData *peer); - void requestPeers(const QList &peers); + void requestPeers(const QList &peers); void requestLastParticipants(ChannelData *channel, bool fromStart = true); void requestBots(ChannelData *channel); void requestParticipantsCountDelayed(ChannelData *channel); @@ -68,11 +76,11 @@ class ApiWrap : private MTP::Sender, private base::Subscriber { void clearWebPageRequest(WebPageData *page); void clearWebPageRequests(); - void scheduleStickerSetRequest(uint64 setId, uint64 access); + void scheduleStickerSetRequest(quint64 setId, quint64 access); void requestStickerSets(); void saveStickerSets(const Stickers::Order &localOrder, const Stickers::Order &localRemoved); void updateStickers(); - void setGroupStickerSet(not_null megagroup, const MTPInputStickerSet &set); + void setGroupStickerSet(not_null megagroup, const MTPInputStickerSet &set); void joinChannel(ChannelData *channel); void leaveChannel(ChannelData *channel); @@ -89,7 +97,7 @@ class ApiWrap : private MTP::Sender, private base::Subscriber { void handlePrivacyChange(mtpTypeId keyTypeId, const MTPVector &rules); int onlineTillFromStatus(const MTPUserStatus &status, int currentOnlineTill); - base::Observable &fullPeerUpdated() { + base::Observable &fullPeerUpdated() { return _fullPeerUpdated; } @@ -98,15 +106,12 @@ class ApiWrap : private MTP::Sender, private base::Subscriber { void applyUpdatesNoPtsCheck(const MTPUpdates &updates); void applyUpdateNoPtsCheck(const MTPUpdate &update); - void jumpToDate(not_null peer, const QDate &date); + void jumpToDate(not_null peer, const QDate &date); - void preloadEnoughUnreadMentions(not_null history); + void preloadEnoughUnreadMentions(not_null history); void checkForUnreadMentions(const base::flat_set &possiblyReadMentions, ChannelData *channel = nullptr); - void editChatAdmins( - not_null chat, - bool adminsEnabled, - base::flat_set> &&admins); + void editChatAdmins(not_null chat, bool adminsEnabled, base::flat_set> &&admins); ~ApiWrap(); @@ -136,7 +141,7 @@ class ApiWrap : private MTP::Sender, private base::Subscriber { void lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelParticipants &result, mtpRequestId req); void resolveWebPages(); void gotWebPages(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId req); - void gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result); + void gotStickerSet(quint64 setId, const MTPmessages_StickerSet &result); PeerData *notifySettingReceived(MTPInputNotifyPeer peer, const MTPPeerNotifySettings &settings); @@ -149,18 +154,18 @@ class ApiWrap : private MTP::Sender, private base::Subscriber { void requestFeaturedStickers(TimeId now); void requestSavedGifs(TimeId now); - void cancelEditChatAdmins(not_null chat); - void saveChatAdmins(not_null chat); - void sendSaveChatAdminsRequests(not_null chat); + void cancelEditChatAdmins(not_null chat); + void saveChatAdmins(not_null chat); + void sendSaveChatAdminsRequests(not_null chat); - not_null _session; + not_null _session; mtpRequestId _changelogSubscription = 0; MessageDataRequests _messageDataRequests; - QMap _channelMessageDataRequests; + QMap _channelMessageDataRequests; SingleQueuedInvokation _messageDataResolveDelayed; - using PeerRequests = QMap; + using PeerRequests = QMap; PeerRequests _fullPeerRequests; PeerRequests _peerRequests; @@ -168,27 +173,27 @@ class ApiWrap : private MTP::Sender, private base::Subscriber { PeerRequests _botsRequests; base::DelayedCallTimer _participantsCountRequestTimer; - typedef QPair KickRequest; + typedef QPair KickRequest; typedef QMap KickRequests; KickRequests _kickRequests; - QMap _selfParticipantRequests; + QMap _selfParticipantRequests; - QMap _webPagesPending; + QMap _webPagesPending; base::Timer _webPagesTimer; - QMap > _stickerSetRequests; + QMap> _stickerSetRequests; - QMap _channelAmInRequests; - QMap _blockRequests; - QMap _exportInviteRequests; + QMap _channelAmInRequests; + QMap _blockRequests; + QMap _exportInviteRequests; - QMap _notifySettingRequests; + QMap _notifySettingRequests; - QMap _draftsSaveRequestIds; + QMap _draftsSaveRequestIds; base::Timer _draftsSaveTimer; - OrderedSet _stickerSetDisenableRequests; + std::set _stickerSetDisenableRequests; Stickers::Order _stickersOrder; mtpRequestId _stickersReorderRequestId = 0; mtpRequestId _stickersClearRecentRequestId = 0; @@ -203,12 +208,11 @@ class ApiWrap : private MTP::Sender, private base::Subscriber { mtpRequestId _contactsStatusesRequestId = 0; - base::flat_map, mtpRequestId> _unreadMentionsRequests; - - base::flat_map, mtpRequestId> _chatAdminsEnabledRequests; - base::flat_map, base::flat_set>> _chatAdminsToSave; - base::flat_map, base::flat_set> _chatAdminsSaveRequests; + base::flat_map, mtpRequestId> _unreadMentionsRequests; - base::Observable _fullPeerUpdated; + base::flat_map, mtpRequestId> _chatAdminsEnabledRequests; + base::flat_map, base::flat_set>> _chatAdminsToSave; + base::flat_map, base::flat_set> _chatAdminsSaveRequests; + base::Observable _fullPeerUpdated; }; diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 3d4402b11..5f8f4bfb3 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -1,2785 +1,2890 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "app.h" #ifdef OS_MAC_OLD #include #endif // OS_MAC_OLD -#include "styles/style_overview.h" -#include "styles/style_mediaview.h" -#include "styles/style_chat_helpers.h" -#include "styles/style_history.h" -#include "styles/style_boxes.h" -#include "lang/lang_keys.h" +#include "apiwrap.h" +#include "application.h" +#include "auth_session.h" #include "data/data_abstract_structure.h" -#include "history/history_service_layout.h" #include "history/history_location_manager.h" #include "history/history_media_types.h" -#include "media/media_audio.h" +#include "history/history_service_layout.h" #include "inline_bots/inline_bot_layout_item.h" -#include "messenger.h" -#include "application.h" -#include "storage/file_upload.h" -#include "mainwindow.h" +#include "lang/lang_keys.h" #include "mainwidget.h" -#include "storage/localstorage.h" -#include "apiwrap.h" +#include "mainwindow.h" +#include "media/media_audio.h" +#include "messenger.h" #include "numbers.h" #include "observer_peer.h" -#include "auth_session.h" -#include "window/themes/window_theme.h" -#include "window/notifications_manager.h" #include "platform/platform_notifications_manager.h" +#include "storage/file_upload.h" +#include "storage/localstorage.h" +#include "styles/style_boxes.h" +#include "styles/style_chat_helpers.h" +#include "styles/style_history.h" +#include "styles/style_mediaview.h" +#include "styles/style_overview.h" +#include "window/notifications_manager.h" +#include "window/themes/window_theme.h" + +#include +#include +#include +#include // used in list of PhotosData namespace { - App::LaunchState _launchState = App::Launched; +App::LaunchState _launchState = App::Launched; - UserData *self = nullptr; +UserData *self = nullptr; - using PeersData = QHash; - PeersData peersData; +using PeersData = QHash; +PeersData peersData; - using MutedPeers = QMap; - MutedPeers mutedPeers; +using MutedPeers = QMap; +MutedPeers mutedPeers; - PhotosData photosData; - DocumentsData documentsData; +PhotosData photosData; +DocumentsData documentsData; - using LocationsData = QHash; - LocationsData locationsData; +using LocationsData = QHash; +LocationsData locationsData; - using WebPagesData = QHash; - WebPagesData webPagesData; +using WebPagesData = QHash; +WebPagesData webPagesData; - using GamesData = QHash; - GamesData gamesData; +using GamesData = QHash; +GamesData gamesData; - PhotoItems photoItems; - DocumentItems documentItems; - WebPageItems webPageItems; - GameItems gameItems; - SharedContactItems sharedContactItems; - GifItems gifItems; +PhotoItems photoItems; +DocumentItems documentItems; +WebPageItems webPageItems; +GameItems gameItems; +SharedContactItems sharedContactItems; +GifItems gifItems; - using DependentItemsSet = OrderedSet; - using DependentItems = QMap; - DependentItems dependentItems; +using DependentItemsSet = std::set; +using DependentItems = QMap; +DependentItems dependentItems; - Histories histories; +Histories histories; - using MsgsData = QHash; - MsgsData msgsData; - using ChannelMsgsData = QMap; - ChannelMsgsData channelMsgsData; +using MsgsData = QHash; +MsgsData msgsData; +using ChannelMsgsData = QMap; +ChannelMsgsData channelMsgsData; - using RandomData = QMap; - RandomData randomData; +using RandomData = QMap; +RandomData randomData; - using SentData = QMap>; - SentData sentData; +using SentData = QMap>; +SentData sentData; - HistoryItem *hoveredItem = nullptr, - *pressedItem = nullptr, - *hoveredLinkItem = nullptr, - *pressedLinkItem = nullptr, - *contextItem = nullptr, - *mousedItem = nullptr; +HistoryItem *hoveredItem = nullptr, *pressedItem = nullptr, *hoveredLinkItem = nullptr, *pressedLinkItem = nullptr, + *contextItem = nullptr, *mousedItem = nullptr; - QPixmap *emoji = nullptr, *emojiLarge = nullptr; - style::font monofont; +QPixmap *emoji = nullptr, *emojiLarge = nullptr; +style::font monofont; - struct CornersPixmaps { - QPixmap p[4]; - }; - QVector corners; - using CornersMap = QMap; - CornersMap cornersMap; - QImage cornersMaskLarge[4], cornersMaskSmall[4]; +struct CornersPixmaps { + QPixmap p[4]; +}; +QVector corners; +using CornersMap = QMap; +CornersMap cornersMap; +QImage cornersMaskLarge[4], cornersMaskSmall[4]; - using EmojiImagesMap = QMap; - EmojiImagesMap MainEmojiMap; - QMap OtherEmojiMap; +using EmojiImagesMap = QMap; +EmojiImagesMap MainEmojiMap; +QMap OtherEmojiMap; - int32 serviceImageCacheSize = 0; +qint32 serviceImageCacheSize = 0; - using LastPhotosList = QLinkedList; - LastPhotosList lastPhotos; - using LastPhotosMap = QHash; - LastPhotosMap lastPhotosMap; -} +using LastPhotosList = QLinkedList; +LastPhotosList lastPhotos; +using LastPhotosMap = QHash; +LastPhotosMap lastPhotosMap; +} // namespace namespace App { - QString formatPhone(QString phone) { - if (phone.isEmpty()) return QString(); - if (phone.at(0) == '0') return phone; +QString formatPhone(QString phone) { + if (phone.isEmpty()) return QString(); + if (phone.at(0) == '0') return phone; - QString number = phone; - for (const QChar *ch = phone.constData(), *e = ch + phone.size(); ch != e; ++ch) { - if (ch->unicode() < '0' || ch->unicode() > '9') { - number = phone.replace(QRegularExpression(qsl("[^\\d]")), QString()); - } + QString number = phone; + for (const QChar *ch = phone.constData(), *e = ch + phone.size(); ch != e; ++ch) { + if (ch->unicode() < '0' || ch->unicode() > '9') { + number = phone.replace(QRegularExpression(qsl("[^\\d]")), QString()); } - QVector groups = phoneNumberParse(number); - if (groups.isEmpty()) return '+' + number; + } + QVector groups = phoneNumberParse(number); + if (groups.isEmpty()) return '+' + number; - QString result; - result.reserve(number.size() + groups.size() + 1); - result.append('+'); - int32 sum = 0; - for (int32 i = 0, l = groups.size(); i < l; ++i) { - result.append(number.midRef(sum, groups.at(i))); - sum += groups.at(i); - if (sum < number.size()) result.append(' '); - } - if (sum < number.size()) result.append(number.midRef(sum)); - return result; + QString result; + result.reserve(number.size() + groups.size() + 1); + result.append('+'); + qint32 sum = 0; + for (qint32 i = 0, l = groups.size(); i < l; ++i) { + result.append(number.midRef(sum, groups.at(i))); + sum += groups.at(i); + if (sum < number.size()) result.append(' '); } + if (sum < number.size()) result.append(number.midRef(sum)); + return result; +} - MainWindow *wnd() { - if (auto instance = Messenger::InstancePointer()) { - return instance->getActiveWindow(); - } - return nullptr; +MainWindow *wnd() { + if (auto instance = Messenger::InstancePointer()) { + return instance->getActiveWindow(); } + return nullptr; +} - MainWidget *main() { - if (auto window = wnd()) { - return window->mainWidget(); - } - return nullptr; +MainWidget *main() { + if (auto window = wnd()) { + return window->mainWidget(); } + return nullptr; +} - bool passcoded() { - if (auto window = wnd()) { - return window->passcodeWidget(); - } - return false; +bool passcoded() { + if (auto window = wnd()) { + return window->passcodeWidget(); } + return false; +} namespace { - bool loggedOut() { - if (Global::LocalPasscode()) { - Global::SetLocalPasscode(false); - Global::RefLocalPasscodeChanged().notify(); - } - Media::Player::mixer()->stopAndClear(); - if (auto w = wnd()) { - w->tempDirDelete(Local::ClearManagerAll); - w->setupIntro(); - } - histories().clear(); - Messenger::Instance().authSessionDestroy(); - Local::reset(); - Window::Theme::Background()->reset(); - - cSetOtherOnline(0); - globalNotifyAllPtr = UnknownNotifySettings; - globalNotifyUsersPtr = UnknownNotifySettings; - globalNotifyChatsPtr = UnknownNotifySettings; - clearStorageImages(); - if (auto w = wnd()) { - w->updateConnectingStatus(); - } - return true; - } +bool loggedOut() { + if (Global::LocalPasscode()) { + Global::SetLocalPasscode(false); + Global::RefLocalPasscodeChanged().notify(); + } + Media::Player::mixer()->stopAndClear(); + if (auto w = wnd()) { + w->tempDirDelete(Local::ClearManagerAll); + w->setupIntro(); + } + histories().clear(); + Messenger::Instance().authSessionDestroy(); + Local::reset(); + Window::Theme::Background()->reset(); + + cSetOtherOnline(0); + globalNotifyAllPtr = UnknownNotifySettings; + globalNotifyUsersPtr = UnknownNotifySettings; + globalNotifyChatsPtr = UnknownNotifySettings; + clearStorageImages(); + if (auto w = wnd()) { + w->updateConnectingStatus(); + } + return true; +} } // namespace - void logOut() { - if (auto mtproto = Messenger::Instance().mtp()) { - mtproto->logout(rpcDone(&loggedOut), rpcFail(&loggedOut)); - } else { - // We log out because we've forgotten passcode. - // So we just start mtproto from scratch. - Messenger::Instance().startMtp(); - loggedOut(); - } +void logOut() { + if (auto mtproto = Messenger::Instance().mtp()) { + mtproto->logout(rpcDone([] { return loggedOut(); }), rpcFail([] { return loggedOut(); })); + } else { + // We log out because we've forgotten passcode. + // So we just start mtproto from scratch. + Messenger::Instance().startMtp(); + loggedOut(); } +} - TimeId onlineForSort(UserData *user, TimeId now) { - if (isServiceUser(user->id) || user->botInfo) { - return -1; - } - TimeId online = user->onlineTill; - if (online <= 0) { - switch (online) { - case 0: - case -1: return online; +TimeId onlineForSort(UserData *user, TimeId now) { + if (isServiceUser(user->id) || user->botInfo) { + return -1; + } + TimeId online = user->onlineTill; + if (online <= 0) { + switch (online) { + case 0: + case -1: return online; - case -2: { - QDate yesterday(date(now).date()); - return int32(QDateTime(yesterday.addDays(-3)).toTime_t()) + (unixtime() - myunixtime()); - } break; + case -2: { + QDate yesterday(date(now).date()); + return qint32(QDateTime(yesterday.addDays(-3)).toTime_t()) + (unixtime() - myunixtime()); + } break; - case -3: { - QDate weekago(date(now).date()); - return int32(QDateTime(weekago.addDays(-7)).toTime_t()) + (unixtime() - myunixtime()); - } break; + case -3: { + QDate weekago(date(now).date()); + return qint32(QDateTime(weekago.addDays(-7)).toTime_t()) + (unixtime() - myunixtime()); + } break; - case -4: { - QDate monthago(date(now).date()); - return int32(QDateTime(monthago.addDays(-30)).toTime_t()) + (unixtime() - myunixtime()); - } break; - } - return -online; + case -4: { + QDate monthago(date(now).date()); + return qint32(QDateTime(monthago.addDays(-30)).toTime_t()) + (unixtime() - myunixtime()); + } break; } - return online; + return -online; } + return online; +} - int32 onlineWillChangeIn(UserData *user, TimeId now) { - if (isServiceUser(user->id) || user->botInfo) { - return 86400; - } - return onlineWillChangeIn(user->onlineTill, now); +qint32 onlineWillChangeIn(UserData *user, TimeId now) { + if (isServiceUser(user->id) || user->botInfo) { + return 86400; } + return onlineWillChangeIn(user->onlineTill, now); +} - int32 onlineWillChangeIn(TimeId online, TimeId now) { - if (online <= 0) { - if (-online > now) return -online - now; - return 86400; - } - if (online > now) { - return online - now; - } - int32 minutes = (now - online) / 60; - if (minutes < 60) { - return (minutes + 1) * 60 - (now - online); - } - int32 hours = (now - online) / 3600; - if (hours < 12) { - return (hours + 1) * 3600 - (now - online); - } - QDateTime dNow(date(now)), dTomorrow(dNow.date().addDays(1)); - return dNow.secsTo(dTomorrow); +qint32 onlineWillChangeIn(TimeId online, TimeId now) { + if (online <= 0) { + if (-online > now) return -online - now; + return 86400; + } + if (online > now) { + return online - now; } + qint32 minutes = (now - online) / 60; + if (minutes < 60) { + return (minutes + 1) * 60 - (now - online); + } + qint32 hours = (now - online) / 3600; + if (hours < 12) { + return (hours + 1) * 3600 - (now - online); + } + QDateTime dNow(date(now)), dTomorrow(dNow.date().addDays(1)); + return dNow.secsTo(dTomorrow); +} - QString onlineText(UserData *user, TimeId now, bool precise) { - if (isNotificationsUser(user->id)) { - return lang(lng_status_service_notifications); - } else if (user->botInfo) { - return lang(lng_status_bot); - } else if (isServiceUser(user->id)) { - return lang(lng_status_support); - } - return onlineText(user->onlineTill, now, precise); +QString onlineText(UserData *user, TimeId now, bool precise) { + if (isNotificationsUser(user->id)) { + return lang(lng_status_service_notifications); + } else if (user->botInfo) { + return lang(lng_status_bot); + } else if (isServiceUser(user->id)) { + return lang(lng_status_support); } + return onlineText(user->onlineTill, now, precise); +} - QString onlineText(TimeId online, TimeId now, bool precise) { - if (online <= 0) { - switch (online) { - case 0: - case -1: return lang(lng_status_offline); - case -2: return lang(lng_status_recently); - case -3: return lang(lng_status_last_week); - case -4: return lang(lng_status_last_month); - } - return (-online > now) ? lang(lng_status_online) : lang(lng_status_recently); - } - if (online > now) { - return lang(lng_status_online); - } - QString when; - if (precise) { - QDateTime dOnline(date(online)), dNow(date(now)); - if (dOnline.date() == dNow.date()) { - return lng_status_lastseen_today(lt_time, dOnline.time().toString(cTimeFormat())); - } else if (dOnline.date().addDays(1) == dNow.date()) { - return lng_status_lastseen_yesterday(lt_time, dOnline.time().toString(cTimeFormat())); - } - return lng_status_lastseen_date_time(lt_date, dOnline.date().toString(qsl("dd.MM.yy")), lt_time, dOnline.time().toString(cTimeFormat())); - } - int32 minutes = (now - online) / 60; - if (!minutes) { - return lang(lng_status_lastseen_now); - } else if (minutes < 60) { - return lng_status_lastseen_minutes(lt_count, minutes); - } - int32 hours = (now - online) / 3600; - if (hours < 12) { - return lng_status_lastseen_hours(lt_count, hours); +QString onlineText(TimeId online, TimeId now, bool precise) { + if (online <= 0) { + switch (online) { + case 0: + case -1: return lang(lng_status_offline); + case -2: return lang(lng_status_recently); + case -3: return lang(lng_status_last_week); + case -4: return lang(lng_status_last_month); } + return (-online > now) ? lang(lng_status_online) : lang(lng_status_recently); + } + if (online > now) { + return lang(lng_status_online); + } + QString when; + if (precise) { QDateTime dOnline(date(online)), dNow(date(now)); if (dOnline.date() == dNow.date()) { return lng_status_lastseen_today(lt_time, dOnline.time().toString(cTimeFormat())); } else if (dOnline.date().addDays(1) == dNow.date()) { return lng_status_lastseen_yesterday(lt_time, dOnline.time().toString(cTimeFormat())); } - return lng_status_lastseen_date(lt_date, dOnline.date().toString(qsl("dd.MM.yy"))); + return lng_status_lastseen_date_time(lt_date, dOnline.date().toString(qsl("dd.MM.yy")), lt_time, + dOnline.time().toString(cTimeFormat())); + } + qint32 minutes = (now - online) / 60; + if (!minutes) { + return lang(lng_status_lastseen_now); + } else if (minutes < 60) { + return lng_status_lastseen_minutes(lt_count, minutes); } + qint32 hours = (now - online) / 3600; + if (hours < 12) { + return lng_status_lastseen_hours(lt_count, hours); + } + QDateTime dOnline(date(online)), dNow(date(now)); + if (dOnline.date() == dNow.date()) { + return lng_status_lastseen_today(lt_time, dOnline.time().toString(cTimeFormat())); + } else if (dOnline.date().addDays(1) == dNow.date()) { + return lng_status_lastseen_yesterday(lt_time, dOnline.time().toString(cTimeFormat())); + } + return lng_status_lastseen_date(lt_date, dOnline.date().toString(qsl("dd.MM.yy"))); +} - namespace { - // we should get a full restriction in "{fulltype}: {reason}" format and we - // need to find a "-all" tag in {fulltype}, otherwise ignore this restriction - QString extractRestrictionReason(const QString &fullRestriction) { - int fullTypeEnd = fullRestriction.indexOf(':'); - if (fullTypeEnd <= 0) { - return QString(); - } +namespace { +// we should get a full restriction in "{fulltype}: {reason}" format and we +// need to find a "-all" tag in {fulltype}, otherwise ignore this restriction +QString extractRestrictionReason(const QString &fullRestriction) { + int fullTypeEnd = fullRestriction.indexOf(':'); + if (fullTypeEnd <= 0) { + return QString(); + } - // {fulltype} is in "{type}-{tag}-{tag}-{tag}" format - // if we find "all" tag we return the restriction string - auto typeTags = fullRestriction.mid(0, fullTypeEnd).split('-').mid(1); + // {fulltype} is in "{type}-{tag}-{tag}-{tag}" format + // if we find "all" tag we return the restriction string + auto typeTags = fullRestriction.mid(0, fullTypeEnd).split('-').mid(1); #ifndef OS_MAC_STORE - auto restrictionApplies = typeTags.contains(qsl("all")); + auto restrictionApplies = typeTags.contains(qsl("all")); #else // OS_MAC_STORE - auto restrictionApplies = typeTags.contains(qsl("all")) || typeTags.contains(qsl("ios")); + auto restrictionApplies = typeTags.contains(qsl("all")) || typeTags.contains(qsl("ios")); #endif // OS_MAC_STORE - if (restrictionApplies) { - return fullRestriction.midRef(fullTypeEnd + 1).trimmed().toString(); - } - return QString(); - } + if (restrictionApplies) { + return fullRestriction.midRef(fullTypeEnd + 1).trimmed().toString(); } + return QString(); +} +} // namespace - bool onlineColorUse(UserData *user, TimeId now) { - if (isServiceUser(user->id) || user->botInfo) { - return false; - } - return onlineColorUse(user->onlineTill, now); +bool onlineColorUse(UserData *user, TimeId now) { + if (isServiceUser(user->id) || user->botInfo) { + return false; } + return onlineColorUse(user->onlineTill, now); +} - bool onlineColorUse(TimeId online, TimeId now) { - if (online <= 0) { - switch (online) { - case 0: - case -1: - case -2: - case -3: - case -4: return false; - } - return (-online > now); +bool onlineColorUse(TimeId online, TimeId now) { + if (online <= 0) { + switch (online) { + case 0: + case -1: + case -2: + case -3: + case -4: return false; } - return (online > now); + return (-online > now); } + return (online > now); +} - UserData *feedUser(const MTPUser &user) { - UserData *data = nullptr; - bool wasContact = false, minimal = false; - const MTPUserStatus *status = 0, emptyStatus = MTP_userStatusEmpty(); - - Notify::PeerUpdate update; - using UpdateFlag = Notify::PeerUpdate::Flag; - - switch (user.type()) { - case mtpc_userEmpty: { - auto &d = user.c_userEmpty(); - - auto peer = peerFromUser(d.vid.v); - data = App::user(peer); - auto canShareThisContact = data->canShareThisContactFast(); - wasContact = data->isContact(); - - data->input = MTP_inputPeerUser(d.vid, MTP_long(0)); - data->inputUser = MTP_inputUser(d.vid, MTP_long(0)); +UserData *feedUser(const MTPUser &user) { + UserData *data = nullptr; + bool wasContact = false, minimal = false; + const MTPUserStatus *status = 0, emptyStatus = MTP_userStatusEmpty(); + + Notify::PeerUpdate update; + using UpdateFlag = Notify::PeerUpdate::Flag; + + switch (user.type()) { + case mtpc_userEmpty: { + auto &d = user.c_userEmpty(); + + auto peer = peerFromUser(d.vid.v); + data = App::user(peer); + auto canShareThisContact = data->canShareThisContactFast(); + wasContact = data->isContact(); + + data->input = MTP_inputPeerUser(d.vid, MTP_long(0)); + data->inputUser = MTP_inputUser(d.vid, MTP_long(0)); + data->setName(lang(lng_deleted), QString(), QString(), QString()); + data->setPhoto(MTP_userProfilePhotoEmpty()); + data->setIsInaccessible(); + data->flags = 0; + data->setBotInfoVersion(-1); + status = &emptyStatus; + data->contact = -1; + + if (canShareThisContact != data->canShareThisContactFast()) update.flags |= UpdateFlag::UserCanShareContact; + if (wasContact != data->isContact()) update.flags |= UpdateFlag::UserIsContact; + } break; + case mtpc_user: { + auto &d = user.c_user(); + minimal = d.is_min(); + + auto peer = peerFromUser(d.vid.v); + data = App::user(peer); + auto canShareThisContact = data->canShareThisContactFast(); + wasContact = data->isContact(); + if (!minimal) { + data->flags = d.vflags.v; + if (d.is_self()) { + data->input = MTP_inputPeerSelf(); + data->inputUser = MTP_inputUserSelf(); + } else if (!d.has_access_hash()) { + data->input = MTP_inputPeerUser(d.vid, MTP_long(data->isInaccessible() ? 0 : data->access)); + data->inputUser = MTP_inputUser(d.vid, MTP_long(data->isInaccessible() ? 0 : data->access)); + } else { + data->input = MTP_inputPeerUser(d.vid, d.vaccess_hash); + data->inputUser = MTP_inputUser(d.vid, d.vaccess_hash); + } + if (d.is_restricted()) { + data->setRestrictionReason(extractRestrictionReason(qs(d.vrestriction_reason))); + } else { + data->setRestrictionReason(QString()); + } + } + if (d.is_deleted()) { + if (!data->phone().isEmpty()) { + data->setPhone(QString()); + update.flags |= UpdateFlag::UserPhoneChanged; + } data->setName(lang(lng_deleted), QString(), QString(), QString()); data->setPhoto(MTP_userProfilePhotoEmpty()); data->setIsInaccessible(); - data->flags = 0; - data->setBotInfoVersion(-1); status = &emptyStatus; - data->contact = -1; - - if (canShareThisContact != data->canShareThisContactFast()) update.flags |= UpdateFlag::UserCanShareContact; - if (wasContact != data->isContact()) update.flags |= UpdateFlag::UserIsContact; - } break; - case mtpc_user: { - auto &d = user.c_user(); - minimal = d.is_min(); - - auto peer = peerFromUser(d.vid.v); - data = App::user(peer); - auto canShareThisContact = data->canShareThisContactFast(); - wasContact = data->isContact(); - if (!minimal) { - data->flags = d.vflags.v; - if (d.is_self()) { - data->input = MTP_inputPeerSelf(); - data->inputUser = MTP_inputUserSelf(); - } else if (!d.has_access_hash()) { - data->input = MTP_inputPeerUser(d.vid, MTP_long(data->isInaccessible() ? 0 : data->access)); - data->inputUser = MTP_inputUser(d.vid, MTP_long(data->isInaccessible() ? 0 : data->access)); - } else { - data->input = MTP_inputPeerUser(d.vid, d.vaccess_hash); - data->inputUser = MTP_inputUser(d.vid, d.vaccess_hash); - } - if (d.is_restricted()) { - data->setRestrictionReason(extractRestrictionReason(qs(d.vrestriction_reason))); - } else { - data->setRestrictionReason(QString()); - } + } else { + // apply first_name and last_name from minimal user only if we don't have + // local values for first name and last name already, otherwise skip + bool noLocalName = data->firstName.isEmpty() && data->lastName.isEmpty(); + QString fname = (!minimal || noLocalName) ? + (d.has_first_name() ? TextUtilities::SingleLine(qs(d.vfirst_name)) : QString()) : + data->firstName; + QString lname = (!minimal || noLocalName) ? + (d.has_last_name() ? TextUtilities::SingleLine(qs(d.vlast_name)) : QString()) : + data->lastName; + + QString phone = minimal ? data->phone() : (d.has_phone() ? qs(d.vphone) : QString()); + QString uname = + minimal ? data->username : (d.has_username() ? TextUtilities::SingleLine(qs(d.vusername)) : QString()); + + bool phoneChanged = (data->phone() != phone); + if (phoneChanged) { + data->setPhone(phone); + update.flags |= UpdateFlag::UserPhoneChanged; + } + bool nameChanged = (data->firstName != fname) || (data->lastName != lname); + + bool showPhone = !isServiceUser(data->id) && !d.is_self() && !d.is_contact() && !d.is_mutual_contact(); + bool showPhoneChanged = !isServiceUser(data->id) && !d.is_self() && + ((showPhone && data->contact) || (!showPhone && !data->contact)); + if (minimal) { + showPhoneChanged = false; + showPhone = !isServiceUser(data->id) && (data->id != Auth().userPeerId()) && !data->contact; } - if (d.is_deleted()) { - if (!data->phone().isEmpty()) { - data->setPhone(QString()); - update.flags |= UpdateFlag::UserPhoneChanged; - } - data->setName(lang(lng_deleted), QString(), QString(), QString()); - data->setPhoto(MTP_userProfilePhotoEmpty()); - data->setIsInaccessible(); - status = &emptyStatus; - } else { - // apply first_name and last_name from minimal user only if we don't have - // local values for first name and last name already, otherwise skip - bool noLocalName = data->firstName.isEmpty() && data->lastName.isEmpty(); - QString fname = (!minimal || noLocalName) ? (d.has_first_name() ? TextUtilities::SingleLine(qs(d.vfirst_name)) : QString()) : data->firstName; - QString lname = (!minimal || noLocalName) ? (d.has_last_name() ? TextUtilities::SingleLine(qs(d.vlast_name)) : QString()) : data->lastName; - - QString phone = minimal ? data->phone() : (d.has_phone() ? qs(d.vphone) : QString()); - QString uname = minimal ? data->username : (d.has_username() ? TextUtilities::SingleLine(qs(d.vusername)) : QString()); - - bool phoneChanged = (data->phone() != phone); - if (phoneChanged) { - data->setPhone(phone); - update.flags |= UpdateFlag::UserPhoneChanged; - } - bool nameChanged = (data->firstName != fname) || (data->lastName != lname); - - bool showPhone = !isServiceUser(data->id) && !d.is_self() && !d.is_contact() && !d.is_mutual_contact(); - bool showPhoneChanged = !isServiceUser(data->id) && !d.is_self() && ((showPhone && data->contact) || (!showPhone && !data->contact)); - if (minimal) { - showPhoneChanged = false; - showPhone = !isServiceUser(data->id) && (data->id != Auth().userPeerId()) && !data->contact; - } - // see also Local::readPeer + // see also Local::readPeer - QString pname = (showPhoneChanged || phoneChanged || nameChanged) ? ((showPhone && !phone.isEmpty()) ? formatPhone(phone) : QString()) : data->nameOrPhone; + QString pname = (showPhoneChanged || phoneChanged || nameChanged) ? + ((showPhone && !phone.isEmpty()) ? formatPhone(phone) : QString()) : + data->nameOrPhone; - if (!minimal && d.is_self() && uname != data->username) { - SignalHandlers::setCrashAnnotation("Username", uname); - } - data->setName(fname, lname, pname, uname); - if (d.has_photo()) { - data->setPhoto(d.vphoto); - } else { - data->setPhoto(MTP_userProfilePhotoEmpty()); - } - if (d.has_access_hash()) data->access = d.vaccess_hash.v; - status = d.has_status() ? &d.vstatus : &emptyStatus; + if (!minimal && d.is_self() && uname != data->username) { + SignalHandlers::setCrashAnnotation("Username", uname); } - if (!minimal) { - if (d.has_bot_info_version()) { - data->setBotInfoVersion(d.vbot_info_version.v); - data->botInfo->readsAllHistory = d.is_bot_chat_history(); - if (data->botInfo->cantJoinGroups != d.is_bot_nochats()) { - data->botInfo->cantJoinGroups = d.is_bot_nochats(); - update.flags |= UpdateFlag::BotCanAddToGroups; - } - data->botInfo->inlinePlaceholder = d.has_bot_inline_placeholder() ? '_' + qs(d.vbot_inline_placeholder) : QString(); - } else { - data->setBotInfoVersion(-1); - } - data->contact = (d.is_contact() || d.is_mutual_contact()) ? 1 : (data->phone().isEmpty() ? -1 : 0); - if (data->contact == 1 && cReportSpamStatuses().value(data->id, dbiprsHidden) != dbiprsHidden) { - cRefReportSpamStatuses().insert(data->id, dbiprsHidden); - Local::writeReportSpamStatuses(); - } - if (d.is_self() && ::self != data) { - ::self = data; - Global::RefSelfChanged().notify(); + data->setName(fname, lname, pname, uname); + if (d.has_photo()) { + data->setPhoto(d.vphoto); + } else { + data->setPhoto(MTP_userProfilePhotoEmpty()); + } + if (d.has_access_hash()) data->access = d.vaccess_hash.v; + status = d.has_status() ? &d.vstatus : &emptyStatus; + } + if (!minimal) { + if (d.has_bot_info_version()) { + data->setBotInfoVersion(d.vbot_info_version.v); + data->botInfo->readsAllHistory = d.is_bot_chat_history(); + if (data->botInfo->cantJoinGroups != d.is_bot_nochats()) { + data->botInfo->cantJoinGroups = d.is_bot_nochats(); + update.flags |= UpdateFlag::BotCanAddToGroups; } + data->botInfo->inlinePlaceholder = + d.has_bot_inline_placeholder() ? '_' + qs(d.vbot_inline_placeholder) : QString(); + } else { + data->setBotInfoVersion(-1); + } + data->contact = (d.is_contact() || d.is_mutual_contact()) ? 1 : (data->phone().isEmpty() ? -1 : 0); + if (data->contact == 1 && cReportSpamStatuses().value(data->id, dbiprsHidden) != dbiprsHidden) { + cRefReportSpamStatuses().insert(data->id, dbiprsHidden); + Local::writeReportSpamStatuses(); + } + if (d.is_self() && ::self != data) { + ::self = data; + Global::RefSelfChanged().notify(); } - - if (canShareThisContact != data->canShareThisContactFast()) update.flags |= UpdateFlag::UserCanShareContact; - if (wasContact != data->isContact()) update.flags |= UpdateFlag::UserIsContact; - } break; } - if (!data) { - return nullptr; - } + if (canShareThisContact != data->canShareThisContactFast()) update.flags |= UpdateFlag::UserCanShareContact; + if (wasContact != data->isContact()) update.flags |= UpdateFlag::UserIsContact; + } break; + } - if (minimal) { - if (data->loadedStatus == PeerData::NotLoaded) { - data->loadedStatus = PeerData::MinimalLoaded; - } - } else if (data->loadedStatus != PeerData::FullLoaded) { - data->loadedStatus = PeerData::FullLoaded; + if (!data) { + return nullptr; + } + + if (minimal) { + if (data->loadedStatus == PeerData::NotLoaded) { + data->loadedStatus = PeerData::MinimalLoaded; } + } else if (data->loadedStatus != PeerData::FullLoaded) { + data->loadedStatus = PeerData::FullLoaded; + } - if (status && !minimal) { - auto oldOnlineTill = data->onlineTill; - auto newOnlineTill = Auth().api().onlineTillFromStatus(*status, oldOnlineTill); - if (oldOnlineTill != newOnlineTill) { - data->onlineTill = newOnlineTill; - update.flags |= UpdateFlag::UserOnlineChanged; - } + if (status && !minimal) { + auto oldOnlineTill = data->onlineTill; + auto newOnlineTill = Auth().api().onlineTillFromStatus(*status, oldOnlineTill); + if (oldOnlineTill != newOnlineTill) { + data->onlineTill = newOnlineTill; + update.flags |= UpdateFlag::UserOnlineChanged; } + } - if (data->contact < 0 && !data->phone().isEmpty() && data->id != Auth().userPeerId()) { - data->contact = 0; + if (data->contact < 0 && !data->phone().isEmpty() && data->id != Auth().userPeerId()) { + data->contact = 0; + } + if (App::main()) { + if ((data->contact > 0 && !wasContact) || (wasContact && data->contact < 1)) { + Notify::userIsContactChanged(data); } - if (App::main()) { - if ((data->contact > 0 && !wasContact) || (wasContact && data->contact < 1)) { - Notify::userIsContactChanged(data); - } - if (update.flags) { - update.peer = data; - Notify::peerUpdatedDelayed(update); - } + if (update.flags) { + update.peer = data; + Notify::peerUpdatedDelayed(update); } - return data; } + return data; +} - UserData *feedUsers(const MTPVector &users) { - UserData *result = nullptr; - for_const (auto &user, users.v) { - if (auto feededUser = feedUser(user)) { - result = feededUser; - } +UserData *feedUsers(const MTPVector &users) { + UserData *result = nullptr; + for_const (auto &user, users.v) { + if (auto feededUser = feedUser(user)) { + result = feededUser; } - - return result; } - PeerData *feedChat(const MTPChat &chat) { - PeerData *data = nullptr; - bool minimal = false; + return result; +} - Notify::PeerUpdate update; - using UpdateFlag = Notify::PeerUpdate::Flag; +PeerData *feedChat(const MTPChat &chat) { + PeerData *data = nullptr; + bool minimal = false; - switch (chat.type()) { - case mtpc_chat: { - auto &d(chat.c_chat()); + Notify::PeerUpdate update; + using UpdateFlag = Notify::PeerUpdate::Flag; - data = App::chat(peerFromChat(d.vid.v)); - auto cdata = data->asChat(); - auto canEdit = cdata->canEdit(); + switch (chat.type()) { + case mtpc_chat: { + auto &d(chat.c_chat()); - if (cdata->version < d.vversion.v) { - cdata->version = d.vversion.v; - cdata->invalidateParticipants(); - } + data = App::chat(peerFromChat(d.vid.v)); + auto cdata = data->asChat(); + auto canEdit = cdata->canEdit(); - data->input = MTP_inputPeerChat(d.vid); - cdata->setName(qs(d.vtitle)); - cdata->setPhoto(d.vphoto); - cdata->date = d.vdate.v; + if (cdata->version < d.vversion.v) { + cdata->version = d.vversion.v; + cdata->invalidateParticipants(); + } - if (d.has_migrated_to() && d.vmigrated_to.type() == mtpc_inputChannel) { - const auto &c(d.vmigrated_to.c_inputChannel()); - ChannelData *channel = App::channel(peerFromChannel(c.vchannel_id)); - if (!channel->mgInfo) { - channel->flags |= MTPDchannel::Flag::f_megagroup; - channel->flagsUpdated(); - } - if (!channel->access) { - channel->input = MTP_inputPeerChannel(c.vchannel_id, c.vaccess_hash); - channel->inputChannel = d.vmigrated_to; - channel->access = d.vmigrated_to.c_inputChannel().vaccess_hash.v; - } - bool updatedTo = (cdata->migrateToPtr != channel), updatedFrom = (channel->mgInfo->migrateFromPtr != cdata); - if (updatedTo) { - cdata->migrateToPtr = channel; - } - if (updatedFrom) { - channel->mgInfo->migrateFromPtr = cdata; - if (History *h = App::historyLoaded(cdata->id)) { - if (History *hto = App::historyLoaded(channel->id)) { - if (!h->isEmpty()) { - h->clear(true); - } - if (hto->inChatList(Dialogs::Mode::All) && h->inChatList(Dialogs::Mode::All)) { - App::removeDialog(h); - } + data->input = MTP_inputPeerChat(d.vid); + cdata->setName(qs(d.vtitle)); + cdata->setPhoto(d.vphoto); + cdata->date = d.vdate.v; + + if (d.has_migrated_to() && d.vmigrated_to.type() == mtpc_inputChannel) { + const auto &c(d.vmigrated_to.c_inputChannel()); + ChannelData *channel = App::channel(peerFromChannel(c.vchannel_id)); + if (!channel->mgInfo) { + channel->flags |= MTPDchannel::Flag::f_megagroup; + channel->flagsUpdated(); + } + if (!channel->access) { + channel->input = MTP_inputPeerChannel(c.vchannel_id, c.vaccess_hash); + channel->inputChannel = d.vmigrated_to; + channel->access = d.vmigrated_to.c_inputChannel().vaccess_hash.v; + } + bool updatedTo = (cdata->migrateToPtr != channel), updatedFrom = (channel->mgInfo->migrateFromPtr != cdata); + if (updatedTo) { + cdata->migrateToPtr = channel; + } + if (updatedFrom) { + channel->mgInfo->migrateFromPtr = cdata; + if (History *h = App::historyLoaded(cdata->id)) { + if (History *hto = App::historyLoaded(channel->id)) { + if (!h->isEmpty()) { + h->clear(true); + } + if (hto->inChatList(Dialogs::Mode::All) && h->inChatList(Dialogs::Mode::All)) { + App::removeDialog(h); } } - Notify::migrateUpdated(channel); - update.flags |= UpdateFlag::MigrationChanged; - } - if (updatedTo) { - Notify::migrateUpdated(cdata); - update.flags |= UpdateFlag::MigrationChanged; } + Notify::migrateUpdated(channel); + update.flags |= UpdateFlag::MigrationChanged; } - - if (!(cdata->flags & MTPDchat::Flag::f_admins_enabled) && (d.vflags.v & MTPDchat::Flag::f_admins_enabled)) { - cdata->invalidateParticipants(); + if (updatedTo) { + Notify::migrateUpdated(cdata); + update.flags |= UpdateFlag::MigrationChanged; } - cdata->flags = d.vflags.v; + } - cdata->count = d.vparticipants_count.v; - cdata->setIsForbidden(false); - if (canEdit != cdata->canEdit()) { - update.flags |= UpdateFlag::ChatCanEdit; - } - } break; - case mtpc_chatForbidden: { - auto &d(chat.c_chatForbidden()); - - data = App::chat(peerFromChat(d.vid.v)); - auto cdata = data->asChat(); - auto canEdit = cdata->canEdit(); - - data->input = MTP_inputPeerChat(d.vid); - cdata->setName(qs(d.vtitle)); - cdata->setPhoto(MTP_chatPhotoEmpty()); - cdata->date = 0; - cdata->count = -1; + if (!(cdata->flags & MTPDchat::Flag::f_admins_enabled) && (d.vflags.v & MTPDchat::Flag::f_admins_enabled)) { cdata->invalidateParticipants(); - cdata->flags = 0; - cdata->setIsForbidden(true); - if (canEdit != cdata->canEdit()) { - update.flags |= UpdateFlag::ChatCanEdit; - } - } break; - case mtpc_channel: { - auto &d = chat.c_channel(); - - auto peerId = peerFromChannel(d.vid.v); - minimal = d.is_min(); - if (minimal) { - data = App::channelLoaded(peerId); - if (!data) { - return nullptr; // minimal is not loaded, need to make getDifference - } - } else { - data = App::channel(peerId); - data->input = MTP_inputPeerChannel(d.vid, d.has_access_hash() ? d.vaccess_hash : MTP_long(0)); + } + cdata->flags = d.vflags.v; + + cdata->count = d.vparticipants_count.v; + cdata->setIsForbidden(false); + if (canEdit != cdata->canEdit()) { + update.flags |= UpdateFlag::ChatCanEdit; + } + } break; + case mtpc_chatForbidden: { + auto &d(chat.c_chatForbidden()); + + data = App::chat(peerFromChat(d.vid.v)); + auto cdata = data->asChat(); + auto canEdit = cdata->canEdit(); + + data->input = MTP_inputPeerChat(d.vid); + cdata->setName(qs(d.vtitle)); + cdata->setPhoto(MTP_chatPhotoEmpty()); + cdata->date = 0; + cdata->count = -1; + cdata->invalidateParticipants(); + cdata->flags = 0; + cdata->setIsForbidden(true); + if (canEdit != cdata->canEdit()) { + update.flags |= UpdateFlag::ChatCanEdit; + } + } break; + case mtpc_channel: { + auto &d = chat.c_channel(); + + auto peerId = peerFromChannel(d.vid.v); + minimal = d.is_min(); + if (minimal) { + data = App::channelLoaded(peerId); + if (!data) { + return nullptr; // minimal is not loaded, need to make getDifference } + } else { + data = App::channel(peerId); + data->input = MTP_inputPeerChannel(d.vid, d.has_access_hash() ? d.vaccess_hash : MTP_long(0)); + } - auto cdata = data->asChannel(); - auto wasInChannel = cdata->amIn(); - auto canViewAdmins = cdata->canViewAdmins(); - auto canViewMembers = cdata->canViewMembers(); - auto canAddMembers = cdata->canAddMembers(); + auto cdata = data->asChannel(); + auto wasInChannel = cdata->amIn(); + auto canViewAdmins = cdata->canViewAdmins(); + auto canViewMembers = cdata->canViewMembers(); + auto canAddMembers = cdata->canAddMembers(); - if (minimal) { - auto mask = MTPDchannel::Flag::f_broadcast | MTPDchannel::Flag::f_verified | MTPDchannel::Flag::f_megagroup | MTPDchannel::Flag::f_democracy; - cdata->flags = (cdata->flags & ~mask) | (d.vflags.v & mask); + if (minimal) { + auto mask = MTPDchannel::Flag::f_broadcast | MTPDchannel::Flag::f_verified | + MTPDchannel::Flag::f_megagroup | MTPDchannel::Flag::f_democracy; + cdata->flags = (cdata->flags & ~mask) | (d.vflags.v & mask); + } else { + if (d.has_admin_rights()) { + cdata->setAdminRights(d.vadmin_rights); + } else if (cdata->hasAdminRights()) { + cdata->setAdminRights(MTP_channelAdminRights(MTP_flags(0))); + } + if (d.has_banned_rights()) { + cdata->setRestrictedRights(d.vbanned_rights); + } else if (cdata->hasRestrictedRights()) { + cdata->setRestrictedRights(MTP_channelBannedRights(MTP_flags(0), MTP_int(0))); + } + cdata->inputChannel = MTP_inputChannel(d.vid, d.vaccess_hash); + cdata->access = d.vaccess_hash.v; + cdata->date = d.vdate.v; + if (cdata->version < d.vversion.v) { + cdata->version = d.vversion.v; + } + if (d.is_restricted()) { + cdata->setRestrictionReason(extractRestrictionReason(qs(d.vrestriction_reason))); } else { - if (d.has_admin_rights()) { - cdata->setAdminRights(d.vadmin_rights); - } else if (cdata->hasAdminRights()) { - cdata->setAdminRights(MTP_channelAdminRights(MTP_flags(0))); - } - if (d.has_banned_rights()) { - cdata->setRestrictedRights(d.vbanned_rights); - } else if (cdata->hasRestrictedRights()) { - cdata->setRestrictedRights(MTP_channelBannedRights(MTP_flags(0), MTP_int(0))); - } - cdata->inputChannel = MTP_inputChannel(d.vid, d.vaccess_hash); - cdata->access = d.vaccess_hash.v; - cdata->date = d.vdate.v; - if (cdata->version < d.vversion.v) { - cdata->version = d.vversion.v; - } - if (d.is_restricted()) { - cdata->setRestrictionReason(extractRestrictionReason(qs(d.vrestriction_reason))); - } else { - cdata->setRestrictionReason(QString()); - } - cdata->flags = d.vflags.v; + cdata->setRestrictionReason(QString()); } - cdata->flagsUpdated(); - - QString uname = d.has_username() ? TextUtilities::SingleLine(qs(d.vusername)) : QString(); - cdata->setName(qs(d.vtitle), uname); - - cdata->setIsForbidden(false); - cdata->setPhoto(d.vphoto); + cdata->flags = d.vflags.v; + } + cdata->flagsUpdated(); - if (wasInChannel != cdata->amIn()) update.flags |= UpdateFlag::ChannelAmIn; - if (canViewAdmins != cdata->canViewAdmins() - || canViewMembers != cdata->canViewMembers() - || canAddMembers != cdata->canAddMembers()) update.flags |= UpdateFlag::ChannelRightsChanged; - } break; - case mtpc_channelForbidden: { - auto &d(chat.c_channelForbidden()); + QString uname = d.has_username() ? TextUtilities::SingleLine(qs(d.vusername)) : QString(); + cdata->setName(qs(d.vtitle), uname); - auto peerId = peerFromChannel(d.vid.v); - data = App::channel(peerId); - data->input = MTP_inputPeerChannel(d.vid, d.vaccess_hash); + cdata->setIsForbidden(false); + cdata->setPhoto(d.vphoto); - auto cdata = data->asChannel(); - auto wasInChannel = cdata->amIn(); - auto canViewAdmins = cdata->canViewAdmins(); - auto canViewMembers = cdata->canViewMembers(); - auto canAddMembers = cdata->canAddMembers(); + if (wasInChannel != cdata->amIn()) update.flags |= UpdateFlag::ChannelAmIn; + if (canViewAdmins != cdata->canViewAdmins() || canViewMembers != cdata->canViewMembers() || + canAddMembers != cdata->canAddMembers()) + update.flags |= UpdateFlag::ChannelRightsChanged; + } break; + case mtpc_channelForbidden: { + auto &d(chat.c_channelForbidden()); - cdata->inputChannel = MTP_inputChannel(d.vid, d.vaccess_hash); + auto peerId = peerFromChannel(d.vid.v); + data = App::channel(peerId); + data->input = MTP_inputPeerChannel(d.vid, d.vaccess_hash); - auto mask = mtpCastFlags(MTPDchannelForbidden::Flag::f_broadcast | MTPDchannelForbidden::Flag::f_megagroup); - cdata->flags = (cdata->flags & ~mask) | (mtpCastFlags(d.vflags) & mask); - cdata->flagsUpdated(); + auto cdata = data->asChannel(); + auto wasInChannel = cdata->amIn(); + auto canViewAdmins = cdata->canViewAdmins(); + auto canViewMembers = cdata->canViewMembers(); + auto canAddMembers = cdata->canAddMembers(); - if (cdata->hasAdminRights()) { - cdata->setAdminRights(MTP_channelAdminRights(MTP_flags(0))); - } - if (cdata->hasRestrictedRights()) { - cdata->setRestrictedRights(MTP_channelBannedRights(MTP_flags(0), MTP_int(0))); - } + cdata->inputChannel = MTP_inputChannel(d.vid, d.vaccess_hash); - cdata->setName(qs(d.vtitle), QString()); + auto mask = mtpCastFlags(MTPDchannelForbidden::Flag::f_broadcast | MTPDchannelForbidden::Flag::f_megagroup); + cdata->flags = (cdata->flags & ~mask) | (mtpCastFlags(d.vflags) & mask); + cdata->flagsUpdated(); - cdata->access = d.vaccess_hash.v; - cdata->setPhoto(MTP_chatPhotoEmpty()); - cdata->date = 0; - cdata->setMembersCount(0); - cdata->setIsForbidden(true); - - if (wasInChannel != cdata->amIn()) update.flags |= UpdateFlag::ChannelAmIn; - if (canViewAdmins != cdata->canViewAdmins() - || canViewMembers != cdata->canViewMembers() - || canAddMembers != cdata->canAddMembers()) update.flags |= UpdateFlag::ChannelRightsChanged; - } break; + if (cdata->hasAdminRights()) { + cdata->setAdminRights(MTP_channelAdminRights(MTP_flags(0))); } - if (!data) { - return nullptr; + if (cdata->hasRestrictedRights()) { + cdata->setRestrictedRights(MTP_channelBannedRights(MTP_flags(0), MTP_int(0))); } - if (minimal) { - if (data->loadedStatus == PeerData::NotLoaded) { - data->loadedStatus = PeerData::MinimalLoaded; - } - } else if (data->loadedStatus != PeerData::FullLoaded) { - data->loadedStatus = PeerData::FullLoaded; - } - if (update.flags) { - update.peer = data; - Notify::peerUpdatedDelayed(update); + cdata->setName(qs(d.vtitle), QString()); + + cdata->access = d.vaccess_hash.v; + cdata->setPhoto(MTP_chatPhotoEmpty()); + cdata->date = 0; + cdata->setMembersCount(0); + cdata->setIsForbidden(true); + + if (wasInChannel != cdata->amIn()) update.flags |= UpdateFlag::ChannelAmIn; + if (canViewAdmins != cdata->canViewAdmins() || canViewMembers != cdata->canViewMembers() || + canAddMembers != cdata->canAddMembers()) + update.flags |= UpdateFlag::ChannelRightsChanged; + } break; + } + if (!data) { + return nullptr; + } + + if (minimal) { + if (data->loadedStatus == PeerData::NotLoaded) { + data->loadedStatus = PeerData::MinimalLoaded; } - return data; + } else if (data->loadedStatus != PeerData::FullLoaded) { + data->loadedStatus = PeerData::FullLoaded; } + if (update.flags) { + update.peer = data; + Notify::peerUpdatedDelayed(update); + } + return data; +} - PeerData *feedChats(const MTPVector &chats) { - PeerData *result = nullptr; - for_const (auto &chat, chats.v) { - if (auto feededChat = feedChat(chat)) { - result = feededChat; - } +PeerData *feedChats(const MTPVector &chats) { + PeerData *result = nullptr; + for_const (auto &chat, chats.v) { + if (auto feededChat = feedChat(chat)) { + result = feededChat; } - return result; } + return result; +} - void feedParticipants(const MTPChatParticipants &p, bool requestBotInfos) { - ChatData *chat = 0; - switch (p.type()) { - case mtpc_chatParticipantsForbidden: { - const auto &d(p.c_chatParticipantsForbidden()); - chat = App::chat(d.vchat_id.v); - chat->count = -1; - chat->invalidateParticipants(); - } break; +void feedParticipants(const MTPChatParticipants &p, bool requestBotInfos) { + ChatData *chat = 0; + switch (p.type()) { + case mtpc_chatParticipantsForbidden: { + const auto &d(p.c_chatParticipantsForbidden()); + chat = App::chat(d.vchat_id.v); + chat->count = -1; + chat->invalidateParticipants(); + } break; + + case mtpc_chatParticipants: { + const auto &d(p.c_chatParticipants()); + chat = App::chat(d.vchat_id.v); + auto canEdit = chat->canEdit(); + if (!requestBotInfos || chat->version <= d.vversion.v) { // !requestBotInfos is true on getFullChat result + chat->version = d.vversion.v; + auto &v = d.vparticipants.v; + chat->count = v.size(); + qint32 pversion = chat->participants.isEmpty() ? 1 : (chat->participants.begin().value() + 1); + chat->invitedByMe.clear(); + chat->admins.clear(); + chat->flags &= ~MTPDchat::Flag::f_admin; + for (auto i = v.cbegin(), e = v.cend(); i != e; ++i) { + qint32 uid = 0, inviter = 0; + switch (i->type()) { + case mtpc_chatParticipantCreator: { + const auto &p(i->c_chatParticipantCreator()); + uid = p.vuser_id.v; + chat->creator = uid; + } break; + case mtpc_chatParticipantAdmin: { + const auto &p(i->c_chatParticipantAdmin()); + uid = p.vuser_id.v; + inviter = p.vinviter_id.v; + } break; + case mtpc_chatParticipant: { + const auto &p(i->c_chatParticipant()); + uid = p.vuser_id.v; + inviter = p.vinviter_id.v; + } break; + } + if (!uid) continue; - case mtpc_chatParticipants: { - const auto &d(p.c_chatParticipants()); - chat = App::chat(d.vchat_id.v); - auto canEdit = chat->canEdit(); - if (!requestBotInfos || chat->version <= d.vversion.v) { // !requestBotInfos is true on getFullChat result - chat->version = d.vversion.v; - auto &v = d.vparticipants.v; - chat->count = v.size(); - int32 pversion = chat->participants.isEmpty() ? 1 : (chat->participants.begin().value() + 1); - chat->invitedByMe.clear(); - chat->admins.clear(); - chat->flags &= ~MTPDchat::Flag::f_admin; - for (auto i = v.cbegin(), e = v.cend(); i != e; ++i) { - int32 uid = 0, inviter = 0; - switch (i->type()) { - case mtpc_chatParticipantCreator: { - const auto &p(i->c_chatParticipantCreator()); - uid = p.vuser_id.v; - chat->creator = uid; - } break; - case mtpc_chatParticipantAdmin: { - const auto &p(i->c_chatParticipantAdmin()); - uid = p.vuser_id.v; - inviter = p.vinviter_id.v; - } break; - case mtpc_chatParticipant: { - const auto &p(i->c_chatParticipant()); - uid = p.vuser_id.v; - inviter = p.vinviter_id.v; - } break; + UserData *user = App::userLoaded(uid); + if (user) { + chat->participants[user] = pversion; + if (inviter == Auth().userId()) { + chat->invitedByMe.insert(user); } - if (!uid) continue; - - UserData *user = App::userLoaded(uid); - if (user) { - chat->participants[user] = pversion; - if (inviter == Auth().userId()) { - chat->invitedByMe.insert(user); - } - if (i->type() == mtpc_chatParticipantAdmin) { - chat->admins.insert(user); - if (user->isSelf()) { - chat->flags |= MTPDchat::Flag::f_admin; - } + if (i->type() == mtpc_chatParticipantAdmin) { + chat->admins.insert(user); + if (user->isSelf()) { + chat->flags |= MTPDchat::Flag::f_admin; } - } else { - chat->invalidateParticipants(); - break; } + } else { + chat->invalidateParticipants(); + break; } - if (!chat->participants.isEmpty()) { - History *h = App::historyLoaded(chat->id); - bool found = !h || !h->lastKeyboardFrom; - int32 botStatus = -1; - for (auto i = chat->participants.begin(), e = chat->participants.end(); i != e;) { - if (i.value() < pversion) { - i = chat->participants.erase(i); - } else { - if (i.key()->botInfo) { - botStatus = 2;// (botStatus > 0/* || !i.key()->botInfo->readsAllHistory*/) ? 2 : 1; - if (requestBotInfos && !i.key()->botInfo->inited) { - Auth().api().requestFullPeer(i.key()); - } - } - if (!found && i.key()->id == h->lastKeyboardFrom) { - found = true; + } + if (!chat->participants.isEmpty()) { + History *h = App::historyLoaded(chat->id); + bool found = !h || !h->lastKeyboardFrom; + qint32 botStatus = -1; + for (auto i = chat->participants.begin(), e = chat->participants.end(); i != e;) { + if (i.value() < pversion) { + i = chat->participants.erase(i); + } else { + if (i.key()->botInfo) { + botStatus = 2; // (botStatus > 0/* || !i.key()->botInfo->readsAllHistory*/) ? 2 : 1; + if (requestBotInfos && !i.key()->botInfo->inited) { + Auth().api().requestFullPeer(i.key()); } - ++i; } + if (!found && i.key()->id == h->lastKeyboardFrom) { + found = true; + } + ++i; } - chat->botStatus = botStatus; - if (!found) { - h->clearLastKeyboard(); - } + } + chat->botStatus = botStatus; + if (!found) { + h->clearLastKeyboard(); } } - if (canEdit != chat->canEdit()) { - Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::ChatCanEdit); - } - } break; } - Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::MembersChanged | Notify::PeerUpdate::Flag::AdminsChanged); + if (canEdit != chat->canEdit()) { + Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::ChatCanEdit); + } + } break; } + Notify::peerUpdatedDelayed(chat, + Notify::PeerUpdate::Flag::MembersChanged | Notify::PeerUpdate::Flag::AdminsChanged); +} - void feedParticipantAdd(const MTPDupdateChatParticipantAdd &d) { - ChatData *chat = App::chat(d.vchat_id.v); - if (chat->version + 1 < d.vversion.v) { - chat->version = d.vversion.v; - chat->invalidateParticipants(); - Auth().api().requestPeer(chat); - } else if (chat->version <= d.vversion.v && chat->count >= 0) { - chat->version = d.vversion.v; - UserData *user = App::userLoaded(d.vuser_id.v); - if (user) { - if (chat->participants.isEmpty() && chat->count) { - chat->count++; - chat->botStatus = 0; - } else if (chat->participants.find(user) == chat->participants.end()) { - chat->participants[user] = (chat->participants.isEmpty() ? 1 : chat->participants.begin().value()); - if (d.vinviter_id.v == Auth().userId()) { - chat->invitedByMe.insert(user); - } else { - chat->invitedByMe.remove(user); - } - chat->count++; - if (user->botInfo) { - chat->botStatus = 2;// (chat->botStatus > 0/* || !user->botInfo->readsAllHistory*/) ? 2 : 1; - if (!user->botInfo->inited) { - Auth().api().requestFullPeer(user); - } - } +void feedParticipantAdd(const MTPDupdateChatParticipantAdd &d) { + ChatData *chat = App::chat(d.vchat_id.v); + if (chat->version + 1 < d.vversion.v) { + chat->version = d.vversion.v; + chat->invalidateParticipants(); + Auth().api().requestPeer(chat); + } else if (chat->version <= d.vversion.v && chat->count >= 0) { + chat->version = d.vversion.v; + UserData *user = App::userLoaded(d.vuser_id.v); + if (user) { + if (chat->participants.isEmpty() && chat->count) { + chat->count++; + chat->botStatus = 0; + } else if (chat->participants.find(user) == chat->participants.end()) { + chat->participants[user] = (chat->participants.isEmpty() ? 1 : chat->participants.begin().value()); + if (d.vinviter_id.v == Auth().userId()) { + chat->invitedByMe.insert(user); + } else { + chat->invitedByMe.erase(user); } - } else { - chat->invalidateParticipants(); chat->count++; + if (user->botInfo) { + chat->botStatus = 2; // (chat->botStatus > 0/* || !user->botInfo->readsAllHistory*/) ? 2 : 1; + if (!user->botInfo->inited) { + Auth().api().requestFullPeer(user); + } + } } - Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::MembersChanged); + } else { + chat->invalidateParticipants(); + chat->count++; } + Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::MembersChanged); } +} - void feedParticipantDelete(const MTPDupdateChatParticipantDelete &d) { - ChatData *chat = App::chat(d.vchat_id.v); - if (chat->version + 1 < d.vversion.v) { - chat->version = d.vversion.v; - chat->invalidateParticipants(); - Auth().api().requestPeer(chat); - } else if (chat->version <= d.vversion.v && chat->count > 0) { - chat->version = d.vversion.v; - auto canEdit = chat->canEdit(); - UserData *user = App::userLoaded(d.vuser_id.v); - if (user) { - if (chat->participants.isEmpty()) { - if (chat->count > 0) { - chat->count--; +void feedParticipantDelete(const MTPDupdateChatParticipantDelete &d) { + ChatData *chat = App::chat(d.vchat_id.v); + if (chat->version + 1 < d.vversion.v) { + chat->version = d.vversion.v; + chat->invalidateParticipants(); + Auth().api().requestPeer(chat); + } else if (chat->version <= d.vversion.v && chat->count > 0) { + chat->version = d.vversion.v; + auto canEdit = chat->canEdit(); + UserData *user = App::userLoaded(d.vuser_id.v); + if (user) { + if (chat->participants.isEmpty()) { + if (chat->count > 0) { + chat->count--; + } + } else { + auto i = chat->participants.find(user); + if (i != chat->participants.end()) { + chat->participants.erase(i); + chat->count--; + chat->invitedByMe.erase(user); + chat->admins.erase(user); + if (user->isSelf()) { + chat->flags &= ~MTPDchat::Flag::f_admin; } - } else { - auto i = chat->participants.find(user); - if (i != chat->participants.end()) { - chat->participants.erase(i); - chat->count--; - chat->invitedByMe.remove(user); - chat->admins.remove(user); - if (user->isSelf()) { - chat->flags &= ~MTPDchat::Flag::f_admin; - } - History *h = App::historyLoaded(chat->id); - if (h && h->lastKeyboardFrom == user->id) { - h->clearLastKeyboard(); - } + History *h = App::historyLoaded(chat->id); + if (h && h->lastKeyboardFrom == user->id) { + h->clearLastKeyboard(); } - if (chat->botStatus > 0 && user->botInfo) { - int32 botStatus = -1; - for (auto j = chat->participants.cbegin(), e = chat->participants.cend(); j != e; ++j) { - if (j.key()->botInfo) { - if (true || botStatus > 0/* || !j.key()->botInfo->readsAllHistory*/) { - botStatus = 2; - break; - } - botStatus = 1; + } + if (chat->botStatus > 0 && user->botInfo) { + qint32 botStatus = -1; + for (auto j = chat->participants.cbegin(), e = chat->participants.cend(); j != e; ++j) { + if (j.key()->botInfo) { + if (true || botStatus > 0 /* || !j.key()->botInfo->readsAllHistory*/) { + botStatus = 2; + break; } + botStatus = 1; } - chat->botStatus = botStatus; } + chat->botStatus = botStatus; } - } else { - chat->invalidateParticipants(); - chat->count--; } - if (canEdit != chat->canEdit()) { - Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::ChatCanEdit); - } - Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::MembersChanged); + } else { + chat->invalidateParticipants(); + chat->count--; } + if (canEdit != chat->canEdit()) { + Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::ChatCanEdit); + } + Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::MembersChanged); } +} - void feedChatAdmins(const MTPDupdateChatAdmins &d) { - ChatData *chat = App::chat(d.vchat_id.v); - if (chat->version <= d.vversion.v) { - bool badVersion = (chat->version + 1 < d.vversion.v); - if (badVersion) { +void feedChatAdmins(const MTPDupdateChatAdmins &d) { + ChatData *chat = App::chat(d.vchat_id.v); + if (chat->version <= d.vversion.v) { + bool badVersion = (chat->version + 1 < d.vversion.v); + if (badVersion) { + chat->invalidateParticipants(); + Auth().api().requestPeer(chat); + } + chat->version = d.vversion.v; + if (mtpIsTrue(d.venabled)) { + if (!badVersion) { chat->invalidateParticipants(); - Auth().api().requestPeer(chat); - } - chat->version = d.vversion.v; - if (mtpIsTrue(d.venabled)) { - if (!badVersion) { - chat->invalidateParticipants(); - } - chat->flags |= MTPDchat::Flag::f_admins_enabled; - } else { - chat->flags &= ~MTPDchat::Flag::f_admins_enabled; } - Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::AdminsChanged); + chat->flags |= MTPDchat::Flag::f_admins_enabled; + } else { + chat->flags &= ~MTPDchat::Flag::f_admins_enabled; } + Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::AdminsChanged); } +} - void feedParticipantAdmin(const MTPDupdateChatParticipantAdmin &d) { - ChatData *chat = App::chat(d.vchat_id.v); - if (chat->version + 1 < d.vversion.v) { - chat->version = d.vversion.v; - chat->invalidateParticipants(); - Auth().api().requestPeer(chat); - } else if (chat->version <= d.vversion.v && chat->count > 0) { - chat->version = d.vversion.v; - auto canEdit = chat->canEdit(); - UserData *user = App::userLoaded(d.vuser_id.v); - if (user) { - if (mtpIsTrue(d.vis_admin)) { - if (user->isSelf()) { - chat->flags |= MTPDchat::Flag::f_admin; - } - if (chat->noParticipantInfo()) { - Auth().api().requestFullPeer(chat); - } else { - chat->admins.insert(user); - } +void feedParticipantAdmin(const MTPDupdateChatParticipantAdmin &d) { + ChatData *chat = App::chat(d.vchat_id.v); + if (chat->version + 1 < d.vversion.v) { + chat->version = d.vversion.v; + chat->invalidateParticipants(); + Auth().api().requestPeer(chat); + } else if (chat->version <= d.vversion.v && chat->count > 0) { + chat->version = d.vversion.v; + auto canEdit = chat->canEdit(); + UserData *user = App::userLoaded(d.vuser_id.v); + if (user) { + if (mtpIsTrue(d.vis_admin)) { + if (user->isSelf()) { + chat->flags |= MTPDchat::Flag::f_admin; + } + if (chat->noParticipantInfo()) { + Auth().api().requestFullPeer(chat); } else { - if (user->isSelf()) { - chat->flags &= ~MTPDchat::Flag::f_admin; - } - chat->admins.remove(user); + chat->admins.insert(user); } } else { - chat->invalidateParticipants(); - } - if (canEdit != chat->canEdit()) { - Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::ChatCanEdit); + if (user->isSelf()) { + chat->flags &= ~MTPDchat::Flag::f_admin; + } + chat->admins.erase(user); } - Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::AdminsChanged); + } else { + chat->invalidateParticipants(); } - } - - bool checkEntitiesAndViewsUpdate(const MTPDmessage &m) { - auto peerId = peerFromMTP(m.vto_id); - if (m.has_from_id() && peerId == Auth().userPeerId()) { - peerId = peerFromUser(m.vfrom_id); + if (canEdit != chat->canEdit()) { + Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::ChatCanEdit); } - if (auto existing = App::histItemById(peerToChannel(peerId), m.vid.v)) { - auto text = qs(m.vmessage); - auto entities = m.has_entities() ? TextUtilities::EntitiesFromMTP(m.ventities.v) : EntitiesInText(); - existing->setText({ text, entities }); - existing->updateMedia(m.has_media() ? (&m.vmedia) : nullptr); - existing->updateReplyMarkup(m.has_reply_markup() ? (&m.vreply_markup) : nullptr); - existing->setViewsCount(m.has_views() ? m.vviews.v : -1); - existing->addToOverview(AddToOverviewNew); + Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::AdminsChanged); + } +} - if (!existing->detached()) { - App::checkSavedGif(existing); - return true; - } +bool checkEntitiesAndViewsUpdate(const MTPDmessage &m) { + auto peerId = peerFromMTP(m.vto_id); + if (m.has_from_id() && peerId == Auth().userPeerId()) { + peerId = peerFromUser(m.vfrom_id); + } + if (auto existing = App::histItemById(peerToChannel(peerId), m.vid.v)) { + auto text = qs(m.vmessage); + auto entities = m.has_entities() ? TextUtilities::EntitiesFromMTP(m.ventities.v) : EntitiesInText(); + existing->setText({text, entities}); + existing->updateMedia(m.has_media() ? (&m.vmedia) : nullptr); + existing->updateReplyMarkup(m.has_reply_markup() ? (&m.vreply_markup) : nullptr); + existing->setViewsCount(m.has_views() ? m.vviews.v : -1); + existing->addToOverview(AddToOverviewNew); - return false; + if (!existing->detached()) { + App::checkSavedGif(existing); + return true; } + return false; } + return false; +} - template - void updateEditedMessage(const TMTPDclass &m) { - auto peerId = peerFromMTP(m.vto_id); - if (m.has_from_id() && peerId == Auth().userPeerId()) { - peerId = peerFromUser(m.vfrom_id); - } - if (auto existing = App::histItemById(peerToChannel(peerId), m.vid.v)) { - existing->applyEdition(m); - } +template void updateEditedMessage(const TMTPDclass &m) { + auto peerId = peerFromMTP(m.vto_id); + if (m.has_from_id() && peerId == Auth().userPeerId()) { + peerId = peerFromUser(m.vfrom_id); + } + if (auto existing = App::histItemById(peerToChannel(peerId), m.vid.v)) { + existing->applyEdition(m); } +} - void updateEditedMessage(const MTPMessage &m) { - if (m.type() == mtpc_message) { // apply message edit - App::updateEditedMessage(m.c_message()); - } else if (m.type() == mtpc_messageService) { - App::updateEditedMessage(m.c_messageService()); - } +void updateEditedMessage(const MTPMessage &m) { + if (m.type() == mtpc_message) { // apply message edit + App::updateEditedMessage(m.c_message()); + } else if (m.type() == mtpc_messageService) { + App::updateEditedMessage(m.c_messageService()); } +} - void addSavedGif(DocumentData *doc) { - SavedGifs &saved(cRefSavedGifs()); - int32 index = saved.indexOf(doc); - if (index) { - if (index > 0) saved.remove(index); - saved.push_front(doc); - if (saved.size() > Global::SavedGifsLimit()) saved.pop_back(); - Local::writeSavedGifs(); +void addSavedGif(DocumentData *doc) { + SavedGifs &saved(cRefSavedGifs()); + qint32 index = saved.indexOf(doc); + if (index) { + if (index > 0) saved.remove(index); + saved.push_front(doc); + if (saved.size() > Global::SavedGifsLimit()) saved.pop_back(); + Local::writeSavedGifs(); - Auth().data().savedGifsUpdated().notify(); - cSetLastSavedGifsUpdate(0); - Auth().api().updateStickers(); - } + Auth().data().savedGifsUpdated().notify(); + cSetLastSavedGifsUpdate(0); + Auth().api().updateStickers(); } +} - void checkSavedGif(HistoryItem *item) { - if (!item->Has() && (item->out() || item->history()->peer == App::self())) { - if (auto media = item->getMedia()) { - if (auto doc = media->getDocument()) { - if (doc->isGifv()) { - addSavedGif(doc); - } +void checkSavedGif(HistoryItem *item) { + if (!item->Has() && (item->out() || item->history()->peer == App::self())) { + if (auto media = item->getMedia()) { + if (auto doc = media->getDocument()) { + if (doc->isGifv()) { + addSavedGif(doc); } } } } +} - void feedMsgs(const QVector &msgs, NewMessageType type) { - QMap msgsIds; - for (int32 i = 0, l = msgs.size(); i < l; ++i) { - const auto &msg(msgs.at(i)); - switch (msg.type()) { - case mtpc_message: { - const auto &d(msg.c_message()); - bool needToAdd = true; - if (type == NewMessageUnread) { // new message, index my forwarded messages to links overview - if (checkEntitiesAndViewsUpdate(d)) { // already in blocks - LOG(("Skipping message, because it is already in blocks!")); - needToAdd = false; - } - } - if (needToAdd) { - msgsIds.insert((uint64(uint32(d.vid.v)) << 32) | uint64(i), i); +void feedMsgs(const QVector &msgs, NewMessageType type) { + QMap msgsIds; + for (qint32 i = 0, l = msgs.size(); i < l; ++i) { + const auto &msg(msgs.at(i)); + switch (msg.type()) { + case mtpc_message: { + const auto &d(msg.c_message()); + bool needToAdd = true; + if (type == NewMessageUnread) { // new message, index my forwarded messages to links overview + if (checkEntitiesAndViewsUpdate(d)) { // already in blocks + LOG(("Skipping message, because it is already in blocks!")); + needToAdd = false; } - } break; - case mtpc_messageEmpty: msgsIds.insert((uint64(uint32(msg.c_messageEmpty().vid.v)) << 32) | uint64(i), i); break; - case mtpc_messageService: msgsIds.insert((uint64(uint32(msg.c_messageService().vid.v)) << 32) | uint64(i), i); break; - } - } - for (QMap::const_iterator i = msgsIds.cbegin(), e = msgsIds.cend(); i != e; ++i) { - histories().addNewMessage(msgs.at(i.value()), type); - } - } - - void feedMsgs(const MTPVector &msgs, NewMessageType type) { - return feedMsgs(msgs.v, type); - } - - ImagePtr image(const MTPPhotoSize &size) { - switch (size.type()) { - case mtpc_photoSize: { - auto &d = size.c_photoSize(); - if (d.vlocation.type() == mtpc_fileLocation) { - auto &l = d.vlocation.c_fileLocation(); - return ImagePtr(StorageImageLocation(d.vw.v, d.vh.v, l.vdc_id.v, l.vvolume_id.v, l.vlocal_id.v, l.vsecret.v), d.vsize.v); } - } break; - case mtpc_photoCachedSize: { - auto &d = size.c_photoCachedSize(); - if (d.vlocation.type() == mtpc_fileLocation) { - auto &l = d.vlocation.c_fileLocation(); - auto bytes = qba(d.vbytes); - return ImagePtr(StorageImageLocation(d.vw.v, d.vh.v, l.vdc_id.v, l.vvolume_id.v, l.vlocal_id.v, l.vsecret.v), bytes); - } else if (d.vlocation.type() == mtpc_fileLocationUnavailable) { - auto bytes = qba(d.vbytes); - return ImagePtr(StorageImageLocation(d.vw.v, d.vh.v, 0, 0, 0, 0), bytes); + if (needToAdd) { + msgsIds.insert((quint64(quint32(d.vid.v)) << 32) | quint64(i), i); } } break; + case mtpc_messageEmpty: + msgsIds.insert((quint64(quint32(msg.c_messageEmpty().vid.v)) << 32) | quint64(i), i); + break; + case mtpc_messageService: + msgsIds.insert((quint64(quint32(msg.c_messageService().vid.v)) << 32) | quint64(i), i); + break; } - return ImagePtr(); } - - StorageImageLocation imageLocation(int32 w, int32 h, const MTPFileLocation &loc) { - if (loc.type() == mtpc_fileLocation) { - const auto &l(loc.c_fileLocation()); - return StorageImageLocation(w, h, l.vdc_id.v, l.vvolume_id.v, l.vlocal_id.v, l.vsecret.v); - } - return StorageImageLocation(w, h, 0, 0, 0, 0); + for (QMap::const_iterator i = msgsIds.cbegin(), e = msgsIds.cend(); i != e; ++i) { + histories().addNewMessage(msgs.at(i.value()), type); } +} - StorageImageLocation imageLocation(const MTPPhotoSize &size) { - switch (size.type()) { - case mtpc_photoSize: { - const auto &d(size.c_photoSize()); - return imageLocation(d.vw.v, d.vh.v, d.vlocation); - } break; - case mtpc_photoCachedSize: { - const auto &d(size.c_photoCachedSize()); - return imageLocation(d.vw.v, d.vh.v, d.vlocation); - } break; - } - return StorageImageLocation(); +void feedMsgs(const MTPVector &msgs, NewMessageType type) { + return feedMsgs(msgs.v, type); +} + +ImagePtr image(const MTPPhotoSize &size) { + switch (size.type()) { + case mtpc_photoSize: { + auto &d = size.c_photoSize(); + if (d.vlocation.type() == mtpc_fileLocation) { + auto &l = d.vlocation.c_fileLocation(); + return ImagePtr( + StorageImageLocation(d.vw.v, d.vh.v, l.vdc_id.v, l.vvolume_id.v, l.vlocal_id.v, l.vsecret.v), + d.vsize.v); + } + } break; + case mtpc_photoCachedSize: { + auto &d = size.c_photoCachedSize(); + if (d.vlocation.type() == mtpc_fileLocation) { + auto &l = d.vlocation.c_fileLocation(); + auto bytes = qba(d.vbytes); + return ImagePtr( + StorageImageLocation(d.vw.v, d.vh.v, l.vdc_id.v, l.vvolume_id.v, l.vlocal_id.v, l.vsecret.v), bytes); + } else if (d.vlocation.type() == mtpc_fileLocationUnavailable) { + auto bytes = qba(d.vbytes); + return ImagePtr(StorageImageLocation(d.vw.v, d.vh.v, 0, 0, 0, 0), bytes); + } + } break; + } + return ImagePtr(); +} + +StorageImageLocation imageLocation(qint32 w, qint32 h, const MTPFileLocation &loc) { + if (loc.type() == mtpc_fileLocation) { + const auto &l(loc.c_fileLocation()); + return StorageImageLocation(w, h, l.vdc_id.v, l.vvolume_id.v, l.vlocal_id.v, l.vsecret.v); } + return StorageImageLocation(w, h, 0, 0, 0, 0); +} - void feedInboxRead(const PeerId &peer, MsgId upTo) { - if (auto history = App::historyLoaded(peer)) { - history->inboxRead(upTo); - } +StorageImageLocation imageLocation(const MTPPhotoSize &size) { + switch (size.type()) { + case mtpc_photoSize: { + const auto &d(size.c_photoSize()); + return imageLocation(d.vw.v, d.vh.v, d.vlocation); + } break; + case mtpc_photoCachedSize: { + const auto &d(size.c_photoCachedSize()); + return imageLocation(d.vw.v, d.vh.v, d.vlocation); + } break; + } + return StorageImageLocation(); +} + +void feedInboxRead(const PeerId &peer, MsgId upTo) { + if (auto history = App::historyLoaded(peer)) { + history->inboxRead(upTo); } +} - void feedOutboxRead(const PeerId &peer, MsgId upTo, TimeId when) { - if (auto history = App::historyLoaded(peer)) { - history->outboxRead(upTo); - if (history->lastMsg && history->lastMsg->out() && history->lastMsg->id <= upTo) { - if (App::main()) App::main()->dlgUpdated(history->peer, history->lastMsg->id); - } - history->updateChatListEntry(); +void feedOutboxRead(const PeerId &peer, MsgId upTo, TimeId when) { + if (auto history = App::historyLoaded(peer)) { + history->outboxRead(upTo); + if (history->lastMsg && history->lastMsg->out() && history->lastMsg->id <= upTo) { + if (App::main()) App::main()->dlgUpdated(history->peer, history->lastMsg->id); + } + history->updateChatListEntry(); - if (history->peer->isUser()) { - history->peer->asUser()->madeAction(when); - } + if (history->peer->isUser()) { + history->peer->asUser()->madeAction(when); } } +} - inline MsgsData *fetchMsgsData(ChannelId channelId, bool insert = true) { - if (channelId == NoChannel) return &msgsData; - ChannelMsgsData::iterator i = channelMsgsData.find(channelId); - if (i == channelMsgsData.cend()) { - if (insert) { - i = channelMsgsData.insert(channelId, MsgsData()); - } else { - return 0; - } +inline MsgsData *fetchMsgsData(ChannelId channelId, bool insert = true) { + if (channelId == NoChannel) return &msgsData; + ChannelMsgsData::iterator i = channelMsgsData.find(channelId); + if (i == channelMsgsData.cend()) { + if (insert) { + i = channelMsgsData.insert(channelId, MsgsData()); + } else { + return 0; } - return &(*i); } + return &(*i); +} - void feedWereDeleted(ChannelId channelId, const QVector &msgsIds) { - MsgsData *data = fetchMsgsData(channelId, false); - if (!data) return; +void feedWereDeleted(ChannelId channelId, const QVector &msgsIds) { + MsgsData *data = fetchMsgsData(channelId, false); + if (!data) return; - ChannelHistory *channelHistory = (channelId == NoChannel) ? 0 : App::historyLoaded(peerFromChannel(channelId))->asChannelHistory(); + ChannelHistory *channelHistory = + (channelId == NoChannel) ? 0 : App::historyLoaded(peerFromChannel(channelId))->asChannelHistory(); - QMap historiesToCheck; - for (QVector::const_iterator i = msgsIds.cbegin(), e = msgsIds.cend(); i != e; ++i) { - MsgsData::const_iterator j = data->constFind(i->v); - if (j != data->cend()) { - History *h = (*j)->history(); - (*j)->destroy(); - if (!h->lastMsg) historiesToCheck.insert(h, true); - } else { - if (channelHistory) { - if (channelHistory->unreadCount() > 0 && i->v >= channelHistory->inboxReadBefore) { - channelHistory->setUnreadCount(channelHistory->unreadCount() - 1); - } + QMap historiesToCheck; + for (QVector::const_iterator i = msgsIds.cbegin(), e = msgsIds.cend(); i != e; ++i) { + MsgsData::const_iterator j = data->constFind(i->v); + if (j != data->cend()) { + History *h = (*j)->history(); + (*j)->destroy(); + if (!h->lastMsg) historiesToCheck.insert(h, true); + } else { + if (channelHistory) { + if (channelHistory->unreadCount() > 0 && i->v >= channelHistory->inboxReadBefore) { + channelHistory->setUnreadCount(channelHistory->unreadCount() - 1); } } } - if (main()) { - for (QMap::const_iterator i = historiesToCheck.cbegin(), e = historiesToCheck.cend(); i != e; ++i) { - main()->checkPeerHistory(i.key()->peer); - } + } + if (main()) { + for (QMap::const_iterator i = historiesToCheck.cbegin(), e = historiesToCheck.cend(); i != e; + ++i) { + main()->checkPeerHistory(i.key()->peer); } } +} - void feedUserLink(MTPint userId, const MTPContactLink &myLink, const MTPContactLink &foreignLink) { - UserData *user = userLoaded(userId.v); - if (user) { - auto wasContact = user->isContact(); - bool wasShowPhone = !user->contact; - switch (myLink.type()) { - case mtpc_contactLinkContact: - user->contact = 1; - if (user->contact == 1 && cReportSpamStatuses().value(user->id, dbiprsHidden) != dbiprsHidden) { - cRefReportSpamStatuses().insert(user->id, dbiprsHidden); - Local::writeReportSpamStatuses(); - } +void feedUserLink(MTPint userId, const MTPContactLink &myLink, const MTPContactLink &foreignLink) { + UserData *user = userLoaded(userId.v); + if (user) { + auto wasContact = user->isContact(); + bool wasShowPhone = !user->contact; + switch (myLink.type()) { + case mtpc_contactLinkContact: + user->contact = 1; + if (user->contact == 1 && cReportSpamStatuses().value(user->id, dbiprsHidden) != dbiprsHidden) { + cRefReportSpamStatuses().insert(user->id, dbiprsHidden); + Local::writeReportSpamStatuses(); + } break; - case mtpc_contactLinkHasPhone: + case mtpc_contactLinkHasPhone: user->contact = 0; break; + case mtpc_contactLinkNone: + case mtpc_contactLinkUnknown: user->contact = -1; break; + } + if (user->contact < 1) { + if (user->contact < 0 && !user->phone().isEmpty() && user->id != Auth().userPeerId()) { user->contact = 0; - break; - case mtpc_contactLinkNone: - case mtpc_contactLinkUnknown: - user->contact = -1; - break; - } - if (user->contact < 1) { - if (user->contact < 0 && !user->phone().isEmpty() && user->id != Auth().userPeerId()) { - user->contact = 0; - } } + } - if (wasContact != user->isContact()) { - Notify::peerUpdatedDelayed(user, Notify::PeerUpdate::Flag::UserIsContact); - } - if ((user->contact > 0 && !wasContact) || (wasContact && user->contact < 1)) { - Notify::userIsContactChanged(user); - } + if (wasContact != user->isContact()) { + Notify::peerUpdatedDelayed(user, Notify::PeerUpdate::Flag::UserIsContact); + } + if ((user->contact > 0 && !wasContact) || (wasContact && user->contact < 1)) { + Notify::userIsContactChanged(user); + } - bool showPhone = !isServiceUser(user->id) && !user->isSelf() && !user->contact; - bool showPhoneChanged = !isServiceUser(user->id) && !user->isSelf() && ((showPhone && !wasShowPhone) || (!showPhone && wasShowPhone)); - if (showPhoneChanged) { - user->setName(TextUtilities::SingleLine(user->firstName), TextUtilities::SingleLine(user->lastName), showPhone ? App::formatPhone(user->phone()) : QString(), TextUtilities::SingleLine(user->username)); - } + bool showPhone = !isServiceUser(user->id) && !user->isSelf() && !user->contact; + bool showPhoneChanged = !isServiceUser(user->id) && !user->isSelf() && + ((showPhone && !wasShowPhone) || (!showPhone && wasShowPhone)); + if (showPhoneChanged) { + user->setName(TextUtilities::SingleLine(user->firstName), TextUtilities::SingleLine(user->lastName), + showPhone ? App::formatPhone(user->phone()) : QString(), + TextUtilities::SingleLine(user->username)); } } +} - PhotoData *feedPhoto(const MTPPhoto &photo, PhotoData *convert) { - switch (photo.type()) { - case mtpc_photo: { - return feedPhoto(photo.c_photo(), convert); - } break; - case mtpc_photoEmpty: { - return App::photoSet(photo.c_photoEmpty().vid.v, convert, 0, 0, ImagePtr(), ImagePtr(), ImagePtr()); - } break; - } - return App::photo(0); +PhotoData *feedPhoto(const MTPPhoto &photo, PhotoData *convert) { + switch (photo.type()) { + case mtpc_photo: { + return feedPhoto(photo.c_photo(), convert); + } break; + case mtpc_photoEmpty: { + return App::photoSet(photo.c_photoEmpty().vid.v, convert, 0, 0, ImagePtr(), ImagePtr(), ImagePtr()); + } break; } + return App::photo(0); +} - PhotoData *feedPhoto(const MTPPhoto &photo, const PreparedPhotoThumbs &thumbs) { - const QPixmap *thumb = 0, *medium = 0, *full = 0; - int32 thumbLevel = -1, mediumLevel = -1, fullLevel = -1; - for (PreparedPhotoThumbs::const_iterator i = thumbs.cbegin(), e = thumbs.cend(); i != e; ++i) { - int32 newThumbLevel = -1, newMediumLevel = -1, newFullLevel = -1; - switch (i.key()) { - case 's': newThumbLevel = 0; newMediumLevel = 5; newFullLevel = 4; break; // box 100x100 - case 'm': newThumbLevel = 2; newMediumLevel = 0; newFullLevel = 3; break; // box 320x320 - case 'x': newThumbLevel = 5; newMediumLevel = 3; newFullLevel = 1; break; // box 800x800 - case 'y': newThumbLevel = 6; newMediumLevel = 6; newFullLevel = 0; break; // box 1280x1280 - case 'w': newThumbLevel = 8; newMediumLevel = 8; newFullLevel = 2; break; // box 2560x2560 // if loading this fix HistoryPhoto::updateFrom - case 'a': newThumbLevel = 1; newMediumLevel = 4; newFullLevel = 8; break; // crop 160x160 - case 'b': newThumbLevel = 3; newMediumLevel = 1; newFullLevel = 7; break; // crop 320x320 - case 'c': newThumbLevel = 4; newMediumLevel = 2; newFullLevel = 6; break; // crop 640x640 - case 'd': newThumbLevel = 7; newMediumLevel = 7; newFullLevel = 5; break; // crop 1280x1280 - } - if (newThumbLevel < 0 || newMediumLevel < 0 || newFullLevel < 0) { - continue; - } - if (thumbLevel < 0 || newThumbLevel < thumbLevel) { - thumbLevel = newThumbLevel; - thumb = &i.value(); - } - if (mediumLevel < 0 || newMediumLevel < mediumLevel) { - mediumLevel = newMediumLevel; - medium = &i.value(); - } - if (fullLevel < 0 || newFullLevel < fullLevel) { - fullLevel = newFullLevel; - full = &i.value(); - } - } - if (!thumb || !medium || !full) { - return App::photo(0); - } - switch (photo.type()) { - case mtpc_photo: { - const auto &ph(photo.c_photo()); - return App::photoSet(ph.vid.v, 0, ph.vaccess_hash.v, ph.vdate.v, ImagePtr(*thumb, "JPG"), ImagePtr(*medium, "JPG"), ImagePtr(*full, "JPG")); - } break; - case mtpc_photoEmpty: return App::photo(photo.c_photoEmpty().vid.v); - } +PhotoData *feedPhoto(const MTPPhoto &photo, const PreparedPhotoThumbs &thumbs) { + const QPixmap *thumb = 0, *medium = 0, *full = 0; + qint32 thumbLevel = -1, mediumLevel = -1, fullLevel = -1; + for (PreparedPhotoThumbs::const_iterator i = thumbs.cbegin(), e = thumbs.cend(); i != e; ++i) { + qint32 newThumbLevel = -1, newMediumLevel = -1, newFullLevel = -1; + switch (i.key()) { + case 's': + newThumbLevel = 0; + newMediumLevel = 5; + newFullLevel = 4; + break; // box 100x100 + case 'm': + newThumbLevel = 2; + newMediumLevel = 0; + newFullLevel = 3; + break; // box 320x320 + case 'x': + newThumbLevel = 5; + newMediumLevel = 3; + newFullLevel = 1; + break; // box 800x800 + case 'y': + newThumbLevel = 6; + newMediumLevel = 6; + newFullLevel = 0; + break; // box 1280x1280 + case 'w': + newThumbLevel = 8; + newMediumLevel = 8; + newFullLevel = 2; + break; // box 2560x2560 // if loading this fix HistoryPhoto::updateFrom + case 'a': + newThumbLevel = 1; + newMediumLevel = 4; + newFullLevel = 8; + break; // crop 160x160 + case 'b': + newThumbLevel = 3; + newMediumLevel = 1; + newFullLevel = 7; + break; // crop 320x320 + case 'c': + newThumbLevel = 4; + newMediumLevel = 2; + newFullLevel = 6; + break; // crop 640x640 + case 'd': + newThumbLevel = 7; + newMediumLevel = 7; + newFullLevel = 5; + break; // crop 1280x1280 + } + if (newThumbLevel < 0 || newMediumLevel < 0 || newFullLevel < 0) { + continue; + } + if (thumbLevel < 0 || newThumbLevel < thumbLevel) { + thumbLevel = newThumbLevel; + thumb = &i.value(); + } + if (mediumLevel < 0 || newMediumLevel < mediumLevel) { + mediumLevel = newMediumLevel; + medium = &i.value(); + } + if (fullLevel < 0 || newFullLevel < fullLevel) { + fullLevel = newFullLevel; + full = &i.value(); + } + } + if (!thumb || !medium || !full) { return App::photo(0); } - - PhotoData *feedPhoto(const MTPDphoto &photo, PhotoData *convert) { - auto &sizes = photo.vsizes.v; - const MTPPhotoSize *thumb = 0, *medium = 0, *full = 0; - int32 thumbLevel = -1, mediumLevel = -1, fullLevel = -1; - for (QVector::const_iterator i = sizes.cbegin(), e = sizes.cend(); i != e; ++i) { - char size = 0; - switch (i->type()) { - case mtpc_photoSize: { - auto &s = i->c_photoSize().vtype.v; - if (s.size()) size = s[0]; - } break; - - case mtpc_photoCachedSize: { - auto &s = i->c_photoCachedSize().vtype.v; - if (s.size()) size = s[0]; - } break; - } - if (!size) continue; - - int32 newThumbLevel = -1, newMediumLevel = -1, newFullLevel = -1; - switch (size) { - case 's': newThumbLevel = 0; newMediumLevel = 5; newFullLevel = 4; break; // box 100x100 - case 'm': newThumbLevel = 2; newMediumLevel = 0; newFullLevel = 3; break; // box 320x320 - case 'x': newThumbLevel = 5; newMediumLevel = 3; newFullLevel = 1; break; // box 800x800 - case 'y': newThumbLevel = 6; newMediumLevel = 6; newFullLevel = 0; break; // box 1280x1280 - case 'w': newThumbLevel = 8; newMediumLevel = 8; newFullLevel = 2; break; // box 2560x2560 - case 'a': newThumbLevel = 1; newMediumLevel = 4; newFullLevel = 8; break; // crop 160x160 - case 'b': newThumbLevel = 3; newMediumLevel = 1; newFullLevel = 7; break; // crop 320x320 - case 'c': newThumbLevel = 4; newMediumLevel = 2; newFullLevel = 6; break; // crop 640x640 - case 'd': newThumbLevel = 7; newMediumLevel = 7; newFullLevel = 5; break; // crop 1280x1280 - } - if (newThumbLevel < 0 || newMediumLevel < 0 || newFullLevel < 0) { - continue; - } - if (thumbLevel < 0 || newThumbLevel < thumbLevel) { - thumbLevel = newThumbLevel; - thumb = &(*i); - } - if (mediumLevel < 0 || newMediumLevel < mediumLevel) { - mediumLevel = newMediumLevel; - medium = &(*i); - } - if (fullLevel < 0 || newFullLevel < fullLevel) { - fullLevel = newFullLevel; - full = &(*i); - } - } - if (thumb && medium && full) { - return App::photoSet(photo.vid.v, convert, photo.vaccess_hash.v, photo.vdate.v, App::image(*thumb), App::image(*medium), App::image(*full)); - } - return App::photoSet(photo.vid.v, convert, 0, 0, ImagePtr(), ImagePtr(), ImagePtr()); + switch (photo.type()) { + case mtpc_photo: { + const auto &ph(photo.c_photo()); + return App::photoSet(ph.vid.v, 0, ph.vaccess_hash.v, ph.vdate.v, ImagePtr(*thumb, "JPG"), + ImagePtr(*medium, "JPG"), ImagePtr(*full, "JPG")); + } break; + case mtpc_photoEmpty: return App::photo(photo.c_photoEmpty().vid.v); } + return App::photo(0); +} - DocumentData *feedDocument(const MTPdocument &document, const QPixmap &thumb) { - switch (document.type()) { - case mtpc_document: { - auto &d = document.c_document(); - return App::documentSet(d.vid.v, 0, d.vaccess_hash.v, d.vversion.v, d.vdate.v, d.vattributes.v, qs(d.vmime_type), ImagePtr(thumb, "JPG"), d.vdc_id.v, d.vsize.v, StorageImageLocation()); +PhotoData *feedPhoto(const MTPDphoto &photo, PhotoData *convert) { + auto &sizes = photo.vsizes.v; + const MTPPhotoSize *thumb = 0, *medium = 0, *full = 0; + qint32 thumbLevel = -1, mediumLevel = -1, fullLevel = -1; + for (QVector::const_iterator i = sizes.cbegin(), e = sizes.cend(); i != e; ++i) { + char size = 0; + switch (i->type()) { + case mtpc_photoSize: { + auto &s = i->c_photoSize().vtype.v; + if (s.size()) size = s[0]; } break; - case mtpc_documentEmpty: return App::document(document.c_documentEmpty().vid.v); - } - return App::document(0); - } - DocumentData *feedDocument(const MTPdocument &document, DocumentData *convert) { - switch (document.type()) { - case mtpc_document: { - return feedDocument(document.c_document(), convert); - } break; - case mtpc_documentEmpty: { - return App::documentSet(document.c_documentEmpty().vid.v, convert, 0, 0, 0, QVector(), QString(), ImagePtr(), 0, 0, StorageImageLocation()); + case mtpc_photoCachedSize: { + auto &s = i->c_photoCachedSize().vtype.v; + if (s.size()) size = s[0]; } break; } - return App::document(0); - } + if (!size) continue; + + qint32 newThumbLevel = -1, newMediumLevel = -1, newFullLevel = -1; + switch (size) { + case 's': + newThumbLevel = 0; + newMediumLevel = 5; + newFullLevel = 4; + break; // box 100x100 + case 'm': + newThumbLevel = 2; + newMediumLevel = 0; + newFullLevel = 3; + break; // box 320x320 + case 'x': + newThumbLevel = 5; + newMediumLevel = 3; + newFullLevel = 1; + break; // box 800x800 + case 'y': + newThumbLevel = 6; + newMediumLevel = 6; + newFullLevel = 0; + break; // box 1280x1280 + case 'w': + newThumbLevel = 8; + newMediumLevel = 8; + newFullLevel = 2; + break; // box 2560x2560 + case 'a': + newThumbLevel = 1; + newMediumLevel = 4; + newFullLevel = 8; + break; // crop 160x160 + case 'b': + newThumbLevel = 3; + newMediumLevel = 1; + newFullLevel = 7; + break; // crop 320x320 + case 'c': + newThumbLevel = 4; + newMediumLevel = 2; + newFullLevel = 6; + break; // crop 640x640 + case 'd': + newThumbLevel = 7; + newMediumLevel = 7; + newFullLevel = 5; + break; // crop 1280x1280 + } + if (newThumbLevel < 0 || newMediumLevel < 0 || newFullLevel < 0) { + continue; + } + if (thumbLevel < 0 || newThumbLevel < thumbLevel) { + thumbLevel = newThumbLevel; + thumb = &(*i); + } + if (mediumLevel < 0 || newMediumLevel < mediumLevel) { + mediumLevel = newMediumLevel; + medium = &(*i); + } + if (fullLevel < 0 || newFullLevel < fullLevel) { + fullLevel = newFullLevel; + full = &(*i); + } + } + if (thumb && medium && full) { + return App::photoSet(photo.vid.v, convert, photo.vaccess_hash.v, photo.vdate.v, App::image(*thumb), + App::image(*medium), App::image(*full)); + } + return App::photoSet(photo.vid.v, convert, 0, 0, ImagePtr(), ImagePtr(), ImagePtr()); +} - DocumentData *feedDocument(const MTPDdocument &document, DocumentData *convert) { - return App::documentSet(document.vid.v, convert, document.vaccess_hash.v, document.vversion.v, document.vdate.v, document.vattributes.v, qs(document.vmime_type), App::image(document.vthumb), document.vdc_id.v, document.vsize.v, App::imageLocation(document.vthumb)); - } +DocumentData *feedDocument(const MTPdocument &document, const QPixmap &thumb) { + switch (document.type()) { + case mtpc_document: { + auto &d = document.c_document(); + return App::documentSet(d.vid.v, 0, d.vaccess_hash.v, d.vversion.v, d.vdate.v, d.vattributes.v, + qs(d.vmime_type), ImagePtr(thumb, "JPG"), d.vdc_id.v, d.vsize.v, + StorageImageLocation()); + } break; + case mtpc_documentEmpty: return App::document(document.c_documentEmpty().vid.v); + } + return App::document(0); +} - WebPageData *feedWebPage(const MTPDwebPage &webpage, WebPageData *convert) { - auto description = TextWithEntities { webpage.has_description() ? TextUtilities::Clean(qs(webpage.vdescription)) : QString() }; - auto siteName = webpage.has_site_name() ? qs(webpage.vsite_name) : QString(); - auto parseFlags = TextParseLinks | TextParseMultiline | TextParseRichText; - if (siteName == qstr("Twitter") || siteName == qstr("Instagram")) { - parseFlags |= TextParseHashtags | TextParseMentions; - } - TextUtilities::ParseEntities(description, parseFlags); - return App::webPageSet(webpage.vid.v, convert, webpage.has_type() ? qs(webpage.vtype) : qsl("article"), qs(webpage.vurl), qs(webpage.vdisplay_url), siteName, webpage.has_title() ? qs(webpage.vtitle) : QString(), description, webpage.has_photo() ? App::feedPhoto(webpage.vphoto) : nullptr, webpage.has_document() ? App::feedDocument(webpage.vdocument) : nullptr, webpage.has_duration() ? webpage.vduration.v : 0, webpage.has_author() ? qs(webpage.vauthor) : QString(), 0); - } +DocumentData *feedDocument(const MTPdocument &document, DocumentData *convert) { + switch (document.type()) { + case mtpc_document: { + return feedDocument(document.c_document(), convert); + } break; + case mtpc_documentEmpty: { + return App::documentSet(document.c_documentEmpty().vid.v, convert, 0, 0, 0, QVector(), + QString(), ImagePtr(), 0, 0, StorageImageLocation()); + } break; + } + return App::document(0); +} - WebPageData *feedWebPage(const MTPDwebPagePending &webpage, WebPageData *convert) { - return App::webPageSet(webpage.vid.v, convert, QString(), QString(), QString(), QString(), QString(), TextWithEntities(), nullptr, nullptr, 0, QString(), webpage.vdate.v); - } +DocumentData *feedDocument(const MTPDdocument &document, DocumentData *convert) { + return App::documentSet(document.vid.v, convert, document.vaccess_hash.v, document.vversion.v, document.vdate.v, + document.vattributes.v, qs(document.vmime_type), App::image(document.vthumb), + document.vdc_id.v, document.vsize.v, App::imageLocation(document.vthumb)); +} - WebPageData *feedWebPage(const MTPWebPage &webpage) { - switch (webpage.type()) { - case mtpc_webPage: return App::feedWebPage(webpage.c_webPage()); - case mtpc_webPageEmpty: { - WebPageData *page = App::webPage(webpage.c_webPageEmpty().vid.v); - if (page->pendingTill > 0) page->pendingTill = -1; // failed - return page; - } break; - case mtpc_webPagePending: return App::feedWebPage(webpage.c_webPagePending()); - case mtpc_webPageNotModified: LOG(("API Error: webPageNotModified is unexpected in feedWebPage().")); break; - } - return nullptr; - } +WebPageData *feedWebPage(const MTPDwebPage &webpage, WebPageData *convert) { + auto description = + TextWithEntities{webpage.has_description() ? TextUtilities::Clean(qs(webpage.vdescription)) : QString()}; + auto siteName = webpage.has_site_name() ? qs(webpage.vsite_name) : QString(); + auto parseFlags = TextParseLinks | TextParseMultiline | TextParseRichText; + if (siteName == qstr("Twitter") || siteName == qstr("Instagram")) { + parseFlags |= TextParseHashtags | TextParseMentions; + } + TextUtilities::ParseEntities(description, parseFlags); + return App::webPageSet( + webpage.vid.v, convert, webpage.has_type() ? qs(webpage.vtype) : qsl("article"), qs(webpage.vurl), + qs(webpage.vdisplay_url), siteName, webpage.has_title() ? qs(webpage.vtitle) : QString(), description, + webpage.has_photo() ? App::feedPhoto(webpage.vphoto) : nullptr, + webpage.has_document() ? App::feedDocument(webpage.vdocument) : nullptr, + webpage.has_duration() ? webpage.vduration.v : 0, webpage.has_author() ? qs(webpage.vauthor) : QString(), 0); +} - WebPageData *feedWebPage(WebPageId webPageId, const QString &siteName, const TextWithEntities &content) { - return App::webPageSet(webPageId, nullptr, qsl("article"), QString(), QString(), siteName, QString(), content, nullptr, nullptr, 0, QString(), 0); - } +WebPageData *feedWebPage(const MTPDwebPagePending &webpage, WebPageData *convert) { + return App::webPageSet(webpage.vid.v, convert, QString(), QString(), QString(), QString(), QString(), + TextWithEntities(), nullptr, nullptr, 0, QString(), webpage.vdate.v); +} - GameData *feedGame(const MTPDgame &game, GameData *convert) { - return App::gameSet(game.vid.v, convert, game.vaccess_hash.v, qs(game.vshort_name), qs(game.vtitle), qs(game.vdescription), App::feedPhoto(game.vphoto), game.has_document() ? App::feedDocument(game.vdocument) : nullptr); - } +WebPageData *feedWebPage(const MTPWebPage &webpage) { + switch (webpage.type()) { + case mtpc_webPage: return App::feedWebPage(webpage.c_webPage()); + case mtpc_webPageEmpty: { + WebPageData *page = App::webPage(webpage.c_webPageEmpty().vid.v); + if (page->pendingTill > 0) page->pendingTill = -1; // failed + return page; + } break; + case mtpc_webPagePending: return App::feedWebPage(webpage.c_webPagePending()); + case mtpc_webPageNotModified: LOG(("API Error: webPageNotModified is unexpected in feedWebPage().")); break; + } + return nullptr; +} - PeerData *peer(const PeerId &id, PeerData::LoadedStatus restriction) { - if (!id) return nullptr; +WebPageData *feedWebPage(WebPageId webPageId, const QString &siteName, const TextWithEntities &content) { + return App::webPageSet(webPageId, nullptr, qsl("article"), QString(), QString(), siteName, QString(), content, + nullptr, nullptr, 0, QString(), 0); +} - auto i = peersData.constFind(id); - if (i == peersData.cend()) { - PeerData *newData = nullptr; - if (peerIsUser(id)) { - newData = new UserData(id); - } else if (peerIsChat(id)) { - newData = new ChatData(id); - } else if (peerIsChannel(id)) { - newData = new ChannelData(id); - } - Assert(newData != nullptr); +GameData *feedGame(const MTPDgame &game, GameData *convert) { + return App::gameSet(game.vid.v, convert, game.vaccess_hash.v, qs(game.vshort_name), qs(game.vtitle), + qs(game.vdescription), App::feedPhoto(game.vphoto), + game.has_document() ? App::feedDocument(game.vdocument) : nullptr); +} - newData->input = MTPinputPeer(MTP_inputPeerEmpty()); - i = peersData.insert(id, newData); +PeerData *peer(const PeerId &id, PeerData::LoadedStatus restriction) { + if (!id) return nullptr; + + auto i = peersData.constFind(id); + if (i == peersData.cend()) { + PeerData *newData = nullptr; + if (peerIsUser(id)) { + newData = new UserData(id); + } else if (peerIsChat(id)) { + newData = new ChatData(id); + } else if (peerIsChannel(id)) { + newData = new ChannelData(id); } - switch (restriction) { - case PeerData::MinimalLoaded: { - if (i.value()->loadedStatus == PeerData::NotLoaded) { - return nullptr; - } - } break; - case PeerData::FullLoaded: { - if (i.value()->loadedStatus != PeerData::FullLoaded) { - return nullptr; - } - } break; + Assert(newData != nullptr); + + newData->input = MTPinputPeer(MTP_inputPeerEmpty()); + i = peersData.insert(id, newData); + } + switch (restriction) { + case PeerData::MinimalLoaded: { + if (i.value()->loadedStatus == PeerData::NotLoaded) { + return nullptr; } - return i.value(); + } break; + case PeerData::FullLoaded: { + if (i.value()->loadedStatus != PeerData::FullLoaded) { + return nullptr; + } + } break; + case PeerData::NotLoaded: break; } + return i.value(); +} - void enumerateUsers(base::lambda action) { - for_const (auto peer, peersData) { - if (auto user = peer->asUser()) { - action(user); - } +void enumerateUsers(Fn action) { + for_const (auto peer, peersData) { + if (auto user = peer->asUser()) { + action(user); } } +} - UserData *self() { - return ::self; - } +UserData *self() { + return ::self; +} - PeerData *peerByName(const QString &username) { - QString uname(username.trimmed()); - for_const (PeerData *peer, peersData) { - if (!peer->userName().compare(uname, Qt::CaseInsensitive)) { - return peer; - } +PeerData *peerByName(const QString &username) { + QString uname(username.trimmed()); + for_const (PeerData *peer, peersData) { + if (!peer->userName().compare(uname, Qt::CaseInsensitive)) { + return peer; } - return nullptr; } + return nullptr; +} - void updateImage(ImagePtr &old, ImagePtr now) { - if (now->isNull()) return; - if (old->isNull()) { - old = now; - } else if (DelayedStorageImage *img = old->toDelayedStorageImage()) { - StorageImageLocation loc = now->location(); - if (!loc.isNull()) { - img->setStorageLocation(loc); - } +void updateImage(ImagePtr &old, ImagePtr now) { + if (now->isNull()) return; + if (old->isNull()) { + old = now; + } else if (DelayedStorageImage *img = old->toDelayedStorageImage()) { + StorageImageLocation loc = now->location(); + if (!loc.isNull()) { + img->setStorageLocation(loc); } } +} - PhotoData *photo(const PhotoId &photo) { - PhotosData::const_iterator i = ::photosData.constFind(photo); - if (i == ::photosData.cend()) { - i = ::photosData.insert(photo, new PhotoData(photo)); - } - return i.value(); +PhotoData *photo(const PhotoId &photo) { + PhotosData::const_iterator i = ::photosData.constFind(photo); + if (i == ::photosData.cend()) { + i = ::photosData.insert(photo, new PhotoData(photo)); } + return i.value(); +} - PhotoData *photoSet(const PhotoId &photo, PhotoData *convert, const uint64 &access, int32 date, const ImagePtr &thumb, const ImagePtr &medium, const ImagePtr &full) { +PhotoData *photoSet(const PhotoId &photo, PhotoData *convert, const quint64 &access, qint32 date, const ImagePtr &thumb, + const ImagePtr &medium, const ImagePtr &full) { + if (convert) { + if (convert->id != photo) { + PhotosData::iterator i = ::photosData.find(convert->id); + if (i != ::photosData.cend() && i.value() == convert) { + ::photosData.erase(i); + } + convert->id = photo; + convert->uploadingData.reset(); + } + if (date) { + convert->access = access; + convert->date = date; + updateImage(convert->thumb, thumb); + updateImage(convert->medium, medium); + updateImage(convert->full, full); + } + } + PhotosData::const_iterator i = ::photosData.constFind(photo); + PhotoData *result; + LastPhotosMap::iterator inLastIter = lastPhotosMap.end(); + if (i == ::photosData.cend()) { if (convert) { - if (convert->id != photo) { - PhotosData::iterator i = ::photosData.find(convert->id); - if (i != ::photosData.cend() && i.value() == convert) { - ::photosData.erase(i); - } - convert->id = photo; - convert->uploadingData.reset(); - } - if (date) { - convert->access = access; - convert->date = date; - updateImage(convert->thumb, thumb); - updateImage(convert->medium, medium); - updateImage(convert->full, full); - } - } - PhotosData::const_iterator i = ::photosData.constFind(photo); - PhotoData *result; - LastPhotosMap::iterator inLastIter = lastPhotosMap.end(); - if (i == ::photosData.cend()) { - if (convert) { - result = convert; - } else { - result = new PhotoData(photo, access, date, thumb, medium, full); - } - ::photosData.insert(photo, result); - } else { - result = i.value(); - if (result != convert && date) { - result->access = access; - result->date = date; - updateImage(result->thumb, thumb); - updateImage(result->medium, medium); - updateImage(result->full, full); - } - inLastIter = lastPhotosMap.find(result); - } - if (inLastIter == lastPhotosMap.end()) { // insert new one - if (lastPhotos.size() == MaxPhotosInMemory) { - lastPhotos.front()->forget(); - lastPhotosMap.remove(lastPhotos.front()); - lastPhotos.pop_front(); - } - lastPhotosMap.insert(result, lastPhotos.insert(lastPhotos.end(), result)); + result = convert; } else { - lastPhotos.erase(inLastIter.value()); // move to back - (*inLastIter) = lastPhotos.insert(lastPhotos.end(), result); - } - return result; - } + result = new PhotoData(photo, access, date, thumb, medium, full); + } + ::photosData.insert(photo, result); + } else { + result = i.value(); + if (result != convert && date) { + result->access = access; + result->date = date; + updateImage(result->thumb, thumb); + updateImage(result->medium, medium); + updateImage(result->full, full); + } + inLastIter = lastPhotosMap.find(result); + } + if (inLastIter == lastPhotosMap.end()) { // insert new one + if (lastPhotos.size() == MaxPhotosInMemory) { + lastPhotos.front()->forget(); + lastPhotosMap.remove(lastPhotos.front()); + lastPhotos.pop_front(); + } + lastPhotosMap.insert(result, lastPhotos.insert(lastPhotos.end(), result)); + } else { + lastPhotos.erase(inLastIter.value()); // move to back + (*inLastIter) = lastPhotos.insert(lastPhotos.end(), result); + } + return result; +} - DocumentData *document(const DocumentId &document) { - DocumentsData::const_iterator i = ::documentsData.constFind(document); - if (i == ::documentsData.cend()) { - i = ::documentsData.insert(document, DocumentData::create(document)); - } - return i.value(); +DocumentData *document(const DocumentId &document) { + DocumentsData::const_iterator i = ::documentsData.constFind(document); + if (i == ::documentsData.cend()) { + i = ::documentsData.insert(document, DocumentData::create(document)); } + return i.value(); +} - DocumentData *documentSet(const DocumentId &document, DocumentData *convert, const uint64 &access, int32 version, int32 date, const QVector &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size, const StorageImageLocation &thumbLocation) { - bool versionChanged = false; - bool sentSticker = false; - if (convert) { - MediaKey oldKey = convert->mediaKey(); - bool idChanged = (convert->id != document); - if (idChanged) { - DocumentsData::iterator i = ::documentsData.find(convert->id); - if (i != ::documentsData.cend() && i.value() == convert) { - ::documentsData.erase(i); - } - - convert->id = document; - convert->status = FileReady; - sentSticker = (convert->sticker() != 0); +DocumentData *documentSet(const DocumentId &document, DocumentData *convert, const quint64 &access, qint32 version, + qint32 date, const QVector &attributes, const QString &mime, + const ImagePtr &thumb, qint32 dc, qint32 size, const StorageImageLocation &thumbLocation) { + bool versionChanged = false; + bool sentSticker = false; + if (convert) { + MediaKey oldKey = convert->mediaKey(); + bool idChanged = (convert->id != document); + if (idChanged) { + DocumentsData::iterator i = ::documentsData.find(convert->id); + if (i != ::documentsData.cend() && i.value() == convert) { + ::documentsData.erase(i); + } + + convert->id = document; + convert->status = FileReady; + sentSticker = (convert->sticker() != 0); + } + if (date) { + convert->setattributes(attributes); + versionChanged = convert->setRemoteVersion(version); + convert->setRemoteLocation(dc, access); + convert->date = date; + convert->setMimeString(mime); + if (!thumb->isNull() && (convert->thumb->isNull() || convert->thumb->width() < thumb->width() || + convert->thumb->height() < thumb->height() || versionChanged)) { + updateImage(convert->thumb, thumb); + } + convert->size = size; + convert->recountIsImage(); + if (convert->sticker() && convert->sticker()->loc.isNull() && !thumbLocation.isNull()) { + convert->sticker()->loc = thumbLocation; } - if (date) { - convert->setattributes(attributes); - versionChanged = convert->setRemoteVersion(version); - convert->setRemoteLocation(dc, access); - convert->date = date; - convert->mime = mime; - if (!thumb->isNull() && (convert->thumb->isNull() || convert->thumb->width() < thumb->width() || convert->thumb->height() < thumb->height() || versionChanged)) { - updateImage(convert->thumb, thumb); - } - convert->size = size; - convert->recountIsImage(); - if (convert->sticker() && convert->sticker()->loc.isNull() && !thumbLocation.isNull()) { - convert->sticker()->loc = thumbLocation; - } - MediaKey newKey = convert->mediaKey(); - if (idChanged) { - if (convert->voice()) { - Local::copyAudio(oldKey, newKey); - } else if (convert->sticker() || convert->isAnimation()) { - Local::copyStickerImage(oldKey, newKey); - } + MediaKey newKey = convert->mediaKey(); + if (idChanged) { + if (convert->voice()) { + Local::copyAudio(oldKey, newKey); + } else if (convert->sticker() || convert->isAnimation()) { + Local::copyStickerImage(oldKey, newKey); } } + } - if (cSavedGifs().indexOf(convert) >= 0) { // id changed - Local::writeSavedGifs(); - } + if (cSavedGifs().indexOf(convert) >= 0) { // id changed + Local::writeSavedGifs(); } - DocumentsData::const_iterator i = ::documentsData.constFind(document); - DocumentData *result; - if (i == ::documentsData.cend()) { - if (convert) { - result = convert; - } else { - result = DocumentData::create(document, dc, access, version, attributes); - result->date = date; - result->mime = mime; + } + DocumentsData::const_iterator i = ::documentsData.constFind(document); + DocumentData *result; + if (i == ::documentsData.cend()) { + if (convert) { + result = convert; + } else { + result = DocumentData::create(document, dc, access, version, attributes); + result->date = date; + result->setMimeString(mime); + result->thumb = thumb; + result->size = size; + result->recountIsImage(); + if (result->sticker()) { + result->sticker()->loc = thumbLocation; + } + } + ::documentsData.insert(document, result); + } else { + result = i.value(); + if (result != convert && date) { + result->setattributes(attributes); + versionChanged = result->setRemoteVersion(version); + if (!result->isValid()) { + result->setRemoteLocation(dc, access); + } + result->date = date; + result->setMimeString(mime); + if (!thumb->isNull() && (result->thumb->isNull() || result->thumb->width() < thumb->width() || + result->thumb->height() < thumb->height() || versionChanged)) { result->thumb = thumb; - result->size = size; - result->recountIsImage(); - if (result->sticker()) { - result->sticker()->loc = thumbLocation; - } } - ::documentsData.insert(document, result); - } else { - result = i.value(); - if (result != convert && date) { - result->setattributes(attributes); - versionChanged = result->setRemoteVersion(version); - if (!result->isValid()) { - result->setRemoteLocation(dc, access); - } - result->date = date; - result->mime = mime; - if (!thumb->isNull() && (result->thumb->isNull() || result->thumb->width() < thumb->width() || result->thumb->height() < thumb->height() || versionChanged)) { - result->thumb = thumb; - } - result->size = size; - result->recountIsImage(); - if (result->sticker() && result->sticker()->loc.isNull() && !thumbLocation.isNull()) { - result->sticker()->loc = thumbLocation; - } + result->size = size; + result->recountIsImage(); + if (result->sticker() && result->sticker()->loc.isNull() && !thumbLocation.isNull()) { + result->sticker()->loc = thumbLocation; } } - if (sentSticker && App::main()) { - App::main()->incrementSticker(result); - } - if (versionChanged) { - if (result->sticker() && result->sticker()->set.type() == mtpc_inputStickerSetID) { - auto it = Global::StickerSets().constFind(result->sticker()->set.c_inputStickerSetID().vid.v); - if (it != Global::StickerSets().cend()) { - if (it->id == Stickers::CloudRecentSetId) { - Local::writeRecentStickers(); - } else if (it->id == Stickers::FavedSetId) { - Local::writeFavedStickers(); - } else if (it->flags & MTPDstickerSet::Flag::f_archived) { - Local::writeArchivedStickers(); - } else if (it->flags & MTPDstickerSet::Flag::f_installed) { - Local::writeInstalledStickers(); - } - if (it->flags & MTPDstickerSet_ClientFlag::f_featured) { - Local::writeFeaturedStickers(); - } + } + if (sentSticker && App::main()) { + App::main()->incrementSticker(result); + } + if (versionChanged) { + if (result->sticker() && result->sticker()->set.type() == mtpc_inputStickerSetID) { + auto it = Global::StickerSets().constFind(result->sticker()->set.c_inputStickerSetID().vid.v); + if (it != Global::StickerSets().cend()) { + if (it->id == Stickers::CloudRecentSetId) { + Local::writeRecentStickers(); + } else if (it->id == Stickers::FavedSetId) { + Local::writeFavedStickers(); + } else if (it->flags & MTPDstickerSet::Flag::f_archived) { + Local::writeArchivedStickers(); + } else if (it->flags & MTPDstickerSet::Flag::f_installed) { + Local::writeInstalledStickers(); } - } - auto &items = App::documentItems(); - auto i = items.constFind(result); - if (i != items.cend()) { - for_const (auto item, i.value()) { - item->setPendingInitDimensions(); + if (it->flags & MTPDstickerSet_ClientFlag::f_featured) { + Local::writeFeaturedStickers(); } } } - return result; + auto &items = App::documentItems(); + auto i = items.constFind(result); + if (i != items.cend()) { + for_const (auto item, i.value()) { item->setPendingInitDimensions(); } + } } + return result; +} - WebPageData *webPage(const WebPageId &webPage) { - auto i = webPagesData.constFind(webPage); - if (i == webPagesData.cend()) { - i = webPagesData.insert(webPage, new WebPageData(webPage)); - } - return i.value(); +WebPageData *webPage(const WebPageId &webPage) { + auto i = webPagesData.constFind(webPage); + if (i == webPagesData.cend()) { + i = webPagesData.insert(webPage, new WebPageData(webPage)); } + return i.value(); +} - WebPageData *webPageSet(const WebPageId &webPage, WebPageData *convert, const QString &type, const QString &url, const QString &displayUrl, const QString &siteName, const QString &title, const TextWithEntities &description, PhotoData *photo, DocumentData *document, int32 duration, const QString &author, int32 pendingTill) { +WebPageData *webPageSet(const WebPageId &webPage, WebPageData *convert, const QString &type, const QString &url, + const QString &displayUrl, const QString &siteName, const QString &title, + const TextWithEntities &description, PhotoData *photo, DocumentData *document, qint32 duration, + const QString &author, qint32 pendingTill) { + if (convert) { + if (convert->id != webPage) { + auto i = webPagesData.find(convert->id); + if (i != webPagesData.cend() && i.value() == convert) { + webPagesData.erase(i); + } + convert->id = webPage; + } + if ((convert->url.isEmpty() && !url.isEmpty()) || + (convert->pendingTill && convert->pendingTill != pendingTill && pendingTill >= -1)) { + convert->type = toWebPageType(type); + convert->url = TextUtilities::Clean(url); + convert->displayUrl = TextUtilities::Clean(displayUrl); + convert->siteName = TextUtilities::Clean(siteName); + convert->title = TextUtilities::SingleLine(title); + convert->description = description; + convert->photo = photo; + convert->document = document; + convert->duration = duration; + convert->author = TextUtilities::Clean(author); + if (convert->pendingTill > 0 && pendingTill <= 0) { + Auth().api().clearWebPageRequest(convert); + } + convert->pendingTill = pendingTill; + if (App::main()) App::main()->webPageUpdated(convert); + } + } + auto i = webPagesData.constFind(webPage); + WebPageData *result; + if (i == webPagesData.cend()) { if (convert) { - if (convert->id != webPage) { - auto i = webPagesData.find(convert->id); - if (i != webPagesData.cend() && i.value() == convert) { - webPagesData.erase(i); - } - convert->id = webPage; - } - if ((convert->url.isEmpty() && !url.isEmpty()) || (convert->pendingTill && convert->pendingTill != pendingTill && pendingTill >= -1)) { - convert->type = toWebPageType(type); - convert->url = TextUtilities::Clean(url); - convert->displayUrl = TextUtilities::Clean(displayUrl); - convert->siteName = TextUtilities::Clean(siteName); - convert->title = TextUtilities::SingleLine(title); - convert->description = description; - convert->photo = photo; - convert->document = document; - convert->duration = duration; - convert->author = TextUtilities::Clean(author); - if (convert->pendingTill > 0 && pendingTill <= 0) { - Auth().api().clearWebPageRequest(convert); - } - convert->pendingTill = pendingTill; - if (App::main()) App::main()->webPageUpdated(convert); - } - } - auto i = webPagesData.constFind(webPage); - WebPageData *result; - if (i == webPagesData.cend()) { - if (convert) { - result = convert; - } else { - result = new WebPageData(webPage, toWebPageType(type), url, displayUrl, siteName, title, description, document, photo, duration, author, (pendingTill >= -1) ? pendingTill : -1); - if (pendingTill > 0) { - Auth().api().requestWebPageDelayed(result); - } - } - webPagesData.insert(webPage, result); + result = convert; } else { - result = i.value(); - if (result != convert) { - if ((result->url.isEmpty() && !url.isEmpty()) || (result->pendingTill && result->pendingTill != pendingTill && pendingTill >= -1)) { - result->type = toWebPageType(type); - result->url = TextUtilities::Clean(url); - result->displayUrl = TextUtilities::Clean(displayUrl); - result->siteName = TextUtilities::Clean(siteName); - result->title = TextUtilities::SingleLine(title); - result->description = description; - result->photo = photo; - result->document = document; - result->duration = duration; - result->author = TextUtilities::Clean(author); - if (result->pendingTill > 0 && pendingTill <= 0) { - Auth().api().clearWebPageRequest(result); - } - result->pendingTill = pendingTill; - if (App::main()) App::main()->webPageUpdated(result); + result = new WebPageData(webPage, toWebPageType(type), url, displayUrl, siteName, title, description, + document, photo, duration, author, (pendingTill >= -1) ? pendingTill : -1); + if (pendingTill > 0) { + Auth().api().requestWebPageDelayed(result); + } + } + webPagesData.insert(webPage, result); + } else { + result = i.value(); + if (result != convert) { + if ((result->url.isEmpty() && !url.isEmpty()) || + (result->pendingTill && result->pendingTill != pendingTill && pendingTill >= -1)) { + result->type = toWebPageType(type); + result->url = TextUtilities::Clean(url); + result->displayUrl = TextUtilities::Clean(displayUrl); + result->siteName = TextUtilities::Clean(siteName); + result->title = TextUtilities::SingleLine(title); + result->description = description; + result->photo = photo; + result->document = document; + result->duration = duration; + result->author = TextUtilities::Clean(author); + if (result->pendingTill > 0 && pendingTill <= 0) { + Auth().api().clearWebPageRequest(result); } + result->pendingTill = pendingTill; + if (App::main()) App::main()->webPageUpdated(result); } } - return result; } + return result; +} - GameData *game(const GameId &game) { - auto i = gamesData.constFind(game); - if (i == gamesData.cend()) { - i = gamesData.insert(game, new GameData(game)); - } - return i.value(); +GameData *game(const GameId &game) { + auto i = gamesData.constFind(game); + if (i == gamesData.cend()) { + i = gamesData.insert(game, new GameData(game)); } + return i.value(); +} - GameData *gameSet(const GameId &game, GameData *convert, const uint64 &accessHash, const QString &shortName, const QString &title, const QString &description, PhotoData *photo, DocumentData *document) { +GameData *gameSet(const GameId &game, GameData *convert, const quint64 &accessHash, const QString &shortName, + const QString &title, const QString &description, PhotoData *photo, DocumentData *document) { + if (convert) { + if (convert->id != game) { + auto i = gamesData.find(convert->id); + if (i != gamesData.cend() && i.value() == convert) { + gamesData.erase(i); + } + convert->id = game; + convert->accessHash = 0; + } + if (!convert->accessHash && accessHash) { + convert->accessHash = accessHash; + convert->shortName = TextUtilities::Clean(shortName); + convert->title = TextUtilities::SingleLine(title); + convert->description = TextUtilities::Clean(description); + convert->photo = photo; + convert->document = document; + if (App::main()) App::main()->gameUpdated(convert); + } + } + auto i = gamesData.constFind(game); + GameData *result; + if (i == gamesData.cend()) { if (convert) { - if (convert->id != game) { - auto i = gamesData.find(convert->id); - if (i != gamesData.cend() && i.value() == convert) { - gamesData.erase(i); - } - convert->id = game; - convert->accessHash = 0; - } - if (!convert->accessHash && accessHash) { - convert->accessHash = accessHash; - convert->shortName = TextUtilities::Clean(shortName); - convert->title = TextUtilities::SingleLine(title); - convert->description = TextUtilities::Clean(description); - convert->photo = photo; - convert->document = document; - if (App::main()) App::main()->gameUpdated(convert); - } - } - auto i = gamesData.constFind(game); - GameData *result; - if (i == gamesData.cend()) { - if (convert) { - result = convert; - } else { - result = new GameData(game, accessHash, shortName, title, description, photo, document); - } - gamesData.insert(game, result); + result = convert; } else { - result = i.value(); - if (result != convert) { - if (!result->accessHash && accessHash) { - result->accessHash = accessHash; - result->shortName = TextUtilities::Clean(shortName); - result->title = TextUtilities::SingleLine(title); - result->description = TextUtilities::Clean(description); - result->photo = photo; - result->document = document; - if (App::main()) App::main()->gameUpdated(result); - } + result = new GameData(game, accessHash, shortName, title, description, photo, document); + } + gamesData.insert(game, result); + } else { + result = i.value(); + if (result != convert) { + if (!result->accessHash && accessHash) { + result->accessHash = accessHash; + result->shortName = TextUtilities::Clean(shortName); + result->title = TextUtilities::SingleLine(title); + result->description = TextUtilities::Clean(description); + result->photo = photo; + result->document = document; + if (App::main()) App::main()->gameUpdated(result); } } - return result; } + return result; +} - LocationData *location(const LocationCoords &coords) { - auto i = locationsData.constFind(coords); - if (i == locationsData.cend()) { - i = locationsData.insert(coords, new LocationData(coords)); - } - return i.value(); +LocationData *location(const LocationCoords &coords) { + auto i = locationsData.constFind(coords); + if (i == locationsData.cend()) { + i = locationsData.insert(coords, new LocationData(coords)); } + return i.value(); +} - void forgetMedia() { - lastPhotos.clear(); - lastPhotosMap.clear(); - for_const (auto photo, ::photosData) { - photo->forget(); - } - for_const (auto document, ::documentsData) { - document->forget(); - } - for_const (auto location, ::locationsData) { - location->thumb->forget(); - } - } +void forgetMedia() { + lastPhotos.clear(); + lastPhotosMap.clear(); + for_const (auto photo, ::photosData) { photo->forget(); } + for_const (auto document, ::documentsData) { document->forget(); } + for_const (auto location, ::locationsData) { location->thumb->forget(); } +} - MTPPhoto photoFromUserPhoto(MTPint userId, MTPint date, const MTPUserProfilePhoto &photo) { - if (photo.type() == mtpc_userProfilePhoto) { - const auto &uphoto(photo.c_userProfilePhoto()); +MTPPhoto photoFromUserPhoto(MTPint userId, MTPint date, const MTPUserProfilePhoto &photo) { + if (photo.type() == mtpc_userProfilePhoto) { + const auto &uphoto(photo.c_userProfilePhoto()); - QVector photoSizes; - photoSizes.push_back(MTP_photoSize(MTP_string("a"), uphoto.vphoto_small, MTP_int(160), MTP_int(160), MTP_int(0))); - photoSizes.push_back(MTP_photoSize(MTP_string("c"), uphoto.vphoto_big, MTP_int(640), MTP_int(640), MTP_int(0))); + QVector photoSizes; + photoSizes.push_back( + MTP_photoSize(MTP_string("a"), uphoto.vphoto_small, MTP_int(160), MTP_int(160), MTP_int(0))); + photoSizes.push_back(MTP_photoSize(MTP_string("c"), uphoto.vphoto_big, MTP_int(640), MTP_int(640), MTP_int(0))); - return MTP_photo(MTP_flags(0), uphoto.vphoto_id, MTP_long(0), date, MTP_vector(photoSizes)); - } - return MTP_photoEmpty(MTP_long(0)); + return MTP_photo(MTP_flags(0), uphoto.vphoto_id, MTP_long(0), date, MTP_vector(photoSizes)); } + return MTP_photoEmpty(MTP_long(0)); +} - QString peerName(const PeerData *peer, bool forDialogs) { - return peer ? ((forDialogs && peer->isUser() && !peer->asUser()->nameOrPhone.isEmpty()) ? peer->asUser()->nameOrPhone : peer->name) : lang(lng_deleted); - } +QString peerName(const PeerData *peer, bool forDialogs) { + return peer ? + ((forDialogs && peer->isUser() && !peer->asUser()->nameOrPhone.isEmpty()) ? peer->asUser()->nameOrPhone : + peer->name) : + lang(lng_deleted); +} - Histories &histories() { - return ::histories; - } +Histories &histories() { + return ::histories; +} - not_null history(const PeerId &peer) { - return ::histories.findOrInsert(peer); - } +not_null history(const PeerId &peer) { + return ::histories.findOrInsert(peer); +} - History *historyFromDialog(const PeerId &peer, int32 unreadCnt, int32 maxInboxRead, int32 maxOutboxRead) { - return ::histories.findOrInsert(peer, unreadCnt, maxInboxRead, maxOutboxRead); - } +History *historyFromDialog(const PeerId &peer, qint32 unreadCnt, qint32 maxInboxRead, qint32 maxOutboxRead) { + return ::histories.findOrInsert(peer, unreadCnt, maxInboxRead, maxOutboxRead); +} - History *historyLoaded(const PeerId &peer) { - return ::histories.find(peer); - } +History *historyLoaded(const PeerId &peer) { + return ::histories.find(peer); +} - HistoryItem *histItemById(ChannelId channelId, MsgId itemId) { - if (!itemId) return nullptr; +HistoryItem *histItemById(ChannelId channelId, MsgId itemId) { + if (!itemId) return nullptr; - auto data = fetchMsgsData(channelId, false); - if (!data) return nullptr; + auto data = fetchMsgsData(channelId, false); + if (!data) return nullptr; - auto i = data->constFind(itemId); - if (i != data->cend()) { - return i.value(); - } - return nullptr; + auto i = data->constFind(itemId); + if (i != data->cend()) { + return i.value(); } + return nullptr; +} - void historyRegItem(HistoryItem *item) { - MsgsData *data = fetchMsgsData(item->channelId()); - MsgsData::const_iterator i = data->constFind(item->id); - if (i == data->cend()) { - data->insert(item->id, item); - } else if (i.value() != item) { - LOG(("App Error: trying to historyRegItem() an already registered item")); - i.value()->destroy(); - data->insert(item->id, item); - } +void historyRegItem(HistoryItem *item) { + MsgsData *data = fetchMsgsData(item->channelId()); + MsgsData::const_iterator i = data->constFind(item->id); + if (i == data->cend()) { + data->insert(item->id, item); + } else if (i.value() != item) { + LOG(("App Error: trying to historyRegItem() an already registered item")); + i.value()->destroy(); + data->insert(item->id, item); } +} - void historyItemDetached(HistoryItem *item) { - if (::hoveredItem == item) { - hoveredItem(nullptr); - } - if (::pressedItem == item) { - pressedItem(nullptr); - } - if (::hoveredLinkItem == item) { - hoveredLinkItem(nullptr); - } - if (::pressedLinkItem == item) { - pressedLinkItem(nullptr); - } - if (::contextItem == item) { - contextItem(nullptr); - } - if (::mousedItem == item) { - mousedItem(nullptr); - } +void historyItemDetached(HistoryItem *item) { + if (::hoveredItem == item) { + hoveredItem(nullptr); } - - void historyUnregItem(HistoryItem *item) { - auto data = fetchMsgsData(item->channelId(), false); - if (!data) return; - - auto i = data->find(item->id); - if (i != data->cend()) { - if (i.value() == item) { - data->erase(i); - } - } - historyItemDetached(item); - auto j = ::dependentItems.find(item); - if (j != ::dependentItems.cend()) { - DependentItemsSet items; - std::swap(items, j.value()); - ::dependentItems.erase(j); - - for_const (auto dependent, items) { - dependent->dependencyItemRemoved(item); - } - } - Auth().notifications().clearFromItem(item); - if (Global::started() && !App::quitting()) { - Global::RefItemRemoved().notify(item, true); - } + if (::pressedItem == item) { + pressedItem(nullptr); } - - void historyUpdateDependent(HistoryItem *item) { - DependentItems::iterator j = ::dependentItems.find(item); - if (j != ::dependentItems.cend()) { - for_const (HistoryItem *dependent, j.value()) { - dependent->updateDependencyItem(); - } - } - if (App::main()) { - App::main()->itemEdited(item); - } + if (::hoveredLinkItem == item) { + hoveredLinkItem(nullptr); } + if (::pressedLinkItem == item) { + pressedLinkItem(nullptr); + } + if (::contextItem == item) { + contextItem(nullptr); + } + if (::mousedItem == item) { + mousedItem(nullptr); + } +} - void historyClearMsgs() { - ::dependentItems.clear(); +void historyUnregItem(HistoryItem *item) { + auto data = fetchMsgsData(item->channelId(), false); + if (!data) return; - QVector toDelete; - for_const (auto item, msgsData) { - if (item->detached()) { - toDelete.push_back(item); - } + auto i = data->find(item->id); + if (i != data->cend()) { + if (i.value() == item) { + data->erase(i); } - for_const (auto &chMsgsData, channelMsgsData) { - for_const (auto item, chMsgsData) { - if (item->detached()) { - toDelete.push_back(item); - } - } - } - msgsData.clear(); - channelMsgsData.clear(); - for_const (auto item, toDelete) { - delete item; - } - - clearMousedItems(); } + historyItemDetached(item); + auto j = ::dependentItems.find(item); + if (j != ::dependentItems.cend()) { + DependentItemsSet items; + std::swap(items, j.value()); + ::dependentItems.erase(j); - void historyClearItems() { - randomData.clear(); - sentData.clear(); - mutedPeers.clear(); - cSetSavedPeers(SavedPeers()); - cSetSavedPeersByTime(SavedPeersByTime()); - cSetRecentInlineBots(RecentInlineBots()); + for_const (auto dependent, items) { dependent->dependencyItemRemoved(item); } + } + Auth().notifications().clearFromItem(item); + if (Global::started() && !App::quitting()) { + Global::RefItemRemoved().notify(item, true); + } +} - for_const (auto peer, ::peersData) { - delete peer; - } - ::peersData.clear(); - for_const (auto game, ::gamesData) { - delete game; - } - ::gamesData.clear(); - for_const (auto webpage, ::webPagesData) { - delete webpage; - } - ::webPagesData.clear(); - for_const (auto photo, ::photosData) { - delete photo; - } - ::photosData.clear(); - for_const (auto document, ::documentsData) { - delete document; - } - ::documentsData.clear(); +void historyUpdateDependent(HistoryItem *item) { + DependentItems::iterator j = ::dependentItems.find(item); + if (j != ::dependentItems.cend()) { + for_const (HistoryItem *dependent, j.value()) { dependent->updateDependencyItem(); } + } + if (App::main()) { + App::main()->itemEdited(item); + } +} - if (AuthSession::Exists()) { - Auth().api().clearWebPageRequests(); - } - cSetRecentStickers(RecentStickerPack()); - Global::SetStickerSets(Stickers::Sets()); - Global::SetStickerSetsOrder(Stickers::Order()); - Global::SetLastStickersUpdate(0); - Global::SetLastRecentStickersUpdate(0); - Global::SetFeaturedStickerSetsOrder(Stickers::Order()); - if (Global::FeaturedStickerSetsUnreadCount() != 0) { - Global::SetFeaturedStickerSetsUnreadCount(0); - Global::RefFeaturedStickerSetsUnreadCountChanged().notify(); +void historyClearMsgs() { + ::dependentItems.clear(); + + QVector toDelete; + for_const (auto item, msgsData) { + if (item->detached()) { + toDelete.push_back(item); } - Global::SetLastFeaturedStickersUpdate(0); - Global::SetArchivedStickerSetsOrder(Stickers::Order()); - cSetSavedGifs(SavedGifs()); - cSetLastSavedGifsUpdate(0); - cSetReportSpamStatuses(ReportSpamStatuses()); - cSetAutoDownloadPhoto(0); - cSetAutoDownloadAudio(0); - cSetAutoDownloadGif(0); - ::photoItems.clear(); - ::documentItems.clear(); - ::webPageItems.clear(); - ::gameItems.clear(); - ::sharedContactItems.clear(); - ::gifItems.clear(); - lastPhotos.clear(); - lastPhotosMap.clear(); - ::self = nullptr; - Global::RefSelfChanged().notify(true); - } - - void historyRegDependency(HistoryItem *dependent, HistoryItem *dependency) { - ::dependentItems[dependency].insert(dependent); - } - - void historyUnregDependency(HistoryItem *dependent, HistoryItem *dependency) { - auto i = ::dependentItems.find(dependency); - if (i != ::dependentItems.cend()) { - i.value().remove(dependent); - if (i.value().isEmpty()) { - ::dependentItems.erase(i); + } + for_const (auto &chMsgsData, channelMsgsData) { + for_const (auto item, chMsgsData) { + if (item->detached()) { + toDelete.push_back(item); } } } + msgsData.clear(); + channelMsgsData.clear(); + for_const (auto item, toDelete) { delete item; } - void historyRegRandom(uint64 randomId, const FullMsgId &itemId) { - randomData.insert(randomId, itemId); - } + clearMousedItems(); +} - void historyUnregRandom(uint64 randomId) { - randomData.remove(randomId); - } +void historyClearItems() { + randomData.clear(); + sentData.clear(); + mutedPeers.clear(); + cSetSavedPeers(SavedPeers()); + cSetSavedPeersByTime(SavedPeersByTime()); + cSetRecentInlineBots(RecentInlineBots()); + + for_const (auto peer, ::peersData) { delete peer; } + ::peersData.clear(); + for_const (auto game, ::gamesData) { delete game; } + ::gamesData.clear(); + for_const (auto webpage, ::webPagesData) { delete webpage; } + ::webPagesData.clear(); + for_const (auto photo, ::photosData) { delete photo; } + ::photosData.clear(); + for_const (auto document, ::documentsData) { delete document; } + ::documentsData.clear(); + + if (AuthSession::Exists()) { + Auth().api().clearWebPageRequests(); + } + cSetRecentStickers(RecentStickerPack()); + Global::SetStickerSets(Stickers::Sets()); + Global::SetStickerSetsOrder(Stickers::Order()); + Global::SetLastStickersUpdate(0); + Global::SetLastRecentStickersUpdate(0); + Global::SetFeaturedStickerSetsOrder(Stickers::Order()); + if (Global::FeaturedStickerSetsUnreadCount() != 0) { + Global::SetFeaturedStickerSetsUnreadCount(0); + Global::RefFeaturedStickerSetsUnreadCountChanged().notify(); + } + Global::SetLastFeaturedStickersUpdate(0); + Global::SetArchivedStickerSetsOrder(Stickers::Order()); + cSetSavedGifs(SavedGifs()); + cSetLastSavedGifsUpdate(0); + cSetReportSpamStatuses(ReportSpamStatuses()); + cSetAutoDownloadPhoto(0); + cSetAutoDownloadAudio(0); + cSetAutoDownloadGif(0); + ::photoItems.clear(); + ::documentItems.clear(); + ::webPageItems.clear(); + ::gameItems.clear(); + ::sharedContactItems.clear(); + ::gifItems.clear(); + lastPhotos.clear(); + lastPhotosMap.clear(); + ::self = nullptr; + Global::RefSelfChanged().notify(true); +} + +void historyRegDependency(HistoryItem *dependent, HistoryItem *dependency) { + ::dependentItems[dependency].insert(dependent); +} - FullMsgId histItemByRandom(uint64 randomId) { - RandomData::const_iterator i = randomData.constFind(randomId); - if (i != randomData.cend()) { - return i.value(); +void historyUnregDependency(HistoryItem *dependent, HistoryItem *dependency) { + auto i = ::dependentItems.find(dependency); + if (i != ::dependentItems.cend()) { + i.value().erase(dependent); + if (i.value().empty()) { + ::dependentItems.erase(i); } - return FullMsgId(); } +} - void historyRegSentData(uint64 randomId, const PeerId &peerId, const QString &text) { - sentData.insert(randomId, qMakePair(peerId, text)); - } +void historyRegRandom(quint64 randomId, const FullMsgId &itemId) { + randomData.insert(randomId, itemId); +} - void historyUnregSentData(uint64 randomId) { - sentData.remove(randomId); - } +void historyUnregRandom(quint64 randomId) { + randomData.remove(randomId); +} - void histSentDataByItem(uint64 randomId, PeerId &peerId, QString &text) { - QPair d = sentData.value(randomId); - peerId = d.first; - text = d.second; +FullMsgId histItemByRandom(quint64 randomId) { + RandomData::const_iterator i = randomData.constFind(randomId); + if (i != randomData.cend()) { + return i.value(); } + return FullMsgId(); +} - void prepareCorners(RoundCorners index, int32 radius, const QBrush &brush, const style::color *shadow = nullptr, QImage *cors = nullptr) { - Expects(::corners.size() > index); - int32 r = radius * cIntRetinaFactor(), s = st::msgShadow * cIntRetinaFactor(); - QImage rect(r * 3, r * 3 + (shadow ? s : 0), QImage::Format_ARGB32_Premultiplied), localCors[4]; - { - Painter p(&rect); - PainterHighQualityEnabler hq(p); +void historyRegSentData(quint64 randomId, const PeerId &peerId, const QString &text) { + sentData.insert(randomId, qMakePair(peerId, text)); +} - p.setCompositionMode(QPainter::CompositionMode_Source); - p.fillRect(QRect(0, 0, rect.width(), rect.height()), Qt::transparent); - p.setCompositionMode(QPainter::CompositionMode_SourceOver); - p.setPen(Qt::NoPen); - if (shadow) { - p.setBrush((*shadow)->b); - p.drawRoundedRect(0, s, r * 3, r * 3, r, r); - } - p.setBrush(brush); - p.drawRoundedRect(0, 0, r * 3, r * 3, r, r); - } - if (!cors) cors = localCors; - cors[0] = rect.copy(0, 0, r, r); - cors[1] = rect.copy(r * 2, 0, r, r); - cors[2] = rect.copy(0, r * 2, r, r + (shadow ? s : 0)); - cors[3] = rect.copy(r * 2, r * 2, r, r + (shadow ? s : 0)); - if (index != SmallMaskCorners && index != LargeMaskCorners) { - for (int i = 0; i < 4; ++i) { - ::corners[index].p[i] = pixmapFromImageInPlace(std::move(cors[i])); - ::corners[index].p[i].setDevicePixelRatio(cRetinaFactor()); - } +void historyUnregSentData(quint64 randomId) { + sentData.remove(randomId); +} + +void histSentDataByItem(quint64 randomId, PeerId &peerId, QString &text) { + QPair d = sentData.value(randomId); + peerId = d.first; + text = d.second; +} + +void prepareCorners(RoundCorners index, qint32 radius, const QBrush &brush, const style::color *shadow = nullptr, + QImage *cors = nullptr) { + Expects(::corners.size() > index); + qint32 r = radius * cIntRetinaFactor(), s = st::msgShadow * cIntRetinaFactor(); + QImage rect(r * 3, r * 3 + (shadow ? s : 0), QImage::Format_ARGB32_Premultiplied), localCors[4]; + { + Painter p(&rect); + PainterHighQualityEnabler hq(p); + + p.setCompositionMode(QPainter::CompositionMode_Source); + p.fillRect(QRect(0, 0, rect.width(), rect.height()), Qt::transparent); + p.setCompositionMode(QPainter::CompositionMode_SourceOver); + p.setPen(Qt::NoPen); + if (shadow) { + p.setBrush((*shadow)->b); + p.drawRoundedRect(0, s, r * 3, r * 3, r, r); + } + p.setBrush(brush); + p.drawRoundedRect(0, 0, r * 3, r * 3, r, r); + } + if (!cors) cors = localCors; + cors[0] = rect.copy(0, 0, r, r); + cors[1] = rect.copy(r * 2, 0, r, r); + cors[2] = rect.copy(0, r * 2, r, r + (shadow ? s : 0)); + cors[3] = rect.copy(r * 2, r * 2, r, r + (shadow ? s : 0)); + if (index != SmallMaskCorners && index != LargeMaskCorners) { + for (int i = 0; i < 4; ++i) { + ::corners[index].p[i] = pixmapFromImageInPlace(std::move(cors[i])); + ::corners[index].p[i].setDevicePixelRatio(cRetinaFactor()); } } +} - void tryFontFamily(QString &family, const QString &tryFamily) { - if (family.isEmpty()) { - if (!QFontInfo(QFont(tryFamily)).family().trimmed().compare(tryFamily, Qt::CaseInsensitive)) { - family = tryFamily; - } +void tryFontFamily(QString &family, const QString &tryFamily) { + if (family.isEmpty()) { + if (!QFontInfo(QFont(tryFamily)).family().trimmed().compare(tryFamily, Qt::CaseInsensitive)) { + family = tryFamily; } } +} + +int msgRadius() { + static int MsgRadius = ([]() { + return st::historyMessageRadius; + auto minMsgHeight = (st::msgPadding.top() + st::msgFont->height + st::msgPadding.bottom()); + return minMsgHeight / 2; + })(); + return MsgRadius; +} - int msgRadius() { - static int MsgRadius = ([]() { - return st::historyMessageRadius; - auto minMsgHeight = (st::msgPadding.top() + st::msgFont->height + st::msgPadding.bottom()); - return minMsgHeight / 2; - })(); - return MsgRadius; +void createMaskCorners() { + QImage mask[4]; + prepareCorners(SmallMaskCorners, st::buttonRadius, QColor(255, 255, 255), nullptr, mask); + for (int i = 0; i < 4; ++i) { + ::cornersMaskSmall[i] = mask[i].convertToFormat(QImage::Format_ARGB32_Premultiplied); + ::cornersMaskSmall[i].setDevicePixelRatio(cRetinaFactor()); + } + prepareCorners(LargeMaskCorners, msgRadius(), QColor(255, 255, 255), nullptr, mask); + for (int i = 0; i < 4; ++i) { + ::cornersMaskLarge[i] = mask[i].convertToFormat(QImage::Format_ARGB32_Premultiplied); + ::cornersMaskLarge[i].setDevicePixelRatio(cRetinaFactor()); } +} - void createMaskCorners() { - QImage mask[4]; - prepareCorners(SmallMaskCorners, st::buttonRadius, QColor(255, 255, 255), nullptr, mask); - for (int i = 0; i < 4; ++i) { - ::cornersMaskSmall[i] = mask[i].convertToFormat(QImage::Format_ARGB32_Premultiplied); - ::cornersMaskSmall[i].setDevicePixelRatio(cRetinaFactor()); - } - prepareCorners(LargeMaskCorners, msgRadius(), QColor(255, 255, 255), nullptr, mask); - for (int i = 0; i < 4; ++i) { - ::cornersMaskLarge[i] = mask[i].convertToFormat(QImage::Format_ARGB32_Premultiplied); - ::cornersMaskLarge[i].setDevicePixelRatio(cRetinaFactor()); - } - } - - void createPaletteCorners() { - prepareCorners(MenuCorners, st::buttonRadius, st::menuBg); - prepareCorners(BoxCorners, st::boxRadius, st::boxBg); - prepareCorners(BotKbOverCorners, st::dateRadius, st::msgBotKbOverBgAdd); - prepareCorners(StickerCorners, st::dateRadius, st::msgServiceBg); - prepareCorners(StickerSelectedCorners, st::dateRadius, st::msgServiceBgSelected); - prepareCorners(SelectedOverlaySmallCorners, st::buttonRadius, st::msgSelectOverlay); - prepareCorners(SelectedOverlayLargeCorners, msgRadius(), st::msgSelectOverlay); - prepareCorners(DateCorners, st::dateRadius, st::msgDateImgBg); - prepareCorners(DateSelectedCorners, st::dateRadius, st::msgDateImgBgSelected); - prepareCorners(InShadowCorners, msgRadius(), st::msgInShadow); - prepareCorners(InSelectedShadowCorners, msgRadius(), st::msgInShadowSelected); - prepareCorners(ForwardCorners, msgRadius(), st::historyForwardChooseBg); - prepareCorners(MediaviewSaveCorners, st::mediaviewControllerRadius, st::mediaviewSaveMsgBg); - prepareCorners(EmojiHoverCorners, st::buttonRadius, st::emojiPanHover); - prepareCorners(StickerHoverCorners, st::buttonRadius, st::emojiPanHover); - prepareCorners(BotKeyboardCorners, st::buttonRadius, st::botKbBg); - prepareCorners(PhotoSelectOverlayCorners, st::buttonRadius, st::overviewPhotoSelectOverlay); - - prepareCorners(Doc1Corners, st::buttonRadius, st::msgFile1Bg); - prepareCorners(Doc2Corners, st::buttonRadius, st::msgFile2Bg); - prepareCorners(Doc3Corners, st::buttonRadius, st::msgFile3Bg); - prepareCorners(Doc4Corners, st::buttonRadius, st::msgFile4Bg); - - prepareCorners(MessageInCorners, msgRadius(), st::msgInBg, &st::msgInShadow); - prepareCorners(MessageInSelectedCorners, msgRadius(), st::msgInBgSelected, &st::msgInShadowSelected); - prepareCorners(MessageOutCorners, msgRadius(), st::msgOutBg, &st::msgOutShadow); - prepareCorners(MessageOutSelectedCorners, msgRadius(), st::msgOutBgSelected, &st::msgOutShadowSelected); - } - - void createCorners() { - ::corners.resize(RoundCornersCount); - createMaskCorners(); - createPaletteCorners(); - } - - void clearCorners() { - ::corners.clear(); - ::cornersMap.clear(); - } - - void initMedia() { - if (!::monofont) { - QString family; - tryFontFamily(family, qsl("Consolas")); - tryFontFamily(family, qsl("Liberation Mono")); - tryFontFamily(family, qsl("Menlo")); - tryFontFamily(family, qsl("Courier")); - if (family.isEmpty()) family = QFontDatabase::systemFont(QFontDatabase::FixedFont).family(); - ::monofont = style::font(st::normalFont->f.pixelSize(), 0, family); - } - Ui::Emoji::Init(); - if (!::emoji) { - ::emoji = new QPixmap(Ui::Emoji::Filename(Ui::Emoji::Index())); - if (cRetina()) ::emoji->setDevicePixelRatio(cRetinaFactor()); - } - if (!::emojiLarge) { - ::emojiLarge = new QPixmap(Ui::Emoji::Filename(Ui::Emoji::Index() + 1)); - if (cRetina()) ::emojiLarge->setDevicePixelRatio(cRetinaFactor()); - } - - createCorners(); - - using Update = Window::Theme::BackgroundUpdate; - static auto subscription = Window::Theme::Background()->add_subscription([](const Update &update) { - if (update.paletteChanged()) { - createPaletteCorners(); - - if (App::main()) { - App::main()->updateScrollColors(); - } - HistoryLayout::serviceColorsUpdated(); - } else if (update.type == Update::Type::New) { - prepareCorners(StickerCorners, st::dateRadius, st::msgServiceBg); - prepareCorners(StickerSelectedCorners, st::dateRadius, st::msgServiceBgSelected); +void createPaletteCorners() { + prepareCorners(MenuCorners, st::buttonRadius, st::menuBg); + prepareCorners(BoxCorners, st::boxRadius, st::boxBg); + prepareCorners(BotKbOverCorners, st::dateRadius, st::msgBotKbOverBgAdd); + prepareCorners(StickerCorners, st::dateRadius, st::msgServiceBg); + prepareCorners(StickerSelectedCorners, st::dateRadius, st::msgServiceBgSelected); + prepareCorners(SelectedOverlaySmallCorners, st::buttonRadius, st::msgSelectOverlay); + prepareCorners(SelectedOverlayLargeCorners, msgRadius(), st::msgSelectOverlay); + prepareCorners(DateCorners, st::dateRadius, st::msgDateImgBg); + prepareCorners(DateSelectedCorners, st::dateRadius, st::msgDateImgBgSelected); + prepareCorners(InShadowCorners, msgRadius(), st::msgInShadow); + prepareCorners(InSelectedShadowCorners, msgRadius(), st::msgInShadowSelected); + prepareCorners(ForwardCorners, msgRadius(), st::historyForwardChooseBg); + prepareCorners(MediaviewSaveCorners, st::mediaviewControllerRadius, st::mediaviewSaveMsgBg); + prepareCorners(EmojiHoverCorners, st::buttonRadius, st::emojiPanHover); + prepareCorners(StickerHoverCorners, st::buttonRadius, st::emojiPanHover); + prepareCorners(BotKeyboardCorners, st::buttonRadius, st::botKbBg); + prepareCorners(PhotoSelectOverlayCorners, st::buttonRadius, st::overviewPhotoSelectOverlay); + + prepareCorners(Doc1Corners, st::buttonRadius, st::msgFile1Bg); + prepareCorners(Doc2Corners, st::buttonRadius, st::msgFile2Bg); + prepareCorners(Doc3Corners, st::buttonRadius, st::msgFile3Bg); + prepareCorners(Doc4Corners, st::buttonRadius, st::msgFile4Bg); + + prepareCorners(MessageInCorners, msgRadius(), st::msgInBg, &st::msgInShadow); + prepareCorners(MessageInSelectedCorners, msgRadius(), st::msgInBgSelected, &st::msgInShadowSelected); + prepareCorners(MessageOutCorners, msgRadius(), st::msgOutBg, &st::msgOutShadow); + prepareCorners(MessageOutSelectedCorners, msgRadius(), st::msgOutBgSelected, &st::msgOutShadowSelected); +} - if (App::main()) { - App::main()->updateScrollColors(); - } - HistoryLayout::serviceColorsUpdated(); - } - }); +void createCorners() { + ::corners.resize(RoundCornersCount); + createMaskCorners(); + createPaletteCorners(); +} + +void clearCorners() { + ::corners.clear(); + ::cornersMap.clear(); +} + +void initMedia() { + if (!::monofont) { + QString family; + tryFontFamily(family, qsl("Consolas")); + tryFontFamily(family, qsl("Liberation Mono")); + tryFontFamily(family, qsl("Menlo")); + tryFontFamily(family, qsl("Courier")); + if (family.isEmpty()) family = QFontDatabase::systemFont(QFontDatabase::FixedFont).family(); + ::monofont = style::font(st::normalFont->f.pixelSize(), 0, family); + } + Ui::Emoji::Init(); + if (!::emoji) { + ::emoji = new QPixmap(Ui::Emoji::Filename(Ui::Emoji::Index())); + if (cRetina()) ::emoji->setDevicePixelRatio(cRetinaFactor()); + } + if (!::emojiLarge) { + ::emojiLarge = new QPixmap(Ui::Emoji::Filename(Ui::Emoji::Index() + 1)); + if (cRetina()) ::emojiLarge->setDevicePixelRatio(cRetinaFactor()); } - void clearHistories() { - ClickHandler::clearActive(); - ClickHandler::unpressed(); + createCorners(); - if (AuthSession::Exists()) { - // Clear notifications to prevent any showNotification() calls while destroying items. - Auth().notifications().clearAllFast(); - } + using Update = Window::Theme::BackgroundUpdate; + static auto subscription = Window::Theme::Background()->add_subscription([](const Update &update) { + if (update.paletteChanged()) { + createPaletteCorners(); + + if (App::main()) { + App::main()->updateScrollColors(); + } + HistoryLayout::serviceColorsUpdated(); + } else if (update.type == Update::Type::New) { + prepareCorners(StickerCorners, st::dateRadius, st::msgServiceBg); + prepareCorners(StickerSelectedCorners, st::dateRadius, st::msgServiceBgSelected); - histories().clear(); + if (App::main()) { + App::main()->updateScrollColors(); + } + HistoryLayout::serviceColorsUpdated(); + } + }); +} - clearStorageImages(); - cSetServerBackgrounds(WallPapers()); +void clearHistories() { + ClickHandler::clearActive(); + ClickHandler::unpressed(); - serviceImageCacheSize = imageCacheSize(); + if (AuthSession::Exists()) { + // Clear notifications to prevent any showNotification() calls while destroying items. + Auth().notifications().clearAllFast(); } - void deinitMedia() { - delete ::emoji; - ::emoji = nullptr; - delete ::emojiLarge; - ::emojiLarge = nullptr; + histories().clear(); - clearCorners(); + clearStorageImages(); + cSetServerBackgrounds(WallPapers()); - MainEmojiMap.clear(); - OtherEmojiMap.clear(); + serviceImageCacheSize = imageCacheSize(); +} - Data::clearGlobalStructures(); +void deinitMedia() { + delete ::emoji; + ::emoji = nullptr; + delete ::emojiLarge; + ::emojiLarge = nullptr; - clearAllImages(); - } + clearCorners(); - void hoveredItem(HistoryItem *item) { - ::hoveredItem = item; - } + MainEmojiMap.clear(); + OtherEmojiMap.clear(); - HistoryItem *hoveredItem() { - return ::hoveredItem; - } + Data::clearGlobalStructures(); - void pressedItem(HistoryItem *item) { - ::pressedItem = item; - } + clearAllImages(); +} - HistoryItem *pressedItem() { - return ::pressedItem; - } +void hoveredItem(HistoryItem *item) { + ::hoveredItem = item; +} - void hoveredLinkItem(HistoryItem *item) { - ::hoveredLinkItem = item; - } +HistoryItem *hoveredItem() { + return ::hoveredItem; +} - HistoryItem *hoveredLinkItem() { - return ::hoveredLinkItem; - } +void pressedItem(HistoryItem *item) { + ::pressedItem = item; +} - void pressedLinkItem(HistoryItem *item) { - ::pressedLinkItem = item; - } +HistoryItem *pressedItem() { + return ::pressedItem; +} - HistoryItem *pressedLinkItem() { - return ::pressedLinkItem; - } +void hoveredLinkItem(HistoryItem *item) { + ::hoveredLinkItem = item; +} - void contextItem(HistoryItem *item) { - ::contextItem = item; - } +HistoryItem *hoveredLinkItem() { + return ::hoveredLinkItem; +} - HistoryItem *contextItem() { - return ::contextItem; - } +void pressedLinkItem(HistoryItem *item) { + ::pressedLinkItem = item; +} - void mousedItem(HistoryItem *item) { - ::mousedItem = item; - } +HistoryItem *pressedLinkItem() { + return ::pressedLinkItem; +} - HistoryItem *mousedItem() { - return ::mousedItem; - } +void contextItem(HistoryItem *item) { + ::contextItem = item; +} - void clearMousedItems() { - hoveredItem(nullptr); - pressedItem(nullptr); - hoveredLinkItem(nullptr); - pressedLinkItem(nullptr); - contextItem(nullptr); - mousedItem(nullptr); - } +HistoryItem *contextItem() { + return ::contextItem; +} - const style::font &monofont() { - return ::monofont; - } +void mousedItem(HistoryItem *item) { + ::mousedItem = item; +} - const QPixmap &emoji() { - return *::emoji; - } +HistoryItem *mousedItem() { + return ::mousedItem; +} - const QPixmap &emojiLarge() { - return *::emojiLarge; - } +void clearMousedItems() { + hoveredItem(nullptr); + pressedItem(nullptr); + hoveredLinkItem(nullptr); + pressedLinkItem(nullptr); + contextItem(nullptr); + mousedItem(nullptr); +} - const QPixmap &emojiSingle(EmojiPtr emoji, int32 fontHeight) { - auto &map = (fontHeight == st::msgFont->height) ? MainEmojiMap : OtherEmojiMap[fontHeight]; - auto i = map.constFind(emoji->index()); - if (i == map.cend()) { - auto image = QImage(Ui::Emoji::Size() + st::emojiPadding * cIntRetinaFactor() * 2, fontHeight * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied); - if (cRetina()) image.setDevicePixelRatio(cRetinaFactor()); - image.fill(Qt::transparent); - { - QPainter p(&image); - emojiDraw(p, emoji, st::emojiPadding * cIntRetinaFactor(), (fontHeight * cIntRetinaFactor() - Ui::Emoji::Size()) / 2); - } - i = map.insert(emoji->index(), App::pixmapFromImageInPlace(std::move(image))); - } - return i.value(); - } +const style::font &monofont() { + return ::monofont; +} + +const QPixmap &emoji() { + return *::emoji; +} - void checkImageCacheSize() { - int64 nowImageCacheSize = imageCacheSize(); - if (nowImageCacheSize > serviceImageCacheSize + MemoryForImageCache) { - App::forgetMedia(); - serviceImageCacheSize = imageCacheSize(); +const QPixmap &emojiLarge() { + return *::emojiLarge; +} + +const QPixmap &emojiSingle(EmojiPtr emoji, qint32 fontHeight) { + auto &map = (fontHeight == st::msgFont->height) ? MainEmojiMap : OtherEmojiMap[fontHeight]; + auto i = map.constFind(emoji->index()); + if (i == map.cend()) { + auto image = QImage(Ui::Emoji::Size() + st::emojiPadding * cIntRetinaFactor() * 2, + fontHeight * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied); + if (cRetina()) image.setDevicePixelRatio(cRetinaFactor()); + image.fill(Qt::transparent); + { + QPainter p(&image); + emojiDraw(p, emoji, st::emojiPadding * cIntRetinaFactor(), + (fontHeight * cIntRetinaFactor() - Ui::Emoji::Size()) / 2); } + i = map.insert(emoji->index(), App::pixmapFromImageInPlace(std::move(image))); } + return i.value(); +} - bool isValidPhone(QString phone) { - phone = phone.replace(QRegularExpression(qsl("[^\\d]")), QString()); - return phone.length() >= 8 || phone == qsl("777") || phone == qsl("333") || phone == qsl("111") || (phone.startsWith(qsl("42")) && (phone.length() == 2 || phone.length() == 5 || phone == qsl("4242"))); +void checkImageCacheSize() { + qint64 nowImageCacheSize = imageCacheSize(); + if (nowImageCacheSize > serviceImageCacheSize + MemoryForImageCache) { + App::forgetMedia(); + serviceImageCacheSize = imageCacheSize(); } +} - void quit() { - if (quitting()) return; - setLaunchState(QuitRequested); +bool isValidPhone(QString phone) { + phone = phone.replace(QRegularExpression(qsl("[^\\d]")), QString()); + return phone.length() >= 8 || phone == qsl("777") || phone == qsl("333") || phone == qsl("111") || + (phone.startsWith(qsl("42")) && (phone.length() == 2 || phone.length() == 5 || phone == qsl("4242"))); +} - if (auto window = wnd()) { - if (!Sandbox::isSavingSession()) { - window->hide(); - } - } - if (auto mainwidget = main()) { - mainwidget->saveDraftToCloud(); +void quit() { + if (quitting()) return; + setLaunchState(QuitRequested); + + if (auto window = wnd()) { + if (!Sandbox::isSavingSession()) { + window->hide(); } - Messenger::QuitAttempt(); } - - bool quitting() { - return _launchState != Launched; + if (auto mainwidget = main()) { + mainwidget->saveDraftToCloud(); } + Messenger::QuitAttempt(); +} - LaunchState launchState() { - return _launchState; - } +bool quitting() { + return _launchState != Launched; +} - void setLaunchState(LaunchState state) { - _launchState = state; - } +LaunchState launchState() { + return _launchState; +} - void restart() { -#ifndef TDESKTOP_DISABLE_AUTOUPDATE - bool updateReady = (Sandbox::updatingState() == Application::UpdatingReady); -#else // !TDESKTOP_DISABLE_AUTOUPDATE - bool updateReady = false; -#endif // else for !TDESKTOP_DISABLE_AUTOUPDATE - if (updateReady) { - cSetRestartingUpdate(true); - } else { - cSetRestarting(true); - cSetRestartingToSettings(true); - } - App::quit(); - } +void setLaunchState(LaunchState state) { + _launchState = state; +} - QImage readImage(QByteArray data, QByteArray *format, bool opaque, bool *animated) { - QByteArray tmpFormat; - QImage result; - QBuffer buffer(&data); - if (!format) { - format = &tmpFormat; - } - { - QImageReader reader(&buffer, *format); +void restart() { + cSetRestarting(true); + cSetRestartingToSettings(true); + App::quit(); +} + +QImage readImage(QByteArray data, QByteArray *format, bool opaque, bool *animated) { + QByteArray tmpFormat; + QImage result; + QBuffer buffer(&data); + if (!format) { + format = &tmpFormat; + } + { + QImageReader reader(&buffer, *format); #ifndef OS_MAC_OLD - reader.setAutoTransform(true); + reader.setAutoTransform(true); #endif // OS_MAC_OLD - if (animated) *animated = reader.supportsAnimation() && reader.imageCount() > 1; - QByteArray fmt = reader.format(); - if (!fmt.isEmpty()) *format = fmt; - if (!reader.read(&result)) { - return QImage(); - } - fmt = reader.format(); - if (!fmt.isEmpty()) *format = fmt; + if (animated) *animated = reader.supportsAnimation() && reader.imageCount() > 1; + QByteArray fmt = reader.format(); + if (!fmt.isEmpty()) *format = fmt; + if (!reader.read(&result)) { + return QImage(); } - buffer.seek(0); - auto fmt = QString::fromUtf8(*format).toLower(); - if (fmt == "jpg" || fmt == "jpeg") { + fmt = reader.format(); + if (!fmt.isEmpty()) *format = fmt; + } + buffer.seek(0); + auto fmt = QString::fromUtf8(*format).toLower(); + if (fmt == "jpg" || fmt == "jpeg") { #ifdef OS_MAC_OLD - if (auto exifData = exif_data_new_from_data((const uchar*)(data.constData()), data.size())) { - auto byteOrder = exif_data_get_byte_order(exifData); - if (auto exifEntry = exif_data_get_entry(exifData, EXIF_TAG_ORIENTATION)) { - auto orientationFix = [exifEntry, byteOrder] { - auto orientation = exif_get_short(exifEntry->data, byteOrder); - switch (orientation) { - case 2: return QTransform(-1, 0, 0, 1, 0, 0); - case 3: return QTransform(-1, 0, 0, -1, 0, 0); - case 4: return QTransform(1, 0, 0, -1, 0, 0); - case 5: return QTransform(0, -1, -1, 0, 0, 0); - case 6: return QTransform(0, 1, -1, 0, 0, 0); - case 7: return QTransform(0, 1, 1, 0, 0, 0); - case 8: return QTransform(0, -1, 1, 0, 0, 0); - } - return QTransform(); - }; - result = result.transformed(orientationFix()); - } - exif_data_free(exifData); + if (auto exifData = exif_data_new_from_data((const uchar *)(data.constData()), data.size())) { + auto byteOrder = exif_data_get_byte_order(exifData); + if (auto exifEntry = exif_data_get_entry(exifData, EXIF_TAG_ORIENTATION)) { + auto orientationFix = [exifEntry, byteOrder] { + auto orientation = exif_get_short(exifEntry->data, byteOrder); + switch (orientation) { + case 2: return QTransform(-1, 0, 0, 1, 0, 0); + case 3: return QTransform(-1, 0, 0, -1, 0, 0); + case 4: return QTransform(1, 0, 0, -1, 0, 0); + case 5: return QTransform(0, -1, -1, 0, 0, 0); + case 6: return QTransform(0, 1, -1, 0, 0, 0); + case 7: return QTransform(0, 1, 1, 0, 0, 0); + case 8: return QTransform(0, -1, 1, 0, 0, 0); + } + return QTransform(); + }; + result = result.transformed(orientationFix()); } -#endif // OS_MAC_OLD - } else if (opaque) { - result = Images::prepareOpaque(std::move(result)); + exif_data_free(exifData); } - return result; +#endif // OS_MAC_OLD + } else if (opaque) { + result = Images::prepareOpaque(std::move(result)); } + return result; +} - QImage readImage(const QString &file, QByteArray *format, bool opaque, bool *animated, QByteArray *content) { - QFile f(file); - if (f.size() > kImageSizeLimit || !f.open(QIODevice::ReadOnly)) { - if (animated) *animated = false; - return QImage(); - } - auto imageBytes = f.readAll(); - auto result = readImage(imageBytes, format, opaque, animated); - if (content && !result.isNull()) { - *content = imageBytes; - } - return result; +QImage readImage(const QString &file, QByteArray *format, bool opaque, bool *animated, QByteArray *content) { + QFile f(file); + if (f.size() > kImageSizeLimit || !f.open(QIODevice::ReadOnly)) { + if (animated) *animated = false; + return QImage(); } - - QPixmap pixmapFromImageInPlace(QImage &&image) { - return QPixmap::fromImage(std::move(image), Qt::ColorOnly); + auto imageBytes = f.readAll(); + auto result = readImage(imageBytes, format, opaque, animated); + if (content && !result.isNull()) { + *content = imageBytes; } + return result; +} - void regPhotoItem(PhotoData *data, HistoryItem *item) { - ::photoItems[data].insert(item); - } +QPixmap pixmapFromImageInPlace(QImage &&image) { + return QPixmap::fromImage(std::move(image), Qt::ColorOnly); +} - void unregPhotoItem(PhotoData *data, HistoryItem *item) { - ::photoItems[data].remove(item); - } +void regPhotoItem(PhotoData *data, HistoryItem *item) { + ::photoItems[data].insert(item); +} - const PhotoItems &photoItems() { - return ::photoItems; - } +void unregPhotoItem(PhotoData *data, HistoryItem *item) { + ::photoItems[data].erase(item); +} - const PhotosData &photosData() { - return ::photosData; - } +const PhotoItems &photoItems() { + return ::photoItems; +} - void regDocumentItem(DocumentData *data, HistoryItem *item) { - ::documentItems[data].insert(item); - } +const PhotosData &photosData() { + return ::photosData; +} - void unregDocumentItem(DocumentData *data, HistoryItem *item) { - ::documentItems[data].remove(item); - } +void regDocumentItem(DocumentData *data, HistoryItem *item) { + ::documentItems[data].insert(item); +} - const DocumentItems &documentItems() { - return ::documentItems; - } +void unregDocumentItem(DocumentData *data, HistoryItem *item) { + ::documentItems[data].erase(item); +} - const DocumentsData &documentsData() { - return ::documentsData; - } +const DocumentItems &documentItems() { + return ::documentItems; +} - void regWebPageItem(WebPageData *data, HistoryItem *item) { - ::webPageItems[data].insert(item); - } +const DocumentsData &documentsData() { + return ::documentsData; +} - void unregWebPageItem(WebPageData *data, HistoryItem *item) { - ::webPageItems[data].remove(item); - } +void regWebPageItem(WebPageData *data, HistoryItem *item) { + ::webPageItems[data].insert(item); +} - const WebPageItems &webPageItems() { - return ::webPageItems; - } +void unregWebPageItem(WebPageData *data, HistoryItem *item) { + ::webPageItems[data].erase(item); +} - void regGameItem(GameData *data, HistoryItem *item) { - ::gameItems[data].insert(item); - } +const WebPageItems &webPageItems() { + return ::webPageItems; +} - void unregGameItem(GameData *data, HistoryItem *item) { - ::gameItems[data].remove(item); - } +void regGameItem(GameData *data, HistoryItem *item) { + ::gameItems[data].insert(item); +} - const GameItems &gameItems() { - return ::gameItems; - } +void unregGameItem(GameData *data, HistoryItem *item) { + ::gameItems[data].erase(item); +} - void regSharedContactItem(int32 userId, HistoryItem *item) { - auto user = App::userLoaded(userId); - auto canShareThisContact = user ? user->canShareThisContact() : false; - ::sharedContactItems[userId].insert(item); - if (canShareThisContact != (user ? user->canShareThisContact() : false)) { - Notify::peerUpdatedDelayed(user, Notify::PeerUpdate::Flag::UserCanShareContact); - } - } +const GameItems &gameItems() { + return ::gameItems; +} - void unregSharedContactItem(int32 userId, HistoryItem *item) { - auto user = App::userLoaded(userId); - auto canShareThisContact = user ? user->canShareThisContact() : false; - ::sharedContactItems[userId].remove(item); - if (canShareThisContact != (user ? user->canShareThisContact() : false)) { - Notify::peerUpdatedDelayed(user, Notify::PeerUpdate::Flag::UserCanShareContact); - } +void regSharedContactItem(qint32 userId, HistoryItem *item) { + auto user = App::userLoaded(userId); + auto canShareThisContact = user ? user->canShareThisContact() : false; + ::sharedContactItems[userId].insert(item); + if (canShareThisContact != (user ? user->canShareThisContact() : false)) { + Notify::peerUpdatedDelayed(user, Notify::PeerUpdate::Flag::UserCanShareContact); } +} - const SharedContactItems &sharedContactItems() { - return ::sharedContactItems; +void unregSharedContactItem(qint32 userId, HistoryItem *item) { + auto user = App::userLoaded(userId); + auto canShareThisContact = user ? user->canShareThisContact() : false; + ::sharedContactItems[userId].erase(item); + if (canShareThisContact != (user ? user->canShareThisContact() : false)) { + Notify::peerUpdatedDelayed(user, Notify::PeerUpdate::Flag::UserCanShareContact); } +} - void regGifItem(Media::Clip::Reader *reader, HistoryItem *item) { - ::gifItems.insert(reader, item); - } +const SharedContactItems &sharedContactItems() { + return ::sharedContactItems; +} - void unregGifItem(Media::Clip::Reader *reader) { - ::gifItems.remove(reader); - } +void regGifItem(Media::Clip::Reader *reader, HistoryItem *item) { + ::gifItems.insert(reader, item); +} - void stopGifItems() { - if (!::gifItems.isEmpty()) { - auto gifs = ::gifItems; - for_const (auto item, gifs) { - if (auto media = item->getMedia()) { - if (!media->isRoundVideoPlaying()) { - media->stopInline(); - } +void unregGifItem(Media::Clip::Reader *reader) { + ::gifItems.remove(reader); +} + +void stopGifItems() { + if (!::gifItems.isEmpty()) { + auto gifs = ::gifItems; + for_const (auto item, gifs) { + if (auto media = item->getMedia()) { + if (!media->isRoundVideoPlaying()) { + media->stopInline(); } } } } +} - QString phoneFromSharedContact(int32 userId) { - auto i = ::sharedContactItems.constFind(userId); - if (i != ::sharedContactItems.cend() && !i->isEmpty()) { - if (auto media = (*i->cbegin())->getMedia()) { - if (media->type() == MediaTypeContact) { - return static_cast(media)->phone(); - } +QString phoneFromSharedContact(qint32 userId) { + auto i = ::sharedContactItems.constFind(userId); + if (i != ::sharedContactItems.cend() && !i->empty()) { + if (auto media = (*i->cbegin())->getMedia()) { + if (media->type() == MediaTypeContact) { + return static_cast(media)->phone(); } } - return QString(); } + return QString(); +} - void regMuted(PeerData *peer, int32 changeIn) { - ::mutedPeers.insert(peer, true); - if (App::main()) App::main()->updateMutedIn(changeIn); - } +void regMuted(PeerData *peer, qint32 changeIn) { + ::mutedPeers.insert(peer, true); + if (App::main()) App::main()->updateMutedIn(changeIn); +} - void unregMuted(PeerData *peer) { - ::mutedPeers.remove(peer); - } +void unregMuted(PeerData *peer) { + ::mutedPeers.remove(peer); +} - void updateMuted() { - int32 changeInMin = 0; - for (MutedPeers::iterator i = ::mutedPeers.begin(); i != ::mutedPeers.end();) { - int32 changeIn = 0; - History *h = App::history(i.key()->id); - if (isNotifyMuted(i.key()->notify, &changeIn)) { - h->setMute(true); - if (changeIn && (!changeInMin || changeIn < changeInMin)) { - changeInMin = changeIn; - } - ++i; - } else { - h->setMute(false); - i = ::mutedPeers.erase(i); - } +void updateMuted() { + qint32 changeInMin = 0; + for (MutedPeers::iterator i = ::mutedPeers.begin(); i != ::mutedPeers.end();) { + qint32 changeIn = 0; + History *h = App::history(i.key()->id); + if (isNotifyMuted(i.key()->notify, &changeIn)) { + h->setMute(true); + if (changeIn && (!changeInMin || changeIn < changeInMin)) { + changeInMin = changeIn; + } + ++i; + } else { + h->setMute(false); + i = ::mutedPeers.erase(i); } - if (changeInMin) App::main()->updateMutedIn(changeInMin); } + if (changeInMin) App::main()->updateMutedIn(changeInMin); +} - void setProxySettings(QNetworkAccessManager &manager) { +void setProxySettings(QNetworkAccessManager &manager) { #ifndef TDESKTOP_DISABLE_NETWORK_PROXY - manager.setProxy(getHttpProxySettings()); + manager.setProxy(getHttpProxySettings()); #endif // !TDESKTOP_DISABLE_NETWORK_PROXY - } +} #ifndef TDESKTOP_DISABLE_NETWORK_PROXY - QNetworkProxy getHttpProxySettings() { - const ProxyData *proxy = nullptr; - if (Global::started()) { - proxy = (Global::ConnectionType() == dbictHttpProxy) ? (&Global::ConnectionProxy()) : nullptr; - } else { - proxy = Sandbox::PreLaunchProxy().host.isEmpty() ? nullptr : (&Sandbox::PreLaunchProxy()); - } - if (proxy) { - return QNetworkProxy(QNetworkProxy::HttpProxy, proxy->host, proxy->port, proxy->user, proxy->password); - } - return QNetworkProxy(QNetworkProxy::DefaultProxy); +QNetworkProxy getHttpProxySettings() { + const ProxyData *proxy = nullptr; + if (Global::started()) { + proxy = (Global::ConnectionType() == dbictHttpProxy) ? (&Global::ConnectionProxy()) : nullptr; + } else { + proxy = Sandbox::PreLaunchProxy().host.isEmpty() ? nullptr : (&Sandbox::PreLaunchProxy()); } + if (proxy) { + return QNetworkProxy(QNetworkProxy::HttpProxy, proxy->host, proxy->port, proxy->user, proxy->password); + } + return QNetworkProxy(QNetworkProxy::DefaultProxy); +} #endif // !TDESKTOP_DISABLE_NETWORK_PROXY - void setProxySettings(QTcpSocket &socket) { +void setProxySettings(QTcpSocket &socket) { #ifndef TDESKTOP_DISABLE_NETWORK_PROXY - if (Global::ConnectionType() == dbictTcpProxy) { - auto &p = Global::ConnectionProxy(); - socket.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, p.host, p.port, p.user, p.password)); - } else { - socket.setProxy(QNetworkProxy(QNetworkProxy::NoProxy)); - } -#endif // !TDESKTOP_DISABLE_NETWORK_PROXY + if (Global::ConnectionType() == dbictTcpProxy) { + auto &p = Global::ConnectionProxy(); + socket.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, p.host, p.port, p.user, p.password)); + } else { + socket.setProxy(QNetworkProxy(QNetworkProxy::NoProxy)); } +#endif // !TDESKTOP_DISABLE_NETWORK_PROXY +} - void complexAdjustRect(ImageRoundCorners corners, QRect &rect, RectParts &parts) { - if (corners & ImageRoundCorner::TopLeft) { - if (!(corners & ImageRoundCorner::BottomLeft)) { - parts = RectPart::NoTopBottom | RectPart::FullTop; - rect.setHeight(rect.height() + msgRadius()); - } - } else if (corners & ImageRoundCorner::BottomLeft) { - parts = RectPart::NoTopBottom | RectPart::FullBottom; - rect.setTop(rect.y() - msgRadius()); - } else { - parts = RectPart::NoTopBottom; - rect.setTop(rect.y() - msgRadius()); +void complexAdjustRect(ImageRoundCorners corners, QRect &rect, RectParts &parts) { + if (corners & ImageRoundCorner::TopLeft) { + if (!(corners & ImageRoundCorner::BottomLeft)) { + parts = RectPart::NoTopBottom | RectPart::FullTop; rect.setHeight(rect.height() + msgRadius()); } + } else if (corners & ImageRoundCorner::BottomLeft) { + parts = RectPart::NoTopBottom | RectPart::FullBottom; + rect.setTop(rect.y() - msgRadius()); + } else { + parts = RectPart::NoTopBottom; + rect.setTop(rect.y() - msgRadius()); + rect.setHeight(rect.height() + msgRadius()); } +} - void complexOverlayRect(Painter &p, QRect rect, ImageRoundRadius radius, ImageRoundCorners corners) { - if (radius == ImageRoundRadius::Ellipse) { - PainterHighQualityEnabler hq(p); - p.setPen(Qt::NoPen); - p.setBrush(p.textPalette().selectOverlay); - p.drawEllipse(rect); - } else { - auto overlayCorners = (radius == ImageRoundRadius::Small) ? SelectedOverlaySmallCorners : SelectedOverlayLargeCorners; - auto overlayParts = RectPart::Full | RectPart::None; - if (radius == ImageRoundRadius::Large) { - complexAdjustRect(corners, rect, overlayParts); - } - roundRect(p, rect, p.textPalette().selectOverlay, overlayCorners, nullptr, overlayParts); - } +void complexOverlayRect(Painter &p, QRect rect, ImageRoundRadius radius, ImageRoundCorners corners) { + if (radius == ImageRoundRadius::Ellipse) { + PainterHighQualityEnabler hq(p); + p.setPen(Qt::NoPen); + p.setBrush(p.textPalette().selectOverlay); + p.drawEllipse(rect); + } else { + auto overlayCorners = + (radius == ImageRoundRadius::Small) ? SelectedOverlaySmallCorners : SelectedOverlayLargeCorners; + auto overlayParts = RectPart::Full | RectPart::None; + if (radius == ImageRoundRadius::Large) { + complexAdjustRect(corners, rect, overlayParts); + } + roundRect(p, rect, p.textPalette().selectOverlay, overlayCorners, nullptr, overlayParts); } +} - void complexLocationRect(Painter &p, QRect rect, ImageRoundRadius radius, ImageRoundCorners corners) { - auto parts = RectPart::Full | RectPart::None; - complexAdjustRect(corners, rect, parts); - roundRect(p, rect, st::msgInBg, MessageInCorners, nullptr, parts); +void complexLocationRect(Painter &p, QRect rect, ImageRoundRadius radius, ImageRoundCorners corners) { + auto parts = RectPart::Full | RectPart::None; + complexAdjustRect(corners, rect, parts); + roundRect(p, rect, st::msgInBg, MessageInCorners, nullptr, parts); +} + +QImage *cornersMask(ImageRoundRadius radius) { + switch (radius) { + case ImageRoundRadius::Large: return ::cornersMaskLarge; + case ImageRoundRadius::Small: + default: break; } + return ::cornersMaskSmall; +} - QImage *cornersMask(ImageRoundRadius radius) { - switch (radius) { - case ImageRoundRadius::Large: return ::cornersMaskLarge; - case ImageRoundRadius::Small: - default: break; +void roundRect(Painter &p, qint32 x, qint32 y, qint32 w, qint32 h, style::color bg, const CornersPixmaps &corner, + const style::color *shadow, RectParts parts) { + auto cornerWidth = corner.p[0].width() / cIntRetinaFactor(); + auto cornerHeight = corner.p[0].height() / cIntRetinaFactor(); + if (w < 2 * cornerWidth || h < 2 * cornerHeight) return; + if (w > 2 * cornerWidth) { + if (parts & RectPart::Top) { + p.fillRect(x + cornerWidth, y, w - 2 * cornerWidth, cornerHeight, bg); + } + if (parts & RectPart::Bottom) { + p.fillRect(x + cornerWidth, y + h - cornerHeight, w - 2 * cornerWidth, cornerHeight, bg); + if (shadow) { + p.fillRect(x + cornerWidth, y + h, w - 2 * cornerWidth, st::msgShadow, *shadow); + } } - return ::cornersMaskSmall; } - - void roundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, style::color bg, const CornersPixmaps &corner, const style::color *shadow, RectParts parts) { - auto cornerWidth = corner.p[0].width() / cIntRetinaFactor(); - auto cornerHeight = corner.p[0].height() / cIntRetinaFactor(); - if (w < 2 * cornerWidth || h < 2 * cornerHeight) return; - if (w > 2 * cornerWidth) { - if (parts & RectPart::Top) { - p.fillRect(x + cornerWidth, y, w - 2 * cornerWidth, cornerHeight, bg); + if (h > 2 * cornerHeight) { + if ((parts & RectPart::NoTopBottom) == RectPart::NoTopBottom) { + p.fillRect(x, y + cornerHeight, w, h - 2 * cornerHeight, bg); + } else { + if (parts & RectPart::Left) { + p.fillRect(x, y + cornerHeight, cornerWidth, h - 2 * cornerHeight, bg); } - if (parts & RectPart::Bottom) { - p.fillRect(x + cornerWidth, y + h - cornerHeight, w - 2 * cornerWidth, cornerHeight, bg); - if (shadow) { - p.fillRect(x + cornerWidth, y + h, w - 2 * cornerWidth, st::msgShadow, *shadow); - } + if ((parts & RectPart::Center) && w > 2 * cornerWidth) { + p.fillRect(x + cornerWidth, y + cornerHeight, w - 2 * cornerWidth, h - 2 * cornerHeight, bg); } - } - if (h > 2 * cornerHeight) { - if ((parts & RectPart::NoTopBottom) == RectPart::NoTopBottom) { - p.fillRect(x, y + cornerHeight, w, h - 2 * cornerHeight, bg); - } else { - if (parts & RectPart::Left) { - p.fillRect(x, y + cornerHeight, cornerWidth, h - 2 * cornerHeight, bg); - } - if ((parts & RectPart::Center) && w > 2 * cornerWidth) { - p.fillRect(x + cornerWidth, y + cornerHeight, w - 2 * cornerWidth, h - 2 * cornerHeight, bg); - } - if (parts & RectPart::Right) { - p.fillRect(x + w - cornerWidth, y + cornerHeight, cornerWidth, h - 2 * cornerHeight, bg); - } + if (parts & RectPart::Right) { + p.fillRect(x + w - cornerWidth, y + cornerHeight, cornerWidth, h - 2 * cornerHeight, bg); } } - if (parts & RectPart::TopLeft) { - p.drawPixmap(x, y, corner.p[0]); - } - if (parts & RectPart::TopRight) { - p.drawPixmap(x + w - cornerWidth, y, corner.p[1]); - } - if (parts & RectPart::BottomLeft) { - p.drawPixmap(x, y + h - cornerHeight, corner.p[2]); - } - if (parts & RectPart::BottomRight) { - p.drawPixmap(x + w - cornerWidth, y + h - cornerHeight, corner.p[3]); - } } - - void roundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, style::color bg, RoundCorners index, const style::color *shadow, RectParts parts) { - roundRect(p, x, y, w, h, bg, ::corners[index], shadow, parts); + if (parts & RectPart::TopLeft) { + p.drawPixmap(x, y, corner.p[0]); + } + if (parts & RectPart::TopRight) { + p.drawPixmap(x + w - cornerWidth, y, corner.p[1]); + } + if (parts & RectPart::BottomLeft) { + p.drawPixmap(x, y + h - cornerHeight, corner.p[2]); + } + if (parts & RectPart::BottomRight) { + p.drawPixmap(x + w - cornerWidth, y + h - cornerHeight, corner.p[3]); } +} - void roundShadow(Painter &p, int32 x, int32 y, int32 w, int32 h, style::color shadow, RoundCorners index, RectParts parts) { - auto &corner = ::corners[index]; - auto cornerWidth = corner.p[0].width() / cIntRetinaFactor(); - auto cornerHeight = corner.p[0].height() / cIntRetinaFactor(); - if (parts & RectPart::Bottom) { - p.fillRect(x + cornerWidth, y + h, w - 2 * cornerWidth, st::msgShadow, shadow); - } - if (parts & RectPart::BottomLeft) { - p.fillRect(x, y + h - cornerHeight, cornerWidth, st::msgShadow, shadow); - p.drawPixmap(x, y + h - cornerHeight + st::msgShadow, corner.p[2]); - } - if (parts & RectPart::BottomRight) { - p.fillRect(x + w - cornerWidth, y + h - cornerHeight, cornerWidth, st::msgShadow, shadow); - p.drawPixmap(x + w - cornerWidth, y + h - cornerHeight + st::msgShadow, corner.p[3]); - } +void roundRect(Painter &p, qint32 x, qint32 y, qint32 w, qint32 h, style::color bg, RoundCorners index, + const style::color *shadow, RectParts parts) { + roundRect(p, x, y, w, h, bg, ::corners[index], shadow, parts); +} + +void roundShadow(Painter &p, qint32 x, qint32 y, qint32 w, qint32 h, style::color shadow, RoundCorners index, + RectParts parts) { + auto &corner = ::corners[index]; + auto cornerWidth = corner.p[0].width() / cIntRetinaFactor(); + auto cornerHeight = corner.p[0].height() / cIntRetinaFactor(); + if (parts & RectPart::Bottom) { + p.fillRect(x + cornerWidth, y + h, w - 2 * cornerWidth, st::msgShadow, shadow); + } + if (parts & RectPart::BottomLeft) { + p.fillRect(x, y + h - cornerHeight, cornerWidth, st::msgShadow, shadow); + p.drawPixmap(x, y + h - cornerHeight + st::msgShadow, corner.p[2]); } + if (parts & RectPart::BottomRight) { + p.fillRect(x + w - cornerWidth, y + h - cornerHeight, cornerWidth, st::msgShadow, shadow); + p.drawPixmap(x + w - cornerWidth, y + h - cornerHeight + st::msgShadow, corner.p[3]); + } +} - void roundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, style::color bg, ImageRoundRadius radius, RectParts parts) { - auto colorKey = ((uint32(bg->c.alpha()) & 0xFF) << 24) | ((uint32(bg->c.red()) & 0xFF) << 16) | ((uint32(bg->c.green()) & 0xFF) << 8) | ((uint32(bg->c.blue()) & 0xFF) << 24); - auto i = cornersMap.find(colorKey); - if (i == cornersMap.cend()) { - QImage images[4]; - switch (radius) { - case ImageRoundRadius::Small: prepareCorners(SmallMaskCorners, st::buttonRadius, bg, nullptr, images); break; - case ImageRoundRadius::Large: prepareCorners(LargeMaskCorners, msgRadius(), bg, nullptr, images); break; - default: p.fillRect(x, y, w, h, bg); return; - } +void roundRect(Painter &p, qint32 x, qint32 y, qint32 w, qint32 h, style::color bg, ImageRoundRadius radius, + RectParts parts) { + auto colorKey = ((quint32(bg->c.alpha()) & 0xFF) << 24) | ((quint32(bg->c.red()) & 0xFF) << 16) | + ((quint32(bg->c.green()) & 0xFF) << 8) | ((quint32(bg->c.blue()) & 0xFF) << 24); + auto i = cornersMap.find(colorKey); + if (i == cornersMap.cend()) { + QImage images[4]; + switch (radius) { + case ImageRoundRadius::Small: prepareCorners(SmallMaskCorners, st::buttonRadius, bg, nullptr, images); break; + case ImageRoundRadius::Large: prepareCorners(LargeMaskCorners, msgRadius(), bg, nullptr, images); break; + default: p.fillRect(x, y, w, h, bg); return; + } - CornersPixmaps pixmaps; - for (int j = 0; j < 4; ++j) { - pixmaps.p[j] = pixmapFromImageInPlace(std::move(images[j])); - pixmaps.p[j].setDevicePixelRatio(cRetinaFactor()); - } - i = cornersMap.insert(colorKey, pixmaps); + CornersPixmaps pixmaps; + for (int j = 0; j < 4; ++j) { + pixmaps.p[j] = pixmapFromImageInPlace(std::move(images[j])); + pixmaps.p[j].setDevicePixelRatio(cRetinaFactor()); } - roundRect(p, x, y, w, h, bg, i.value(), nullptr, parts); + i = cornersMap.insert(colorKey, pixmaps); } + roundRect(p, x, y, w, h, bg, i.value(), nullptr, parts); +} - WallPapers gServerBackgrounds; +WallPapers gServerBackgrounds; -} +} // namespace App diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index 531abac00..7eac40c61 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -1,302 +1,325 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once +#include +#include + #include "core/basic_types.h" #include "history/history.h" #include "history/history_item.h" #include "layout.h" +#include "media/media_clip_reader.h" +#include "ui/animation.h" class Messenger; class MainWindow; class MainWidget; -using HistoryItemsMap = OrderedSet; -using PhotoItems = QHash; -using DocumentItems = QHash; -using WebPageItems = QHash; -using GameItems = QHash; -using SharedContactItems = QHash; -using GifItems = QHash; +using HistoryItemsMap = std::set; +using PhotoItems = QHash; +using DocumentItems = QHash; +using WebPageItems = QHash; +using GameItems = QHash; +using SharedContactItems = QHash; +using GifItems = QHash; -using PhotosData = QHash; -using DocumentsData = QHash; +using PhotosData = QHash; +using DocumentsData = QHash; class LocationCoords; struct LocationData; namespace App { - MainWindow *wnd(); - MainWidget *main(); - bool passcoded(); - - void logOut(); - - QString formatPhone(QString phone); - - TimeId onlineForSort(UserData *user, TimeId now); - int32 onlineWillChangeIn(UserData *user, TimeId now); - int32 onlineWillChangeIn(TimeId online, TimeId now); - QString onlineText(UserData *user, TimeId now, bool precise = false); - QString onlineText(TimeId online, TimeId now, bool precise = false); - bool onlineColorUse(UserData *user, TimeId now); - bool onlineColorUse(TimeId online, TimeId now); - - UserData *feedUser(const MTPUser &user); - UserData *feedUsers(const MTPVector &users); // returns last user - PeerData *feedChat(const MTPChat &chat); - PeerData *feedChats(const MTPVector &chats); // returns last chat - - void feedParticipants(const MTPChatParticipants &p, bool requestBotInfos); - void feedParticipantAdd(const MTPDupdateChatParticipantAdd &d); - void feedParticipantDelete(const MTPDupdateChatParticipantDelete &d); - void feedChatAdmins(const MTPDupdateChatAdmins &d); - void feedParticipantAdmin(const MTPDupdateChatParticipantAdmin &d); - bool checkEntitiesAndViewsUpdate(const MTPDmessage &m); // returns true if item found and it is not detached - void updateEditedMessage(const MTPMessage &m); - void addSavedGif(DocumentData *doc); - void checkSavedGif(HistoryItem *item); - void feedMsgs(const QVector &msgs, NewMessageType type); - void feedMsgs(const MTPVector &msgs, NewMessageType type); - void feedInboxRead(const PeerId &peer, MsgId upTo); - void feedOutboxRead(const PeerId &peer, MsgId upTo, TimeId when); - void feedWereDeleted(ChannelId channelId, const QVector &msgsIds); - void feedUserLink(MTPint userId, const MTPContactLink &myLink, const MTPContactLink &foreignLink); - - ImagePtr image(const MTPPhotoSize &size); - StorageImageLocation imageLocation(int32 w, int32 h, const MTPFileLocation &loc); - StorageImageLocation imageLocation(const MTPPhotoSize &size); - - PhotoData *feedPhoto(const MTPPhoto &photo, const PreparedPhotoThumbs &thumbs); - PhotoData *feedPhoto(const MTPPhoto &photo, PhotoData *convert = nullptr); - PhotoData *feedPhoto(const MTPDphoto &photo, PhotoData *convert = nullptr); - DocumentData *feedDocument(const MTPdocument &document, const QPixmap &thumb); - DocumentData *feedDocument(const MTPdocument &document, DocumentData *convert = nullptr); - DocumentData *feedDocument(const MTPDdocument &document, DocumentData *convert = nullptr); - WebPageData *feedWebPage(const MTPDwebPage &webpage, WebPageData *convert = nullptr); - WebPageData *feedWebPage(const MTPDwebPagePending &webpage, WebPageData *convert = nullptr); - WebPageData *feedWebPage(const MTPWebPage &webpage); - WebPageData *feedWebPage(WebPageId webPageId, const QString &siteName, const TextWithEntities &content); - GameData *feedGame(const MTPDgame &game, GameData *convert = nullptr); - - PeerData *peer(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded); - inline UserData *user(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) { - return asUser(peer(id, restriction)); - } - inline ChatData *chat(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) { - return asChat(peer(id, restriction)); - } - inline ChannelData *channel(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) { - return asChannel(peer(id, restriction)); - } - inline UserData *user(UserId userId, PeerData::LoadedStatus restriction = PeerData::NotLoaded) { - return asUser(peer(peerFromUser(userId), restriction)); - } - inline ChatData *chat(ChatId chatId, PeerData::LoadedStatus restriction = PeerData::NotLoaded) { - return asChat(peer(peerFromChat(chatId), restriction)); - } - inline ChannelData *channel(ChannelId channelId, PeerData::LoadedStatus restriction = PeerData::NotLoaded) { - return asChannel(peer(peerFromChannel(channelId), restriction)); - } - inline PeerData *peerLoaded(const PeerId &id) { - return peer(id, PeerData::FullLoaded); - } - inline UserData *userLoaded(const PeerId &id) { - return user(id, PeerData::FullLoaded); - } - inline ChatData *chatLoaded(const PeerId &id) { - return chat(id, PeerData::FullLoaded); - } - inline ChannelData *channelLoaded(const PeerId &id) { - return channel(id, PeerData::FullLoaded); - } - inline UserData *userLoaded(UserId userId) { - return user(userId, PeerData::FullLoaded); - } - inline ChatData *chatLoaded(ChatId chatId) { - return chat(chatId, PeerData::FullLoaded); - } - inline ChannelData *channelLoaded(ChannelId channelId) { - return channel(channelId, PeerData::FullLoaded); - } - void enumerateUsers(base::lambda action); - - UserData *self(); - PeerData *peerByName(const QString &username); - QString peerName(const PeerData *peer, bool forDialogs = false); - PhotoData *photo(const PhotoId &photo); - PhotoData *photoSet(const PhotoId &photo, PhotoData *convert, const uint64 &access, int32 date, const ImagePtr &thumb, const ImagePtr &medium, const ImagePtr &full); - DocumentData *document(const DocumentId &document); - DocumentData *documentSet(const DocumentId &document, DocumentData *convert, const uint64 &access, int32 version, int32 date, const QVector &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size, const StorageImageLocation &thumbLocation); - WebPageData *webPage(const WebPageId &webPage); - WebPageData *webPageSet(const WebPageId &webPage, WebPageData *convert, const QString &type, const QString &url, const QString &displayUrl, const QString &siteName, const QString &title, const TextWithEntities &description, PhotoData *photo, DocumentData *doc, int32 duration, const QString &author, int32 pendingTill); - GameData *game(const GameId &game); - GameData *gameSet(const GameId &game, GameData *convert, const uint64 &accessHash, const QString &shortName, const QString &title, const QString &description, PhotoData *photo, DocumentData *doc); - LocationData *location(const LocationCoords &coords); - void forgetMedia(); - - MTPPhoto photoFromUserPhoto(MTPint userId, MTPint date, const MTPUserProfilePhoto &photo); - - Histories &histories(); - not_null history(const PeerId &peer); - History *historyFromDialog(const PeerId &peer, int32 unreadCnt, int32 maxInboxRead, int32 maxOutboxRead); - History *historyLoaded(const PeerId &peer); - HistoryItem *histItemById(ChannelId channelId, MsgId itemId); - inline not_null history(const PeerData *peer) { - Assert(peer != nullptr); - return history(peer->id); - } - inline History *historyLoaded(const PeerData *peer) { - return peer ? historyLoaded(peer->id) : nullptr; - } - inline HistoryItem *histItemById(const ChannelData *channel, MsgId itemId) { - return histItemById(channel ? peerToChannel(channel->id) : 0, itemId); - } - inline HistoryItem *histItemById(const FullMsgId &msgId) { - return histItemById(msgId.channel, msgId.msg); - } - void historyRegItem(HistoryItem *item); - void historyItemDetached(HistoryItem *item); - void historyUnregItem(HistoryItem *item); - void historyUpdateDependent(HistoryItem *item); - void historyClearMsgs(); - void historyClearItems(); - void historyRegDependency(HistoryItem *dependent, HistoryItem *dependency); - void historyUnregDependency(HistoryItem *dependent, HistoryItem *dependency); - - void historyRegRandom(uint64 randomId, const FullMsgId &itemId); - void historyUnregRandom(uint64 randomId); - FullMsgId histItemByRandom(uint64 randomId); - void historyRegSentData(uint64 randomId, const PeerId &peerId, const QString &text); - void historyUnregSentData(uint64 randomId); - void histSentDataByItem(uint64 randomId, PeerId &peerId, QString &text); - - void hoveredItem(HistoryItem *item); - HistoryItem *hoveredItem(); - void pressedItem(HistoryItem *item); - HistoryItem *pressedItem(); - void hoveredLinkItem(HistoryItem *item); - HistoryItem *hoveredLinkItem(); - void pressedLinkItem(HistoryItem *item); - HistoryItem *pressedLinkItem(); - void contextItem(HistoryItem *item); - HistoryItem *contextItem(); - void mousedItem(HistoryItem *item); - HistoryItem *mousedItem(); - void clearMousedItems(); - - const style::font &monofont(); - const QPixmap &emoji(); - const QPixmap &emojiLarge(); - const QPixmap &emojiSingle(EmojiPtr emoji, int32 fontHeight); - - void clearHistories(); - - void initMedia(); - void deinitMedia(); - - void checkImageCacheSize(); - - bool isValidPhone(QString phone); - - enum LaunchState { - Launched = 0, - QuitRequested = 1, - QuitProcessed = 2, - }; - void quit(); - bool quitting(); - LaunchState launchState(); - void setLaunchState(LaunchState state); - void restart(); - - constexpr auto kFileSizeLimit = 1500 * 1024 * 1024; // Load files up to 1500mb - constexpr auto kImageSizeLimit = 64 * 1024 * 1024; // Open images up to 64mb jpg/png/gif - QImage readImage(QByteArray data, QByteArray *format = nullptr, bool opaque = true, bool *animated = nullptr); - QImage readImage(const QString &file, QByteArray *format = nullptr, bool opaque = true, bool *animated = nullptr, QByteArray *content = 0); - QPixmap pixmapFromImageInPlace(QImage &&image); - - void regPhotoItem(PhotoData *data, HistoryItem *item); - void unregPhotoItem(PhotoData *data, HistoryItem *item); - const PhotoItems &photoItems(); - const PhotosData &photosData(); - - void regDocumentItem(DocumentData *data, HistoryItem *item); - void unregDocumentItem(DocumentData *data, HistoryItem *item); - const DocumentItems &documentItems(); - const DocumentsData &documentsData(); - - void regWebPageItem(WebPageData *data, HistoryItem *item); - void unregWebPageItem(WebPageData *data, HistoryItem *item); - const WebPageItems &webPageItems(); - - void regGameItem(GameData *data, HistoryItem *item); - void unregGameItem(GameData *data, HistoryItem *item); - const GameItems &gameItems(); - - void regSharedContactItem(int32 userId, HistoryItem *item); - void unregSharedContactItem(int32 userId, HistoryItem *item); - const SharedContactItems &sharedContactItems(); - QString phoneFromSharedContact(int32 userId); - - void regGifItem(Media::Clip::Reader *reader, HistoryItem *item); - void unregGifItem(Media::Clip::Reader *reader); - void stopRoundVideoPlayback(); - void stopGifItems(); - - void regMuted(PeerData *peer, int32 changeIn); - void unregMuted(PeerData *peer); - void updateMuted(); - - void setProxySettings(QNetworkAccessManager &manager); +MainWindow *wnd(); +MainWidget *main(); +bool passcoded(); + +void logOut(); + +QString formatPhone(QString phone); + +TimeId onlineForSort(UserData *user, TimeId now); +qint32 onlineWillChangeIn(UserData *user, TimeId now); +qint32 onlineWillChangeIn(TimeId online, TimeId now); +QString onlineText(UserData *user, TimeId now, bool precise = false); +QString onlineText(TimeId online, TimeId now, bool precise = false); +bool onlineColorUse(UserData *user, TimeId now); +bool onlineColorUse(TimeId online, TimeId now); + +UserData *feedUser(const MTPUser &user); +UserData *feedUsers(const MTPVector &users); // returns last user +PeerData *feedChat(const MTPChat &chat); +PeerData *feedChats(const MTPVector &chats); // returns last chat + +void feedParticipants(const MTPChatParticipants &p, bool requestBotInfos); +void feedParticipantAdd(const MTPDupdateChatParticipantAdd &d); +void feedParticipantDelete(const MTPDupdateChatParticipantDelete &d); +void feedChatAdmins(const MTPDupdateChatAdmins &d); +void feedParticipantAdmin(const MTPDupdateChatParticipantAdmin &d); +bool checkEntitiesAndViewsUpdate(const MTPDmessage &m); // returns true if item found and it is not detached +void updateEditedMessage(const MTPMessage &m); +void addSavedGif(DocumentData *doc); +void checkSavedGif(HistoryItem *item); +void feedMsgs(const QVector &msgs, NewMessageType type); +void feedMsgs(const MTPVector &msgs, NewMessageType type); +void feedInboxRead(const PeerId &peer, MsgId upTo); +void feedOutboxRead(const PeerId &peer, MsgId upTo, TimeId when); +void feedWereDeleted(ChannelId channelId, const QVector &msgsIds); +void feedUserLink(MTPint userId, const MTPContactLink &myLink, const MTPContactLink &foreignLink); + +ImagePtr image(const MTPPhotoSize &size); +StorageImageLocation imageLocation(qint32 w, qint32 h, const MTPFileLocation &loc); +StorageImageLocation imageLocation(const MTPPhotoSize &size); + +PhotoData *feedPhoto(const MTPPhoto &photo, const PreparedPhotoThumbs &thumbs); +PhotoData *feedPhoto(const MTPPhoto &photo, PhotoData *convert = nullptr); +PhotoData *feedPhoto(const MTPDphoto &photo, PhotoData *convert = nullptr); +DocumentData *feedDocument(const MTPdocument &document, const QPixmap &thumb); +DocumentData *feedDocument(const MTPdocument &document, DocumentData *convert = nullptr); +DocumentData *feedDocument(const MTPDdocument &document, DocumentData *convert = nullptr); +WebPageData *feedWebPage(const MTPDwebPage &webpage, WebPageData *convert = nullptr); +WebPageData *feedWebPage(const MTPDwebPagePending &webpage, WebPageData *convert = nullptr); +WebPageData *feedWebPage(const MTPWebPage &webpage); +WebPageData *feedWebPage(WebPageId webPageId, const QString &siteName, const TextWithEntities &content); +GameData *feedGame(const MTPDgame &game, GameData *convert = nullptr); + +PeerData *peer(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded); +inline UserData *user(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) { + return asUser(peer(id, restriction)); +} +inline ChatData *chat(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) { + return asChat(peer(id, restriction)); +} +inline ChannelData *channel(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) { + return asChannel(peer(id, restriction)); +} +inline UserData *user(UserId userId, PeerData::LoadedStatus restriction = PeerData::NotLoaded) { + return asUser(peer(peerFromUser(userId), restriction)); +} +inline ChatData *chat(ChatId chatId, PeerData::LoadedStatus restriction = PeerData::NotLoaded) { + return asChat(peer(peerFromChat(chatId), restriction)); +} +inline ChannelData *channel(ChannelId channelId, PeerData::LoadedStatus restriction = PeerData::NotLoaded) { + return asChannel(peer(peerFromChannel(channelId), restriction)); +} +inline PeerData *peerLoaded(const PeerId &id) { + return peer(id, PeerData::FullLoaded); +} +inline UserData *userLoaded(const PeerId &id) { + return user(id, PeerData::FullLoaded); +} +inline ChatData *chatLoaded(const PeerId &id) { + return chat(id, PeerData::FullLoaded); +} +inline ChannelData *channelLoaded(const PeerId &id) { + return channel(id, PeerData::FullLoaded); +} +inline UserData *userLoaded(UserId userId) { + return user(userId, PeerData::FullLoaded); +} +inline ChatData *chatLoaded(ChatId chatId) { + return chat(chatId, PeerData::FullLoaded); +} +inline ChannelData *channelLoaded(ChannelId channelId) { + return channel(channelId, PeerData::FullLoaded); +} +void enumerateUsers(Fn action); + +UserData *self(); +PeerData *peerByName(const QString &username); +QString peerName(const PeerData *peer, bool forDialogs = false); +PhotoData *photo(const PhotoId &photo); +PhotoData *photoSet(const PhotoId &photo, PhotoData *convert, const quint64 &access, qint32 date, const ImagePtr &thumb, + const ImagePtr &medium, const ImagePtr &full); +DocumentData *document(const DocumentId &document); +DocumentData *documentSet(const DocumentId &document, DocumentData *convert, const quint64 &access, qint32 version, + qint32 date, const QVector &attributes, const QString &mime, + const ImagePtr &thumb, qint32 dc, qint32 size, const StorageImageLocation &thumbLocation); +WebPageData *webPage(const WebPageId &webPage); +WebPageData *webPageSet(const WebPageId &webPage, WebPageData *convert, const QString &type, const QString &url, + const QString &displayUrl, const QString &siteName, const QString &title, + const TextWithEntities &description, PhotoData *photo, DocumentData *doc, qint32 duration, + const QString &author, qint32 pendingTill); +GameData *game(const GameId &game); +GameData *gameSet(const GameId &game, GameData *convert, const quint64 &accessHash, const QString &shortName, + const QString &title, const QString &description, PhotoData *photo, DocumentData *doc); +LocationData *location(const LocationCoords &coords); +void forgetMedia(); + +MTPPhoto photoFromUserPhoto(MTPint userId, MTPint date, const MTPUserProfilePhoto &photo); + +Histories &histories(); +not_null history(const PeerId &peer); +History *historyFromDialog(const PeerId &peer, qint32 unreadCnt, qint32 maxInboxRead, qint32 maxOutboxRead); +History *historyLoaded(const PeerId &peer); +HistoryItem *histItemById(ChannelId channelId, MsgId itemId); +inline not_null history(const PeerData *peer) { + Assert(peer != nullptr); + return history(peer->id); +} +inline History *historyLoaded(const PeerData *peer) { + return peer ? historyLoaded(peer->id) : nullptr; +} +inline HistoryItem *histItemById(const ChannelData *channel, MsgId itemId) { + return histItemById(channel ? peerToChannel(channel->id) : 0, itemId); +} +inline HistoryItem *histItemById(const FullMsgId &msgId) { + return histItemById(msgId.channel, msgId.msg); +} +void historyRegItem(HistoryItem *item); +void historyItemDetached(HistoryItem *item); +void historyUnregItem(HistoryItem *item); +void historyUpdateDependent(HistoryItem *item); +void historyClearMsgs(); +void historyClearItems(); +void historyRegDependency(HistoryItem *dependent, HistoryItem *dependency); +void historyUnregDependency(HistoryItem *dependent, HistoryItem *dependency); + +void historyRegRandom(quint64 randomId, const FullMsgId &itemId); +void historyUnregRandom(quint64 randomId); +FullMsgId histItemByRandom(quint64 randomId); +void historyRegSentData(quint64 randomId, const PeerId &peerId, const QString &text); +void historyUnregSentData(quint64 randomId); +void histSentDataByItem(quint64 randomId, PeerId &peerId, QString &text); + +void hoveredItem(HistoryItem *item); +HistoryItem *hoveredItem(); +void pressedItem(HistoryItem *item); +HistoryItem *pressedItem(); +void hoveredLinkItem(HistoryItem *item); +HistoryItem *hoveredLinkItem(); +void pressedLinkItem(HistoryItem *item); +HistoryItem *pressedLinkItem(); +void contextItem(HistoryItem *item); +HistoryItem *contextItem(); +void mousedItem(HistoryItem *item); +HistoryItem *mousedItem(); +void clearMousedItems(); + +const style::font &monofont(); +const QPixmap &emoji(); +const QPixmap &emojiLarge(); +const QPixmap &emojiSingle(EmojiPtr emoji, qint32 fontHeight); + +void clearHistories(); + +void initMedia(); +void deinitMedia(); + +void checkImageCacheSize(); + +bool isValidPhone(QString phone); + +enum LaunchState { + Launched = 0, + QuitRequested = 1, + QuitProcessed = 2, +}; +void quit(); +bool quitting(); +LaunchState launchState(); +void setLaunchState(LaunchState state); +void restart(); + +constexpr auto kFileSizeLimit = 1500 * 1024 * 1024; // Load files up to 1500mb +constexpr auto kImageSizeLimit = 64 * 1024 * 1024; // Open images up to 64mb jpg/png/gif +QImage readImage(QByteArray data, QByteArray *format = nullptr, bool opaque = true, bool *animated = nullptr); +QImage readImage(const QString &file, QByteArray *format = nullptr, bool opaque = true, bool *animated = nullptr, + QByteArray *content = 0); +QPixmap pixmapFromImageInPlace(QImage &&image); + +void regPhotoItem(PhotoData *data, HistoryItem *item); +void unregPhotoItem(PhotoData *data, HistoryItem *item); +const PhotoItems &photoItems(); +const PhotosData &photosData(); + +void regDocumentItem(DocumentData *data, HistoryItem *item); +void unregDocumentItem(DocumentData *data, HistoryItem *item); +const DocumentItems &documentItems(); +const DocumentsData &documentsData(); + +void regWebPageItem(WebPageData *data, HistoryItem *item); +void unregWebPageItem(WebPageData *data, HistoryItem *item); +const WebPageItems &webPageItems(); + +void regGameItem(GameData *data, HistoryItem *item); +void unregGameItem(GameData *data, HistoryItem *item); +const GameItems &gameItems(); + +void regSharedContactItem(qint32 userId, HistoryItem *item); +void unregSharedContactItem(qint32 userId, HistoryItem *item); +const SharedContactItems &sharedContactItems(); +QString phoneFromSharedContact(qint32 userId); + +void regGifItem(Media::Clip::Reader *reader, HistoryItem *item); +void unregGifItem(Media::Clip::Reader *reader); +void stopRoundVideoPlayback(); +void stopGifItems(); + +void regMuted(PeerData *peer, qint32 changeIn); +void unregMuted(PeerData *peer); +void updateMuted(); + +void setProxySettings(QNetworkAccessManager &manager); #ifndef TDESKTOP_DISABLE_NETWORK_PROXY - QNetworkProxy getHttpProxySettings(); +QNetworkProxy getHttpProxySettings(); #endif // !TDESKTOP_DISABLE_NETWORK_PROXY - void setProxySettings(QTcpSocket &socket); - - void complexOverlayRect(Painter &p, QRect rect, ImageRoundRadius radius, ImageRoundCorners corners); - void complexLocationRect(Painter &p, QRect rect, ImageRoundRadius radius, ImageRoundCorners corners); - - QImage *cornersMask(ImageRoundRadius radius); - void roundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, style::color bg, RoundCorners index, const style::color *shadow = nullptr, RectParts parts = RectPart::Full); - inline void roundRect(Painter &p, const QRect &rect, style::color bg, RoundCorners index, const style::color *shadow = nullptr, RectParts parts = RectPart::Full) { - return roundRect(p, rect.x(), rect.y(), rect.width(), rect.height(), bg, index, shadow, parts); - } - void roundShadow(Painter &p, int32 x, int32 y, int32 w, int32 h, style::color shadow, RoundCorners index, RectParts parts = RectPart::Full); - inline void roundShadow(Painter &p, const QRect &rect, style::color shadow, RoundCorners index, RectParts parts = RectPart::Full) { - return roundShadow(p, rect.x(), rect.y(), rect.width(), rect.height(), shadow, index, parts); - } - void roundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, style::color bg, ImageRoundRadius radius, RectParts parts = RectPart::Full); - inline void roundRect(Painter &p, const QRect &rect, style::color bg, ImageRoundRadius radius, RectParts parts = RectPart::Full) { - return roundRect(p, rect.x(), rect.y(), rect.width(), rect.height(), bg, radius, parts); - } - - struct WallPaper { - WallPaper(int32 id, ImagePtr thumb, ImagePtr full) : id(id), thumb(thumb), full(full) { - } - int32 id; - ImagePtr thumb; - ImagePtr full; - }; - typedef QList WallPapers; - DeclareSetting(WallPapers, ServerBackgrounds); - +void setProxySettings(QTcpSocket &socket); + +void complexOverlayRect(Painter &p, QRect rect, ImageRoundRadius radius, ImageRoundCorners corners); +void complexLocationRect(Painter &p, QRect rect, ImageRoundRadius radius, ImageRoundCorners corners); + +QImage *cornersMask(ImageRoundRadius radius); +void roundRect(Painter &p, qint32 x, qint32 y, qint32 w, qint32 h, style::color bg, RoundCorners index, + const style::color *shadow = nullptr, RectParts parts = RectPart::Full); +inline void roundRect(Painter &p, const QRect &rect, style::color bg, RoundCorners index, + const style::color *shadow = nullptr, RectParts parts = RectPart::Full) { + return roundRect(p, rect.x(), rect.y(), rect.width(), rect.height(), bg, index, shadow, parts); +} +void roundShadow(Painter &p, qint32 x, qint32 y, qint32 w, qint32 h, style::color shadow, RoundCorners index, + RectParts parts = RectPart::Full); +inline void roundShadow(Painter &p, const QRect &rect, style::color shadow, RoundCorners index, + RectParts parts = RectPart::Full) { + return roundShadow(p, rect.x(), rect.y(), rect.width(), rect.height(), shadow, index, parts); +} +void roundRect(Painter &p, qint32 x, qint32 y, qint32 w, qint32 h, style::color bg, ImageRoundRadius radius, + RectParts parts = RectPart::Full); +inline void roundRect(Painter &p, const QRect &rect, style::color bg, ImageRoundRadius radius, + RectParts parts = RectPart::Full) { + return roundRect(p, rect.x(), rect.y(), rect.width(), rect.height(), bg, radius, parts); +} + +struct WallPaper { + WallPaper(qint32 id, ImagePtr thumb, ImagePtr full) + : id(id) + , thumb(thumb) + , full(full) {} + qint32 id; + ImagePtr thumb; + ImagePtr full; }; +typedef QList WallPapers; +DeclareSetting(WallPapers, ServerBackgrounds); + +}; // namespace App diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp index 2e27d5063..8f3346b88 100644 --- a/Telegram/SourceFiles/application.cpp +++ b/Telegram/SourceFiles/application.cpp @@ -1,36 +1,41 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "application.h" -#include "platform/platform_specific.h" +#include "base/timer.h" #include "mainwidget.h" #include "mainwindow.h" +#include "messenger.h" +#include "platform/platform_specific.h" #include "storage/localstorage.h" -#include "autoupdater.h" #include "window/notifications_manager.h" -#include "messenger.h" -#include "base/timer.h" + +#include +#include namespace { +// @todo are there no other ways to get/set hex? QChar _toHex(ushort v) { v = v & 0x000F; return QChar::fromLatin1((v >= 10) ? ('a' + (v - 10)) : ('0' + v)); @@ -39,6 +44,7 @@ ushort _fromHex(QChar c) { return ((c.unicode() >= uchar('a')) ? (c.unicode() - uchar('a') + 10) : (c.unicode() - uchar('0'))) & 0x000F; } +// @todo urlencode/decode functions might help here?? QString _escapeTo7bit(const QString &str) { QString result; result.reserve(str.size() * 2); @@ -46,7 +52,11 @@ QString _escapeTo7bit(const QString &str) { QChar ch(str.at(i)); ushort uch(ch.unicode()); if (uch < 32 || uch > 127 || uch == ushort(uchar('%'))) { - result.append('%').append(_toHex(uch >> 12)).append(_toHex(uch >> 8)).append(_toHex(uch >> 4)).append(_toHex(uch)); + result.append('%') + .append(_toHex(uch >> 12)) + .append(_toHex(uch >> 8)) + .append(_toHex(uch >> 4)) + .append(_toHex(uch)); } else { result.append(ch); } @@ -60,7 +70,8 @@ QString _escapeFrom7bit(const QString &str) { for (int i = 0, l = str.size(); i != l; ++i) { QChar ch(str.at(i)); if (ch == QChar::fromLatin1('%') && i + 4 < l) { - result.append(QChar(ushort((_fromHex(str.at(i + 1)) << 12) | (_fromHex(str.at(i + 2)) << 8) | (_fromHex(str.at(i + 3)) << 4) | _fromHex(str.at(i + 4))))); + result.append(QChar(ushort((_fromHex(str.at(i + 1)) << 12) | (_fromHex(str.at(i + 2)) << 8) | + (_fromHex(str.at(i + 3)) << 4) | _fromHex(str.at(i + 4))))); i += 4; } else { result.append(ch); @@ -71,9 +82,10 @@ QString _escapeFrom7bit(const QString &str) { } // namespace -Application::Application(int &argc, char **argv) : QApplication(argc, argv) { +Application::Application(int &argc, char **argv) + : QApplication(argc, argv) { QByteArray d(QFile::encodeName(QDir(cWorkingDir()).absolutePath())); - char h[33] = { 0 }; + char h[33] = {0}; hashMd5Hex(d.constData(), d.size(), h); #ifndef OS_MAC_STORE _localServerName = psServerPrefix() + h + '-' + cGUIDStr(); @@ -84,7 +96,8 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) { connect(&_localSocket, SIGNAL(connected()), this, SLOT(socketConnected())); connect(&_localSocket, SIGNAL(disconnected()), this, SLOT(socketDisconnected())); - connect(&_localSocket, SIGNAL(error(QLocalSocket::LocalSocketError)), this, SLOT(socketError(QLocalSocket::LocalSocketError))); + connect(&_localSocket, SIGNAL(error(QLocalSocket::LocalSocketError)), this, + SLOT(socketError(QLocalSocket::LocalSocketError))); connect(&_localSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(socketWritten(qint64))); connect(&_localSocket, SIGNAL(readyRead()), this, SLOT(socketReading())); connect(&_localServer, SIGNAL(newConnection()), this, SLOT(newInstanceConnected())); @@ -92,18 +105,11 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) { QTimer::singleShot(0, this, SLOT(startApplication())); connect(this, SIGNAL(aboutToQuit()), this, SLOT(closeApplication())); -#ifndef TDESKTOP_DISABLE_AUTOUPDATE - _updateCheckTimer.create(this); - connect(_updateCheckTimer, SIGNAL(timeout()), this, SLOT(updateCheck())); - connect(this, SIGNAL(updateFailed()), this, SLOT(onUpdateFailed())); - connect(this, SIGNAL(updateReady()), this, SLOT(onUpdateReady())); -#endif // !TDESKTOP_DISABLE_AUTOUPDATE - if (cManyInstance()) { LOG(("Many instance allowed, starting...")); singleInstanceChecked(); } else { - LOG(("Connecting local socket to %1...").arg(_localServerName)); + LOG(("Connecting local socket to %1...").arg(_localServerName)); _localSocket.connectToServer(_localServerName); } } @@ -135,7 +141,7 @@ void Application::socketConnected() { _localSocket.write(commands.toLatin1()); } -void Application::socketWritten(qint64/* bytes*/) { +void Application::socketWritten(qint64 /* bytes*/) { if (_localSocket.state() != QLocalSocket::ConnectedState) { LOG(("Socket is not connected %1").arg(_localSocket.state())); return; @@ -153,7 +159,7 @@ void Application::socketReading() { } _localSocketReadData.append(_localSocket.readAll()); if (QRegularExpression("RES:(\\d+);").match(_localSocketReadData).hasMatch()) { - uint64 pid = _localSocketReadData.mid(4, _localSocketReadData.length() - 5).toULongLong(); + quint64 pid = _localSocketReadData.mid(4, _localSocketReadData.length() - 5).toULongLong(); psActivateProcess(pid); LOG(("Show command response received, pid = %1, activating and quitting...").arg(pid)); return App::quit(); @@ -180,19 +186,13 @@ void Application::socketError(QLocalSocket::LocalSocketError e) { psCheckLocalSocket(_localServerName); if (!_localServer.listen(_localServerName)) { - LOG(("Failed to start listening to %1 server, error %2").arg(_localServerName).arg(int(_localServer.serverError()))); + LOG(("Failed to start listening to %1 server, error %2") + .arg(_localServerName) + .arg(int(_localServer.serverError()))); return App::quit(); } #endif // !Q_OS_WINRT -#ifndef TDESKTOP_DISABLE_AUTOUPDATE - if (!cNoStartUpdate() && checkReadyUpdate()) { - cSetRestartingUpdate(true); - DEBUG_LOG(("Application Info: installing update instead of starting app...")); - return App::quit(); - } -#endif // !TDESKTOP_DISABLE_AUTOUPDATE - singleInstanceChecked(); } @@ -234,7 +234,8 @@ void Application::socketDisconnected() { void Application::newInstanceConnected() { DEBUG_LOG(("Application Info: new local socket connected")); - for (QLocalSocket *client = _localServer.nextPendingConnection(); client; client = _localServer.nextPendingConnection()) { + for (QLocalSocket *client = _localServer.nextPendingConnection(); client; + client = _localServer.nextPendingConnection()) { _localClients.push_back(LocalClient(client, QByteArray())); connect(client, SIGNAL(readyRead()), this, SLOT(readClients())); connect(client, SIGNAL(disconnected()), this, SLOT(removeClients())); @@ -249,8 +250,9 @@ void Application::readClients() { i->second.append(i->first->readAll()); if (i->second.size()) { QString cmds(QString::fromLatin1(i->second)); - int32 from = 0, l = cmds.length(); - for (int32 to = cmds.indexOf(QChar(';'), from); to >= from; to = (from < l) ? cmds.indexOf(QChar(';'), from) : -1) { + qint32 from = 0, l = cmds.length(); + for (qint32 to = cmds.indexOf(QChar(';'), from); to >= from; + to = (from < l) ? cmds.indexOf(QChar(';'), from) : -1) { QStringRef cmd(&cmds, from, to - from); if (cmd.startsWith(qsl("CMD:"))) { Sandbox::execExternal(cmds.mid(from + 4, to - from - 4)); @@ -265,7 +267,8 @@ void Application::readClients() { startUrl = _escapeFrom7bit(cmds.mid(from + 5, to - from - 5)).mid(0, 8192); } } else { - LOG(("Application Error: unknown command %1 passed in local socket").arg(QString(cmd.constData(), cmd.length()))); + LOG(("Application Error: unknown command %1 passed in local socket") + .arg(QString(cmd.constData(), cmd.length()))); } from = to + 1; } @@ -332,173 +335,10 @@ void Application::closeApplication() { _localClients.clear(); _localSocket.close(); - -#ifndef TDESKTOP_DISABLE_AUTOUPDATE - delete _updateReply; - _updateReply = 0; - if (_updateChecker) _updateChecker->deleteLater(); - _updateChecker = 0; - if (_updateThread) { - _updateThread->quit(); - } - _updateThread = 0; -#endif // !TDESKTOP_DISABLE_AUTOUPDATE -} - -#ifndef TDESKTOP_DISABLE_AUTOUPDATE -void Application::updateCheck() { - startUpdateCheck(false); -} - -void Application::updateGotCurrent() { - if (!_updateReply || _updateThread) return; - - cSetLastUpdateCheck(unixtime()); - QRegularExpressionMatch m = QRegularExpression(qsl("^\\s*(\\d+)\\s*:\\s*([\\x21-\\x7f]+)\\s*$")).match(QString::fromLatin1(_updateReply->readAll())); - if (m.hasMatch()) { - uint64 currentVersion = m.captured(1).toULongLong(); - QString url = m.captured(2); - bool betaVersion = false; - if (url.startsWith(qstr("beta_"))) { - betaVersion = true; - url = url.mid(5) + '_' + countBetaVersionSignature(currentVersion); - } - if ((!betaVersion || cBetaVersion()) && currentVersion > (betaVersion ? cBetaVersion() : uint64(AppVersion))) { - _updateThread = new QThread(); - connect(_updateThread, SIGNAL(finished()), _updateThread, SLOT(deleteLater())); - _updateChecker = new UpdateChecker(_updateThread, url); - _updateThread->start(); - } - } - if (_updateReply) _updateReply->deleteLater(); - _updateReply = 0; - if (!_updateThread) { - QDir updates(cWorkingDir() + "tupdates"); - if (updates.exists()) { - QFileInfoList list = updates.entryInfoList(QDir::Files); - for (QFileInfoList::iterator i = list.begin(), e = list.end(); i != e; ++i) { - if (QRegularExpression("^(tupdate|tmacupd|tmac32upd|tlinuxupd|tlinux32upd)\\d+(_[a-z\\d]+)?$", QRegularExpression::CaseInsensitiveOption).match(i->fileName()).hasMatch()) { - QFile(i->absoluteFilePath()).remove(); - } - } - } - emit updateLatest(); - } - startUpdateCheck(true); - Local::writeSettings(); -} - -void Application::updateFailedCurrent(QNetworkReply::NetworkError e) { - LOG(("App Error: could not get current version (update check): %1").arg(e)); - if (_updateReply) _updateReply->deleteLater(); - _updateReply = 0; - - emit updateFailed(); - startUpdateCheck(true); } -void Application::onUpdateReady() { - if (_updateChecker) { - _updateChecker->deleteLater(); - _updateChecker = nullptr; - } - _updateCheckTimer->stop(); - - cSetLastUpdateCheck(unixtime()); - Local::writeSettings(); -} - -void Application::onUpdateFailed() { - if (_updateChecker) { - _updateChecker->deleteLater(); - _updateChecker = 0; - if (_updateThread) _updateThread->quit(); - _updateThread = 0; - } - - cSetLastUpdateCheck(unixtime()); - Local::writeSettings(); -} - -Application::UpdatingState Application::updatingState() { - if (!_updateThread) return Application::UpdatingNone; - if (!_updateChecker) return Application::UpdatingReady; - return Application::UpdatingDownload; -} - -int32 Application::updatingSize() { - if (!_updateChecker) return 0; - return _updateChecker->size(); -} - -int32 Application::updatingReady() { - if (!_updateChecker) return 0; - return _updateChecker->ready(); -} - -void Application::stopUpdate() { - if (_updateReply) { - _updateReply->abort(); - _updateReply->deleteLater(); - _updateReply = 0; - } - if (_updateChecker) { - _updateChecker->deleteLater(); - _updateChecker = 0; - if (_updateThread) _updateThread->quit(); - _updateThread = 0; - } -} - -void Application::startUpdateCheck(bool forceWait) { - if (!Sandbox::started()) return; - - _updateCheckTimer->stop(); - if (_updateThread || _updateReply || !cAutoUpdate() || cExeName().isEmpty()) return; - - int32 constDelay = cBetaVersion() ? 600 : UpdateDelayConstPart, randDelay = cBetaVersion() ? 300 : UpdateDelayRandPart; - int32 updateInSecs = cLastUpdateCheck() + constDelay + int32(rand() % randDelay) - unixtime(); - bool sendRequest = (updateInSecs <= 0 || updateInSecs > (constDelay + randDelay)); - if (!sendRequest && !forceWait) { - QDir updates(cWorkingDir() + "tupdates"); - if (updates.exists()) { - QFileInfoList list = updates.entryInfoList(QDir::Files); - for (QFileInfoList::iterator i = list.begin(), e = list.end(); i != e; ++i) { - if (QRegularExpression("^(tupdate|tmacupd|tmac32upd|tlinuxupd|tlinux32upd)\\d+(_[a-z\\d]+)?$", QRegularExpression::CaseInsensitiveOption).match(i->fileName()).hasMatch()) { - sendRequest = true; - } - } - } - } - if (cManyInstance() && !cDebug()) return; // only main instance is updating - - if (sendRequest) { - QUrl url(cUpdateURL()); - if (cBetaVersion()) { - url.setQuery(qsl("version=%1&beta=%2").arg(AppVersion).arg(cBetaVersion())); - } else if (cAlphaVersion()) { - url.setQuery(qsl("version=%1&alpha=1").arg(AppVersion)); - } else { - url.setQuery(qsl("version=%1").arg(AppVersion)); - } - QString u = url.toString(); - QNetworkRequest checkVersion(url); - if (_updateReply) _updateReply->deleteLater(); - - App::setProxySettings(_updateManager); - _updateReply = _updateManager.get(checkVersion); - connect(_updateReply, SIGNAL(finished()), this, SLOT(updateGotCurrent())); - connect(_updateReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(updateFailedCurrent(QNetworkReply::NetworkError))); - emit updateChecking(); - } else { - _updateCheckTimer->start((updateInSecs + 5) * 1000); - } -} - -#endif // !TDESKTOP_DISABLE_AUTOUPDATE - inline Application *application() { - return qobject_cast(QApplication::instance()); + return qobject_cast(QApplication::instance()); } namespace Sandbox { @@ -548,73 +388,6 @@ void adjustSingleTimers() { base::Timer::Adjust(); } -#ifndef TDESKTOP_DISABLE_AUTOUPDATE - -void startUpdateCheck() { - if (auto a = application()) { - return a->startUpdateCheck(false); - } -} - -void stopUpdate() { - if (auto a = application()) { - return a->stopUpdate(); - } -} - -Application::UpdatingState updatingState() { - if (auto a = application()) { - return a->updatingState(); - } - return Application::UpdatingNone; -} - -int32 updatingSize() { - if (auto a = application()) { - return a->updatingSize(); - } - return 0; -} - -int32 updatingReady() { - if (auto a = application()) { - return a->updatingReady(); - } - return 0; -} - -void updateChecking() { - if (auto a = application()) { - emit a->updateChecking(); - } -} - -void updateLatest() { - if (auto a = application()) { - emit a->updateLatest(); - } -} - -void updateProgress(qint64 ready, qint64 total) { - if (auto a = application()) { - emit a->updateProgress(ready, total); - } -} - -void updateFailed() { - if (auto a = application()) { - emit a->updateFailed(); - } -} - -void updateReady() { - if (auto a = application()) { - emit a->updateReady(); - } -} - -#endif // !TDESKTOP_DISABLE_AUTOUPDATE - void connect(const char *signal, QObject *object, const char *method) { if (auto a = application()) { a->connect(a, signal, object, method); @@ -624,7 +397,7 @@ void connect(const char *signal, QObject *object, const char *method) { void launch() { Assert(application() != 0); - float64 dpi = Application::primaryScreen()->logicalDotsPerInch(); + double dpi = Application::primaryScreen()->logicalDotsPerInch(); if (dpi <= 108) { // 0-96-108 cSetScreenScale(dbisOne); } else if (dpi <= 132) { // 108-120-132 @@ -639,14 +412,17 @@ void launch() { if (devicePixelRatio > 1.) { if ((cPlatform() != dbipMac && cPlatform() != dbipMacOld) || (devicePixelRatio != 2.)) { LOG(("Found non-trivial Device Pixel Ratio: %1").arg(devicePixelRatio)); - LOG(("Environmental variables: QT_DEVICE_PIXEL_RATIO='%1'").arg(QString::fromLatin1(qgetenv("QT_DEVICE_PIXEL_RATIO")))); + LOG(("Environmental variables: QT_DEVICE_PIXEL_RATIO='%1'") + .arg(QString::fromLatin1(qgetenv("QT_DEVICE_PIXEL_RATIO")))); LOG(("Environmental variables: QT_SCALE_FACTOR='%1'").arg(QString::fromLatin1(qgetenv("QT_SCALE_FACTOR")))); - LOG(("Environmental variables: QT_AUTO_SCREEN_SCALE_FACTOR='%1'").arg(QString::fromLatin1(qgetenv("QT_AUTO_SCREEN_SCALE_FACTOR")))); - LOG(("Environmental variables: QT_SCREEN_SCALE_FACTORS='%1'").arg(QString::fromLatin1(qgetenv("QT_SCREEN_SCALE_FACTORS")))); + LOG(("Environmental variables: QT_AUTO_SCREEN_SCALE_FACTOR='%1'") + .arg(QString::fromLatin1(qgetenv("QT_AUTO_SCREEN_SCALE_FACTOR")))); + LOG(("Environmental variables: QT_SCREEN_SCALE_FACTORS='%1'") + .arg(QString::fromLatin1(qgetenv("QT_SCREEN_SCALE_FACTORS")))); } cSetRetina(true); cSetRetinaFactor(devicePixelRatio); - cSetIntRetinaFactor(int32(cRetinaFactor())); + cSetIntRetinaFactor(qint32(cRetinaFactor())); cSetConfigScale(dbisOne); cSetRealScale(dbisOne); } diff --git a/Telegram/SourceFiles/application.h b/Telegram/SourceFiles/application.h index eec0ffc84..9c5717a41 100644 --- a/Telegram/SourceFiles/application.h +++ b/Telegram/SourceFiles/application.h @@ -1,26 +1,35 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once -class UpdateChecker; +#include + +#include +#include +#include + +class Messenger; + class Application : public QApplication { Q_OBJECT @@ -36,7 +45,7 @@ class Application : public QApplication { signals: void adjustSingleTimers(); -// Single instance application + // Single instance application public slots: void socketConnected(); void socketError(QLocalSocket::LocalSocketError e); @@ -52,7 +61,7 @@ public slots: void closeApplication(); // will be done in aboutToQuit() private: - typedef QPair LocalClient; + typedef QPair LocalClient; typedef QList LocalClients; std::unique_ptr _messengerInstance; @@ -64,47 +73,6 @@ public slots: bool _secondInstance = false; void singleInstanceChecked(); - -#ifndef TDESKTOP_DISABLE_AUTOUPDATE - -// Autoupdating -public: - void startUpdateCheck(bool forceWait); - void stopUpdate(); - - enum UpdatingState { - UpdatingNone, - UpdatingDownload, - UpdatingReady, - }; - UpdatingState updatingState(); - int32 updatingSize(); - int32 updatingReady(); - -signals: - void updateChecking(); - void updateLatest(); - void updateProgress(qint64 ready, qint64 total); - void updateReady(); - void updateFailed(); - -public slots: - void updateCheck(); - - void updateGotCurrent(); - void updateFailedCurrent(QNetworkReply::NetworkError e); - - void onUpdateReady(); - void onUpdateFailed(); - -private: - object_ptr _updateCheckTimer = { nullptr }; - QNetworkReply *_updateReply = nullptr; - QNetworkAccessManager _updateManager; - QThread *_updateThread = nullptr; - UpdateChecker *_updateChecker = nullptr; - -#endif // !TDESKTOP_DISABLE_AUTOUPDATE }; namespace Sandbox { @@ -118,23 +86,6 @@ void execExternal(const QString &cmd); void adjustSingleTimers(); -#ifndef TDESKTOP_DISABLE_AUTOUPDATE - -void startUpdateCheck(); -void stopUpdate(); - -Application::UpdatingState updatingState(); -int32 updatingSize(); -int32 updatingReady(); - -void updateChecking(); -void updateLatest(); -void updateProgress(qint64 ready, qint64 total); -void updateFailed(); -void updateReady(); - -#endif // !TDESKTOP_DISABLE_AUTOUPDATE - void connect(const char *signal, QObject *object, const char *method); void launch(); diff --git a/Telegram/SourceFiles/auth_session.cpp b/Telegram/SourceFiles/auth_session.cpp index 08db86bfd..5b7a45144 100644 --- a/Telegram/SourceFiles/auth_session.cpp +++ b/Telegram/SourceFiles/auth_session.cpp @@ -1,36 +1,40 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "auth_session.h" #include "apiwrap.h" +#include "calls/calls_instance.h" +#include "chat_helpers/tabbed_selector.h" #include "messenger.h" +#include "platform/platform_specific.h" #include "storage/file_download.h" #include "storage/file_upload.h" #include "storage/localstorage.h" #include "storage/serialize_common.h" #include "window/notifications_manager.h" -#include "platform/platform_specific.h" -#include "calls/calls_instance.h" #include "window/section_widget.h" -#include "chat_helpers/tabbed_selector.h" + +#include "app.h" // App::user namespace { @@ -39,10 +43,9 @@ constexpr auto kAutoLockTimeoutLateMs = TimeMs(3000); } // namespace AuthSessionData::Variables::Variables() -: selectorTab(ChatHelpers::SelectorTab::Emoji) -, floatPlayerColumn(Window::Column::Second) -, floatPlayerCorner(RectPart::TopRight) { -} + : selectorTab(ChatHelpers::SelectorTab::Emoji) + , floatPlayerColumn(Window::Column::Second) + , floatPlayerCorner(RectPart::TopRight) {} QByteArray AuthSessionData::serialize() const { auto size = sizeof(qint32) * 8; @@ -88,7 +91,7 @@ void AuthSessionData::constructFromSerialized(const QByteArray &serialized) { qint32 floatPlayerColumn = static_cast(Window::Column::Second); qint32 floatPlayerCorner = static_cast(RectPart::TopRight); QMap soundOverrides; - OrderedSet groupStickersSectionHidden; + std::set groupStickersSectionHidden; stream >> selectorTab; stream >> lastSeenWarningSeen; if (!stream.atEnd()) { @@ -168,17 +171,15 @@ AuthSession &Auth() { } AuthSession::AuthSession(UserId userId) -: _userId(userId) -, _autoLockTimer([this] { checkAutoLock(); }) -, _api(std::make_unique(this)) -, _calls(std::make_unique()) -, _downloader(std::make_unique()) -, _uploader(std::make_unique()) -, _notifications(std::make_unique(this)) { + : _userId(userId) + , _autoLockTimer([this] { checkAutoLock(); }) + , _api(std::make_unique(this)) + , _calls(std::make_unique()) + , _downloader(std::make_unique()) + , _uploader(std::make_unique()) + , _notifications(std::make_unique(this)) { Expects(_userId != 0); - _saveDataTimer.setCallback([this] { - Local::writeUserSettings(); - }); + _saveDataTimer.setCallback([] { Local::writeUserSettings(); }); subscribe(Messenger::Instance().passcodedChanged(), [this] { _shouldLockAt = 0; notifications().updateAll(); @@ -223,7 +224,7 @@ void AuthSession::checkAutoLock() { auto shouldLockInMs = Global::AutoLock() * 1000LL; auto idleForMs = psIdleTime(); auto notPlayingVideoForMs = now - data().lastTimeVideoPlayedAt(); - auto checkTimeMs = qMin(idleForMs, notPlayingVideoForMs); + auto checkTimeMs = std::min(idleForMs, notPlayingVideoForMs); if (checkTimeMs >= shouldLockInMs || (_shouldLockAt > 0 && now > _shouldLockAt + kAutoLockTimeoutLateMs)) { Messenger::Instance().setupPasscode(); } else { diff --git a/Telegram/SourceFiles/auth_session.h b/Telegram/SourceFiles/auth_session.h index 3124a26b3..246c61697 100644 --- a/Telegram/SourceFiles/auth_session.h +++ b/Telegram/SourceFiles/auth_session.h @@ -1,26 +1,29 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "base/timer.h" +#include "data/data_peer.h" namespace Storage { class Downloader; @@ -43,6 +46,8 @@ enum class SelectorTab; } // namespace ChatHelpers class ApiWrap; +class History; +class HistoryItem; class AuthSessionData final { public: @@ -61,18 +66,18 @@ class AuthSessionData final { base::Observable &savedGifsUpdated() { return _savedGifsUpdated; } - base::Observable> &historyCleared() { + base::Observable> &historyCleared() { return _historyCleared; } - base::Observable> &repaintLogEntry() { + base::Observable> &repaintLogEntry() { return _repaintLogEntry; } base::Observable &pendingHistoryResize() { return _pendingHistoryResize; } struct ItemVisibilityQuery { - not_null item; - not_null isVisible; + not_null item; + not_null isVisible; }; base::Observable &queryItemVisibility() { return _queryItemVisibility; @@ -137,10 +142,10 @@ class AuthSessionData final { _variables.groupStickersSectionHidden.insert(peerId); } bool isGroupStickersSectionHidden(PeerId peerId) const { - return _variables.groupStickersSectionHidden.contains(peerId); + return _variables.groupStickersSectionHidden.find(peerId) != _variables.groupStickersSectionHidden.end(); } void removeGroupStickersSectionHidden(PeerId peerId) { - _variables.groupStickersSectionHidden.remove(peerId); + _variables.groupStickersSectionHidden.erase(peerId); } private: @@ -154,21 +159,20 @@ class AuthSessionData final { QMap soundOverrides; Window::Column floatPlayerColumn; RectPart floatPlayerCorner; - OrderedSet groupStickersSectionHidden; + std::set groupStickersSectionHidden; }; - base::Variable _contactsLoaded = { false }; - base::Variable _allChatsLoaded = { false }; + base::Variable _contactsLoaded = {false}; + base::Variable _allChatsLoaded = {false}; base::Observable _moreChatsLoaded; base::Observable _stickersUpdated; base::Observable _savedGifsUpdated; - base::Observable> _historyCleared; - base::Observable> _repaintLogEntry; + base::Observable> _historyCleared; + base::Observable> _repaintLogEntry; base::Observable _pendingHistoryResize; base::Observable _queryItemVisibility; Variables _variables; TimeMs _lastTimeVideoPlayedAt = 0; - }; // One per Messenger. @@ -222,8 +226,8 @@ class AuthSession final : private base::Subscriber { void checkAutoLock(); void checkAutoLockIn(TimeMs time); - base::Observable documentUpdated; - base::Observable> messageIdChanging; + base::Observable documentUpdated; + base::Observable> messageIdChanging; ~AuthSession(); @@ -240,5 +244,4 @@ class AuthSession final : private base::Subscriber { const std::unique_ptr _downloader; const std::unique_ptr _uploader; const std::unique_ptr _notifications; - }; diff --git a/Telegram/SourceFiles/autoupdater.cpp b/Telegram/SourceFiles/autoupdater.cpp deleted file mode 100644 index a6aa4c296..000000000 --- a/Telegram/SourceFiles/autoupdater.cpp +++ /dev/null @@ -1,627 +0,0 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ - -#include "autoupdater.h" - -#include -#include -#include -#include - -#ifdef Q_OS_WIN // use Lzma SDK for win -#include -#else // Q_OS_WIN -#include -#endif // else of Q_OS_WIN - -#include "application.h" -#include "platform/platform_specific.h" - -#ifndef TDESKTOP_DISABLE_AUTOUPDATE - -#ifdef Q_OS_WIN -typedef DWORD VerInt; -typedef WCHAR VerChar; -#else // Q_OS_WIN -typedef int VerInt; -typedef wchar_t VerChar; -#endif // Q_OS_WIN - -UpdateChecker::UpdateChecker(QThread *thread, const QString &url) : reply(0), already(0), full(0) { - updateUrl = url; - moveToThread(thread); - manager.moveToThread(thread); - App::setProxySettings(manager); - - connect(thread, SIGNAL(started()), this, SLOT(start())); - initOutput(); -} - -void UpdateChecker::initOutput() { - QString fileName; - QRegularExpressionMatch m = QRegularExpression(qsl("/([^/\\?]+)(\\?|$)")).match(updateUrl); - if (m.hasMatch()) { - fileName = m.captured(1).replace(QRegularExpression(qsl("[^a-zA-Z0-9_\\-]")), QString()); - } - if (fileName.isEmpty()) { - fileName = qsl("tupdate-%1").arg(rand_value() % 1000000); - } - QString dirStr = cWorkingDir() + qsl("tupdates/"); - fileName = dirStr + fileName; - QFileInfo file(fileName); - - QDir dir(dirStr); - if (dir.exists()) { - QFileInfoList all = dir.entryInfoList(QDir::Files); - for (QFileInfoList::iterator i = all.begin(), e = all.end(); i != e; ++i) { - if (i->absoluteFilePath() != file.absoluteFilePath()) { - QFile::remove(i->absoluteFilePath()); - } - } - } else { - dir.mkdir(dir.absolutePath()); - } - outputFile.setFileName(fileName); - if (file.exists()) { - uint64 fullSize = file.size(); - if (fullSize < INT_MAX) { - int32 goodSize = (int32)fullSize; - if (goodSize % UpdateChunk) { - goodSize = goodSize - (goodSize % UpdateChunk); - if (goodSize) { - if (outputFile.open(QIODevice::ReadOnly)) { - QByteArray goodData = outputFile.readAll().mid(0, goodSize); - outputFile.close(); - if (outputFile.open(QIODevice::WriteOnly)) { - outputFile.write(goodData); - outputFile.close(); - - QMutexLocker lock(&mutex); - already = goodSize; - } - } - } - } else { - QMutexLocker lock(&mutex); - already = goodSize; - } - } - if (!already) { - QFile::remove(fileName); - } - } -} - -void UpdateChecker::start() { - sendRequest(); -} - -void UpdateChecker::sendRequest() { - QNetworkRequest req(updateUrl); - QByteArray rangeHeaderValue = "bytes=" + QByteArray::number(already) + "-"; - req.setRawHeader("Range", rangeHeaderValue); - req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true); - if (reply) reply->deleteLater(); - reply = manager.get(req); - connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(partFinished(qint64,qint64))); - connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(partFailed(QNetworkReply::NetworkError))); - connect(reply, SIGNAL(metaDataChanged()), this, SLOT(partMetaGot())); -} - -void UpdateChecker::partMetaGot() { - typedef QList Pairs; - Pairs pairs = reply->rawHeaderPairs(); - for (Pairs::iterator i = pairs.begin(), e = pairs.end(); i != e; ++i) { - if (QString::fromUtf8(i->first).toLower() == "content-range") { - QRegularExpressionMatch m = QRegularExpression(qsl("/(\\d+)([^\\d]|$)")).match(QString::fromUtf8(i->second)); - if (m.hasMatch()) { - { - QMutexLocker lock(&mutex); - full = m.captured(1).toInt(); - } - - Sandbox::updateProgress(already, full); - } - } - } -} - -int32 UpdateChecker::ready() { - QMutexLocker lock(&mutex); - return already; -} - -int32 UpdateChecker::size() { - QMutexLocker lock(&mutex); - return full; -} - -void UpdateChecker::partFinished(qint64 got, qint64 total) { - if (!reply) return; - - QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); - if (statusCode.isValid()) { - int status = statusCode.toInt(); - if (status != 200 && status != 206 && status != 416) { - LOG(("Update Error: Bad HTTP status received in partFinished(): %1").arg(status)); - return fatalFail(); - } - } - - if (!already && !full) { - QMutexLocker lock(&mutex); - full = total; - } - DEBUG_LOG(("Update Info: part %1 of %2").arg(got).arg(total)); - - if (!outputFile.isOpen()) { - if (!outputFile.open(QIODevice::Append)) { - LOG(("Update Error: Could not open output file '%1' for appending").arg(outputFile.fileName())); - return fatalFail(); - } - } - QByteArray r = reply->readAll(); - if (!r.isEmpty()) { - outputFile.write(r); - - QMutexLocker lock(&mutex); - already += r.size(); - } - if (got >= total) { - reply->deleteLater(); - reply = 0; - outputFile.close(); - unpackUpdate(); - } else { - Sandbox::updateProgress(already, full); - } -} - -void UpdateChecker::partFailed(QNetworkReply::NetworkError e) { - if (!reply) return; - - QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); - reply->deleteLater(); - reply = 0; - if (statusCode.isValid()) { - int status = statusCode.toInt(); - if (status == 416) { // Requested range not satisfiable - outputFile.close(); - unpackUpdate(); - return; - } - } - LOG(("Update Error: failed to download part starting from %1, error %2").arg(already).arg(e)); - Sandbox::updateFailed(); -} - -void UpdateChecker::fatalFail() { - clearAll(); - Sandbox::updateFailed(); -} - -void UpdateChecker::clearAll() { - psDeleteDir(cWorkingDir() + qsl("tupdates")); -} - -//QString winapiErrorWrap() { -// WCHAR errMsg[2048]; -// DWORD errorCode = GetLastError(); -// LPTSTR errorText = NULL, errorTextDefault = L"(Unknown error)"; -// FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&errorText, 0, 0); -// if (!errorText) { -// errorText = errorTextDefault; -// } -// StringCbPrintf(errMsg, sizeof(errMsg), L"Error code: %d, error message: %s", errorCode, errorText); -// if (errorText != errorTextDefault) { -// LocalFree(errorText); -// } -// return QString::fromWCharArray(errMsg); -//} - -void UpdateChecker::unpackUpdate() { - QByteArray packed; - if (!outputFile.open(QIODevice::ReadOnly)) { - LOG(("Update Error: cant read updates file!")); - return fatalFail(); - } - -#ifdef Q_OS_WIN // use Lzma SDK for win - const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header -#else // Q_OS_WIN - const int32 hSigLen = 128, hShaLen = 20, hPropsLen = 0, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hOriginalSizeLen; // header -#endif // Q_OS_WIN - - QByteArray compressed = outputFile.readAll(); - int32 compressedLen = compressed.size() - hSize; - if (compressedLen <= 0) { - LOG(("Update Error: bad compressed size: %1").arg(compressed.size())); - return fatalFail(); - } - outputFile.close(); - - QString tempDirPath = cWorkingDir() + qsl("tupdates/temp"), readyFilePath = cWorkingDir() + qsl("tupdates/temp/ready"); - psDeleteDir(tempDirPath); - - QDir tempDir(tempDirPath); - if (tempDir.exists() || QFile(readyFilePath).exists()) { - LOG(("Update Error: cant clear tupdates/temp dir!")); - return fatalFail(); - } - - uchar sha1Buffer[20]; - bool goodSha1 = !memcmp(compressed.constData() + hSigLen, hashSha1(compressed.constData() + hSigLen + hShaLen, compressedLen + hPropsLen + hOriginalSizeLen, sha1Buffer), hShaLen); - if (!goodSha1) { - LOG(("Update Error: bad SHA1 hash of update file!")); - return fatalFail(); - } - - RSA *pbKey = PEM_read_bio_RSAPublicKey(BIO_new_mem_buf(const_cast(AppAlphaVersion ? UpdatesPublicAlphaKey : UpdatesPublicKey), -1), 0, 0, 0); - if (!pbKey) { - LOG(("Update Error: cant read public rsa key!")); - return fatalFail(); - } - if (RSA_verify(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (const uchar*)(compressed.constData()), hSigLen, pbKey) != 1) { // verify signature - RSA_free(pbKey); - if (cAlphaVersion() || cBetaVersion()) { // try other public key, if we are in alpha or beta version - pbKey = PEM_read_bio_RSAPublicKey(BIO_new_mem_buf(const_cast(AppAlphaVersion ? UpdatesPublicKey : UpdatesPublicAlphaKey), -1), 0, 0, 0); - if (!pbKey) { - LOG(("Update Error: cant read public rsa key!")); - return fatalFail(); - } - if (RSA_verify(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (const uchar*)(compressed.constData()), hSigLen, pbKey) != 1) { // verify signature - RSA_free(pbKey); - LOG(("Update Error: bad RSA signature of update file!")); - return fatalFail(); - } - } else { - LOG(("Update Error: bad RSA signature of update file!")); - return fatalFail(); - } - } - RSA_free(pbKey); - - QByteArray uncompressed; - - int32 uncompressedLen; - memcpy(&uncompressedLen, compressed.constData() + hSigLen + hShaLen + hPropsLen, hOriginalSizeLen); - uncompressed.resize(uncompressedLen); - - size_t resultLen = uncompressed.size(); -#ifdef Q_OS_WIN // use Lzma SDK for win - SizeT srcLen = compressedLen; - int uncompressRes = LzmaUncompress((uchar*)uncompressed.data(), &resultLen, (const uchar*)(compressed.constData() + hSize), &srcLen, (const uchar*)(compressed.constData() + hSigLen + hShaLen), LZMA_PROPS_SIZE); - if (uncompressRes != SZ_OK) { - LOG(("Update Error: could not uncompress lzma, code: %1").arg(uncompressRes)); - return fatalFail(); - } -#else // Q_OS_WIN - lzma_stream stream = LZMA_STREAM_INIT; - - lzma_ret ret = lzma_stream_decoder(&stream, UINT64_MAX, LZMA_CONCATENATED); - if (ret != LZMA_OK) { - const char *msg; - switch (ret) { - case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; - case LZMA_OPTIONS_ERROR: msg = "Specified preset is not supported"; break; - case LZMA_UNSUPPORTED_CHECK: msg = "Specified integrity check is not supported"; break; - default: msg = "Unknown error, possibly a bug"; break; - } - LOG(("Error initializing the decoder: %1 (error code %2)").arg(msg).arg(ret)); - return fatalFail(); - } - - stream.avail_in = compressedLen; - stream.next_in = (uint8_t*)(compressed.constData() + hSize); - stream.avail_out = resultLen; - stream.next_out = (uint8_t*)uncompressed.data(); - - lzma_ret res = lzma_code(&stream, LZMA_FINISH); - if (stream.avail_in) { - LOG(("Error in decompression, %1 bytes left in _in of %2 whole.").arg(stream.avail_in).arg(compressedLen)); - return fatalFail(); - } else if (stream.avail_out) { - LOG(("Error in decompression, %1 bytes free left in _out of %2 whole.").arg(stream.avail_out).arg(resultLen)); - return fatalFail(); - } - lzma_end(&stream); - if (res != LZMA_OK && res != LZMA_STREAM_END) { - const char *msg; - switch (res) { - case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; - case LZMA_FORMAT_ERROR: msg = "The input data is not in the .xz format"; break; - case LZMA_OPTIONS_ERROR: msg = "Unsupported compression options"; break; - case LZMA_DATA_ERROR: msg = "Compressed file is corrupt"; break; - case LZMA_BUF_ERROR: msg = "Compressed data is truncated or otherwise corrupt"; break; - default: msg = "Unknown error, possibly a bug"; break; - } - LOG(("Error in decompression: %1 (error code %2)").arg(msg).arg(res)); - return fatalFail(); - } -#endif // Q_OS_WIN - - tempDir.mkdir(tempDir.absolutePath()); - - quint32 version; - { - QDataStream stream(uncompressed); - stream.setVersion(QDataStream::Qt_5_1); - - stream >> version; - if (stream.status() != QDataStream::Ok) { - LOG(("Update Error: cant read version from downloaded stream, status: %1").arg(stream.status())); - return fatalFail(); - } - - quint64 betaVersion = 0; - if (version == 0x7FFFFFFF) { // beta version - stream >> betaVersion; - if (stream.status() != QDataStream::Ok) { - LOG(("Update Error: cant read beta version from downloaded stream, status: %1").arg(stream.status())); - return fatalFail(); - } - if (!cBetaVersion() || betaVersion <= cBetaVersion()) { - LOG(("Update Error: downloaded beta version %1 is not greater, than mine %2").arg(betaVersion).arg(cBetaVersion())); - return fatalFail(); - } - } else if (int32(version) <= AppVersion) { - LOG(("Update Error: downloaded version %1 is not greater, than mine %2").arg(version).arg(AppVersion)); - return fatalFail(); - } - - quint32 filesCount; - stream >> filesCount; - if (stream.status() != QDataStream::Ok) { - LOG(("Update Error: cant read files count from downloaded stream, status: %1").arg(stream.status())); - return fatalFail(); - } - if (!filesCount) { - LOG(("Update Error: update is empty!")); - return fatalFail(); - } - for (uint32 i = 0; i < filesCount; ++i) { - QString relativeName; - quint32 fileSize; - QByteArray fileInnerData; - bool executable = false; - - stream >> relativeName >> fileSize >> fileInnerData; -#if defined Q_OS_MAC || defined Q_OS_LINUX - stream >> executable; -#endif // Q_OS_MAC || Q_OS_LINUX - if (stream.status() != QDataStream::Ok) { - LOG(("Update Error: cant read file from downloaded stream, status: %1").arg(stream.status())); - return fatalFail(); - } - if (fileSize != quint32(fileInnerData.size())) { - LOG(("Update Error: bad file size %1 not matching data size %2").arg(fileSize).arg(fileInnerData.size())); - return fatalFail(); - } - - QFile f(tempDirPath + '/' + relativeName); - if (!QDir().mkpath(QFileInfo(f).absolutePath())) { - LOG(("Update Error: cant mkpath for file '%1'").arg(tempDirPath + '/' + relativeName)); - return fatalFail(); - } - if (!f.open(QIODevice::WriteOnly)) { - LOG(("Update Error: cant open file '%1' for writing").arg(tempDirPath + '/' + relativeName)); - return fatalFail(); - } - auto writtenBytes = f.write(fileInnerData); - if (writtenBytes != fileSize) { - f.close(); - LOG(("Update Error: cant write file '%1', desiredSize: %2, write result: %3").arg(tempDirPath + '/' + relativeName).arg(fileSize).arg(writtenBytes)); - return fatalFail(); - } - f.close(); - if (executable) { - QFileDevice::Permissions p = f.permissions(); - p |= QFileDevice::ExeOwner | QFileDevice::ExeUser | QFileDevice::ExeGroup | QFileDevice::ExeOther; - f.setPermissions(p); - } - } - - // create tdata/version file - tempDir.mkdir(QDir(tempDirPath + qsl("/tdata")).absolutePath()); - std::wstring versionString = ((version % 1000) ? QString("%1.%2.%3").arg(int(version / 1000000)).arg(int((version % 1000000) / 1000)).arg(int(version % 1000)) : QString("%1.%2").arg(int(version / 1000000)).arg(int((version % 1000000) / 1000))).toStdWString(); - - VerInt versionNum = VerInt(version), versionLen = VerInt(versionString.size() * sizeof(VerChar)); - VerChar versionStr[32]; - memcpy(versionStr, versionString.c_str(), versionLen); - - QFile fVersion(tempDirPath + qsl("/tdata/version")); - if (!fVersion.open(QIODevice::WriteOnly)) { - LOG(("Update Error: cant write version file '%1'").arg(tempDirPath + qsl("/version"))); - return fatalFail(); - } - fVersion.write((const char*)&versionNum, sizeof(VerInt)); - if (versionNum == 0x7FFFFFFF) { // beta version - fVersion.write((const char*)&betaVersion, sizeof(quint64)); - } else { - fVersion.write((const char*)&versionLen, sizeof(VerInt)); - fVersion.write((const char*)&versionStr[0], versionLen); - } - fVersion.close(); - } - - QFile readyFile(readyFilePath); - if (readyFile.open(QIODevice::WriteOnly)) { - if (readyFile.write("1", 1)) { - readyFile.close(); - } else { - LOG(("Update Error: cant write ready file '%1'").arg(readyFilePath)); - return fatalFail(); - } - } else { - LOG(("Update Error: cant create ready file '%1'").arg(readyFilePath)); - return fatalFail(); - } - outputFile.remove(); - - Sandbox::updateReady(); -} - -UpdateChecker::~UpdateChecker() { - delete reply; - reply = 0; -} - -bool checkReadyUpdate() { - QString readyFilePath = cWorkingDir() + qsl("tupdates/temp/ready"), readyPath = cWorkingDir() + qsl("tupdates/temp"); - if (!QFile(readyFilePath).exists() || cExeName().isEmpty()) { - if (QDir(cWorkingDir() + qsl("tupdates/ready")).exists() || QDir(cWorkingDir() + qsl("tupdates/temp")).exists()) { - UpdateChecker::clearAll(); - } - return false; - } - - // check ready version - QString versionPath = readyPath + qsl("/tdata/version"); - { - QFile fVersion(versionPath); - if (!fVersion.open(QIODevice::ReadOnly)) { - LOG(("Update Error: cant read version file '%1'").arg(versionPath)); - UpdateChecker::clearAll(); - return false; - } - VerInt versionNum; - if (fVersion.read((char*)&versionNum, sizeof(VerInt)) != sizeof(VerInt)) { - LOG(("Update Error: cant read version from file '%1'").arg(versionPath)); - UpdateChecker::clearAll(); - return false; - } - if (versionNum == 0x7FFFFFFF) { // beta version - quint64 betaVersion = 0; - if (fVersion.read((char*)&betaVersion, sizeof(quint64)) != sizeof(quint64)) { - LOG(("Update Error: cant read beta version from file '%1'").arg(versionPath)); - UpdateChecker::clearAll(); - return false; - } - if (!cBetaVersion() || betaVersion <= cBetaVersion()) { - LOG(("Update Error: cant install beta version %1 having beta version %2").arg(betaVersion).arg(cBetaVersion())); - UpdateChecker::clearAll(); - return false; - } - } else if (versionNum <= AppVersion) { - LOG(("Update Error: cant install version %1 having version %2").arg(versionNum).arg(AppVersion)); - UpdateChecker::clearAll(); - return false; - } - fVersion.close(); - } - -#ifdef Q_OS_WIN - QString curUpdater = (cExeDir() + qsl("Updater.exe")); - QFileInfo updater(cWorkingDir() + qsl("tupdates/temp/Updater.exe")); -#elif defined Q_OS_MAC // Q_OS_WIN - QString curUpdater = (cExeDir() + cExeName() + qsl("/Contents/Frameworks/Updater")); - QFileInfo updater(cWorkingDir() + qsl("tupdates/temp/Telegram.app/Contents/Frameworks/Updater")); -#elif defined Q_OS_LINUX // Q_OS_MAC - QString curUpdater = (cExeDir() + qsl("Updater")); - QFileInfo updater(cWorkingDir() + qsl("tupdates/temp/Updater")); -#endif // Q_OS_LINUX - if (!updater.exists()) { - QFileInfo current(curUpdater); - if (!current.exists()) { - UpdateChecker::clearAll(); - return false; - } - if (!QFile(current.absoluteFilePath()).copy(updater.absoluteFilePath())) { - UpdateChecker::clearAll(); - return false; - } - } -#ifdef Q_OS_WIN - if (CopyFile(updater.absoluteFilePath().toStdWString().c_str(), curUpdater.toStdWString().c_str(), FALSE) == FALSE) { - DWORD errorCode = GetLastError(); - if (errorCode == ERROR_ACCESS_DENIED) { // we are in write-protected dir, like Program Files - cSetWriteProtected(true); - return true; - } else { - UpdateChecker::clearAll(); - return false; - } - } - if (DeleteFile(updater.absoluteFilePath().toStdWString().c_str()) == FALSE) { - UpdateChecker::clearAll(); - return false; - } -#elif defined Q_OS_MAC // Q_OS_WIN - QDir().mkpath(QFileInfo(curUpdater).absolutePath()); - DEBUG_LOG(("Update Info: moving %1 to %2...").arg(updater.absoluteFilePath()).arg(curUpdater)); - if (!objc_moveFile(updater.absoluteFilePath(), curUpdater)) { - UpdateChecker::clearAll(); - return false; - } -#elif defined Q_OS_LINUX // Q_OS_MAC - if (!linuxMoveFile(QFile::encodeName(updater.absoluteFilePath()).constData(), QFile::encodeName(curUpdater).constData())) { - UpdateChecker::clearAll(); - return false; - } -#endif // Q_OS_LINUX - return true; -} - -#endif // !TDESKTOP_DISABLE_AUTOUPDATE - -QString countBetaVersionSignature(uint64 version) { // duplicated in packer.cpp - if (cBetaPrivateKey().isEmpty()) { - LOG(("Error: Trying to count beta version signature without beta private key!")); - return QString(); - } - - QByteArray signedData = (qstr("TelegramBeta_") + QString::number(version, 16).toLower()).toUtf8(); - - static const int32 shaSize = 20, keySize = 128; - - uchar sha1Buffer[shaSize]; - hashSha1(signedData.constData(), signedData.size(), sha1Buffer); // count sha1 - - uint32 siglen = 0; - - RSA *prKey = PEM_read_bio_RSAPrivateKey(BIO_new_mem_buf(const_cast(cBetaPrivateKey().constData()), -1), 0, 0, 0); - if (!prKey) { - LOG(("Error: Could not read beta private key!")); - return QString(); - } - if (RSA_size(prKey) != keySize) { - LOG(("Error: Bad beta private key size: %1").arg(RSA_size(prKey))); - RSA_free(prKey); - return QString(); - } - QByteArray signature; - signature.resize(keySize); - if (RSA_sign(NID_sha1, (const uchar*)(sha1Buffer), shaSize, (uchar*)(signature.data()), &siglen, prKey) != 1) { // count signature - LOG(("Error: Counting beta version signature failed!")); - RSA_free(prKey); - return QString(); - } - RSA_free(prKey); - - if (siglen != keySize) { - LOG(("Error: Bad beta version signature length: %1").arg(siglen)); - return QString(); - } - - signature = signature.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); - signature = signature.replace('-', '8').replace('_', 'B'); - return QString::fromUtf8(signature.mid(19, 32)); -} diff --git a/Telegram/SourceFiles/autoupdater.h b/Telegram/SourceFiles/autoupdater.h deleted file mode 100644 index 58100857c..000000000 --- a/Telegram/SourceFiles/autoupdater.h +++ /dev/null @@ -1,76 +0,0 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ -#pragma once - -#ifndef TDESKTOP_DISABLE_AUTOUPDATE - -#include -#include -#include - -class UpdateChecker : public QObject { - Q_OBJECT - -public: - UpdateChecker(QThread *thread, const QString &url); - - void unpackUpdate(); - - int32 ready(); - int32 size(); - - static void clearAll(); - - ~UpdateChecker(); - -public slots: - - void start(); - void partMetaGot(); - void partFinished(qint64 got, qint64 total); - void partFailed(QNetworkReply::NetworkError e); - void sendRequest(); - -private: - void initOutput(); - - void fatalFail(); - - QString updateUrl; - QNetworkAccessManager manager; - QNetworkReply *reply; - int32 already, full; - QFile outputFile; - - QMutex mutex; - -}; - -bool checkReadyUpdate(); - -#else // TDESKTOP_DISABLE_AUTOUPDATE -class UpdateChecker : public QObject { - Q_OBJECT -}; - -#endif // TDESKTOP_DISABLE_AUTOUPDATE - -QString countBetaVersionSignature(uint64 version); diff --git a/Telegram/SourceFiles/backports/is_invocable.h b/Telegram/SourceFiles/backports/is_invocable.h new file mode 100644 index 000000000..a3a693b30 --- /dev/null +++ b/Telegram/SourceFiles/backports/is_invocable.h @@ -0,0 +1,134 @@ +/* Extracted from https://github.com/facebook/folly/blob/master/folly/functional/Invoke.h */ + +/* + * Copyright 2017-present Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#if __cpp_lib_is_invocable >= 201703 || (_MSC_VER >= 1911 && _MSVC_LANG > 201402) + +namespace backports { + +/* using override */ using std::invoke_result; +/* using override */ using std::invoke_result_t; +/* using override */ using std::is_invocable; +/* using override */ using std::is_invocable_r; +/* using override */ using std::is_invocable_r_v; +/* using override */ using std::is_invocable_v; +/* using override */ using std::is_nothrow_invocable; +/* using override */ using std::is_nothrow_invocable_r; +/* using override */ using std::is_nothrow_invocable_r_v; +/* using override */ using std::is_nothrow_invocable_v; + +} // namespace backports + +#else + +namespace backports { + +namespace invoke_detail { + +template struct Bools { + using valid_type = bool; + static constexpr std::size_t size() { + return sizeof...(Bs); + } +}; + +template struct Negation : std::bool_constant {}; + +// Lighter-weight than Conjunction, but evaluates all sub-conditions eagerly. +template struct StrictConjunction : std::is_same, Bools<(Ts::value || true)...>> {}; + +template +struct StrictDisjunction : Negation, Bools<(Ts::value && false)...>>> {}; + +template +using invoke_result_ = decltype(std::invoke(std::declval(), std::declval()...)); + +template +struct invoke_nothrow_ : std::bool_constant(), std::declval()...))> {}; + +// from: http://en.cppreference.com/w/cpp/types/result_of, CC-BY-SA + +template struct invoke_result {}; + +template struct invoke_result>, F, Args...> { + using type = invoke_result_; +}; + +template struct is_invocable : std::false_type {}; + +template +struct is_invocable>, F, Args...> : std::true_type {}; + +template struct is_invocable_r : std::false_type {}; + +template +struct is_invocable_r>, R, F, Args...> + : std::is_convertible, R> {}; + +template struct is_nothrow_invocable : std::false_type {}; + +template +struct is_nothrow_invocable>, F, Args...> : invoke_nothrow_ {}; + +template struct is_nothrow_invocable_r : std::false_type {}; + +template +struct is_nothrow_invocable_r>, R, F, Args...> + : StrictConjunction, R>, invoke_nothrow_> {}; + +} // namespace invoke_detail + +// mimic: std::invoke_result, C++17 +template struct invoke_result : invoke_detail::invoke_result {}; + +// mimic: std::invoke_result_t, C++17 +template using invoke_result_t = typename invoke_result::type; + +// mimic: std::is_invocable, C++17 +template struct is_invocable : invoke_detail::is_invocable {}; + +// mimic: std::is_invocable_r, C++17 +template +struct is_invocable_r : invoke_detail::is_invocable_r {}; + +// mimic: std::is_nothrow_invocable, C++17 +template +struct is_nothrow_invocable : invoke_detail::is_nothrow_invocable {}; + +// mimic: std::is_nothrow_invocable_r, C++17 +template +struct is_nothrow_invocable_r : invoke_detail::is_nothrow_invocable_r {}; + +template inline constexpr bool is_invocable_v = is_invocable::value; + +template +inline constexpr bool is_invocable_r_v = is_invocable_r::value; + +template +inline constexpr bool is_nothrow_invocable_v = is_nothrow_invocable::value; + +template +inline constexpr bool is_nothrow_invocable_r_v = is_nothrow_invocable_r::value; + +} // namespace backports + +#endif diff --git a/Telegram/SourceFiles/base/algorithm.h b/Telegram/SourceFiles/base/algorithm.h index 44188b05e..6d5b0ff24 100644 --- a/Telegram/SourceFiles/base/algorithm.h +++ b/Telegram/SourceFiles/base/algorithm.h @@ -1,37 +1,39 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once +#include +#include + namespace base { -template -decltype(auto) for_each(Range &&range, Method &&method) { - return std::for_each( - std::begin(std::forward(range)), - std::end(std::forward(range)), - std::forward(method)); +// @todo use ranges-v3 here +template decltype(auto) for_each(Range &&range, Method &&method) { + return std::for_each(std::begin(std::forward(range)), std::end(std::forward(range)), + std::forward(method)); } -template -decltype(auto) for_each_apply(Method &&method) { +template decltype(auto) for_each_apply(Method &&method) { return [&method](auto &&range) { return for_each(std::forward(range), std::forward(method)); }; diff --git a/Telegram/SourceFiles/base/assertion.h b/Telegram/SourceFiles/base/assertion.h index 33de049a9..724a27afc 100644 --- a/Telegram/SourceFiles/base/assertion.h +++ b/Telegram/SourceFiles/base/assertion.h @@ -1,26 +1,29 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include +#include namespace base { namespace assertion { @@ -30,13 +33,15 @@ void log(const char *message, const char *file, int line); // Release build assertions. inline constexpr void noop() { + // MSVC2015 requires return to suppress warning: a constexpr function must contain exactly one return statement + return void(); } [[noreturn]] inline void fail(const char *message, const char *file, int line) { log(message, file, line); // Crash with access violation and generate crash report. - volatile auto nullptr_value = (int*)nullptr; + volatile auto nullptr_value = (int *)nullptr; *nullptr_value = 0; // Silent the possible failure to comply noreturn warning. @@ -44,9 +49,11 @@ inline constexpr void noop() { } inline constexpr void validate(bool condition, const char *message, const char *file, int line) { - (GSL_UNLIKELY(!(condition))) ? fail(message, file, line) : noop(); + // MSVC2015 requires return to suppress error C3249: illegal statement or sub-expression for 'constexpr' function + return (GSL_UNLIKELY(!(condition))) ? fail(message, file, line) : noop(); } + } // namespace assertion } // namespace base diff --git a/Telegram/SourceFiles/base/build_config.h b/Telegram/SourceFiles/base/build_config.h index 173163038..b824e8daf 100644 --- a/Telegram/SourceFiles/base/build_config.h +++ b/Telegram/SourceFiles/base/build_config.h @@ -1,28 +1,30 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include -// thanks Chromium +// thanks Chromium - @todo replace this with cmake-generated config file #if defined(__APPLE__) #define OS_MAC 1 @@ -56,10 +58,37 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #define ARCH_CPU_X86_FAMILY 1 #define ARCH_CPU_X86_64 1 #define ARCH_CPU_64_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 #elif defined(_M_IX86) || defined(__i386__) #define ARCH_CPU_X86_FAMILY 1 #define ARCH_CPU_X86 1 #define ARCH_CPU_32_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#elif defined(__ARMEL__) +#define ARCH_CPU_ARM_FAMILY 1 +#define ARCH_CPU_ARMEL 1 +#define ARCH_CPU_32_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#elif defined(__aarch64__) +#define ARCH_CPU_ARM_FAMILY 1 +#define ARCH_CPU_ARM64 1 +#define ARCH_CPU_64_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#elif defined(__pnacl__) +#define ARCH_CPU_32_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#elif defined(__MIPSEL__) +#if defined(__LP64__) +#define ARCH_CPU_MIPS64_FAMILY 1 +#define ARCH_CPU_MIPS64EL 1 +#define ARCH_CPU_64_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#else +#define ARCH_CPU_MIPS_FAMILY 1 +#define ARCH_CPU_MIPSEL 1 +#define ARCH_CPU_32_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#endif #else #error Please add support for your architecture in base/build_config.h #endif diff --git a/Telegram/SourceFiles/base/flags.h b/Telegram/SourceFiles/base/flags.h index d51e84f1a..277b8c327 100644 --- a/Telegram/SourceFiles/base/flags.h +++ b/Telegram/SourceFiles/base/flags.h @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include @@ -30,49 +32,41 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org namespace base { -template -class flags; +template class flags; -template -struct extended_flags; +template struct extended_flags; -template -using extended_flags_t = typename extended_flags::type; +template using extended_flags_t = typename extended_flags::type; namespace details { -struct flags_zero_helper_struct { -}; +struct flags_zero_helper_struct {}; -using flags_zero_helper = void(base::details::flags_zero_helper_struct::*)(); +using flags_zero_helper = void (base::details::flags_zero_helper_struct::*)(); -template ::type> +template ::type> inline constexpr auto extended_flag_convert(ExtendedEnum value) { return static_cast(value); } -template ::type> +template ::type> inline constexpr auto extended_flags_convert(ExtendedEnum value) { return flags(extended_flag_convert(value)); } } // namespace details -template -class flags { +template class flags { public: using Enum = EnumType; using Type = std::underlying_type_t; constexpr flags() = default; - constexpr flags(details::flags_zero_helper) noexcept { - } - constexpr flags(Enum value) noexcept : _value(static_cast(value)) { - } - explicit constexpr flags(Type value) noexcept : _value(value) { - } + constexpr flags(details::flags_zero_helper) noexcept {} + constexpr flags(Enum value) noexcept + : _value(static_cast(value)) {} + explicit constexpr flags(Type value) noexcept + : _value(value) {} constexpr auto value() const noexcept { return _value; @@ -139,157 +133,131 @@ class flags { private: Type _value = 0; - }; -template -constexpr auto make_flags(Enum value) noexcept { +template constexpr auto make_flags(Enum value) noexcept { return flags(value); } -template ::value>, - typename = std::enable_if_t> +template ::value>, + typename = std::enable_if_t> inline constexpr auto operator|(Enum a, flags b) noexcept { return b | a; } -template ::value>, - typename = std::enable_if_t> +template ::value>, + typename = std::enable_if_t> inline constexpr auto operator&(Enum a, flags b) noexcept { return b & a; } -template ::value>, - typename = std::enable_if_t> +template ::value>, + typename = std::enable_if_t> inline constexpr auto operator^(Enum a, flags b) noexcept { return b ^ a; } -template ::type> +template ::type> inline constexpr auto operator|(flags> a, ExtendedEnum b) { return a | details::extended_flags_convert(b); } -template ::type> +template ::type> inline constexpr auto operator|(ExtendedEnum a, flags> b) { return b | a; } -template > +template > inline constexpr auto operator&(flags> a, ExtendedEnum b) { return a & details::extended_flags_convert(b); } -template ::type> +template ::type> inline constexpr auto operator&(ExtendedEnum a, flags> b) { return b & a; } -template > +template > inline constexpr auto operator^(flags> a, ExtendedEnum b) { return a ^ details::extended_flags_convert(b); } -template ::type> +template ::type> inline constexpr auto operator^(ExtendedEnum a, flags> b) { return b ^ a; } -template ::type> +template ::type> inline constexpr auto &operator&=(flags> &a, ExtendedEnum b) { return (a &= details::extended_flags_convert(b)); } -template ::type> +template ::type> inline constexpr auto &operator|=(flags> &a, ExtendedEnum b) { return (a |= details::extended_flags_convert(b)); } -template ::type> +template ::type> inline constexpr auto &operator^=(flags> &a, ExtendedEnum b) { return (a ^= details::extended_flags_convert(b)); } -template ::type> +template ::type> inline constexpr auto operator==(flags> a, ExtendedEnum b) { return a == details::extended_flags_convert(b); } -template ::type> +template ::type> inline constexpr auto operator==(ExtendedEnum a, flags> b) { return (b == a); } -template ::type> +template ::type> inline constexpr auto operator!=(flags> a, ExtendedEnum b) { return !(a == b); } -template ::type> +template ::type> inline constexpr auto operator!=(ExtendedEnum a, flags> b) { return !(a == b); } -template ::type> +template ::type> inline constexpr auto operator<(flags> a, ExtendedEnum b) { return a < details::extended_flags_convert(b); } -template ::type> +template ::type> inline constexpr auto operator<(ExtendedEnum a, flags> b) { return details::extended_flags_convert(a) < b; } -template ::type> +template ::type> inline constexpr auto operator>(flags> a, ExtendedEnum b) { return (b < a); } -template ::type> +template ::type> inline constexpr auto operator>(ExtendedEnum a, flags> b) { return (b < a); } -template ::type> +template ::type> inline constexpr auto operator<=(flags> a, ExtendedEnum b) { return !(b < a); } -template ::type> +template ::type> inline constexpr auto operator<=(ExtendedEnum a, flags> b) { return !(b < a); } -template ::type> +template ::type> inline constexpr auto operator>=(flags> a, ExtendedEnum b) { return !(a < b); } -template ::type> +template ::type> inline constexpr auto operator>=(ExtendedEnum a, flags> b) { return !(a < b); } @@ -298,73 +266,62 @@ inline constexpr auto operator>=(ExtendedEnum a, flags::value>, - typename = std::enable_if_t> +template ::value>, + typename = std::enable_if_t> inline constexpr auto operator!(Enum a) noexcept { return !base::make_flags(a); } -template ::value>, - typename = std::enable_if_t> +template ::value>, + typename = std::enable_if_t> inline constexpr auto operator~(Enum a) noexcept { return ~base::make_flags(a); } -template ::value>, - typename = std::enable_if_t> +template ::value>, + typename = std::enable_if_t> inline constexpr auto operator|(Enum a, Enum b) noexcept { return base::make_flags(a) | b; } -template ::value>, - typename = std::enable_if_t> +template ::value>, + typename = std::enable_if_t> inline constexpr auto operator|(Enum a, base::details::flags_zero_helper) noexcept { return base::make_flags(a); } -template ::value>, - typename = std::enable_if_t> +template ::value>, + typename = std::enable_if_t> inline constexpr auto operator|(base::details::flags_zero_helper, Enum b) noexcept { return base::make_flags(b); } -template ::type> +template ::type> inline constexpr auto operator|(ExtendedEnum a, ExtendedEnum b) { return base::details::extended_flags_convert(a) | b; } -template ::type> +template ::type> inline constexpr auto operator|(ExtendedEnum a, typename base::extended_flags::type b) { return base::details::extended_flags_convert(a) | b; } -template ::type> +template ::type> inline constexpr auto operator|(typename base::extended_flags::type a, ExtendedEnum b) { return b | a; } -template ::type> +template ::type> inline constexpr auto operator|(base::details::flags_zero_helper, ExtendedEnum b) { return 0 | base::details::extended_flag_convert(b); } -template ::type> +template ::type> inline constexpr auto operator|(ExtendedEnum a, base::details::flags_zero_helper) { return base::details::extended_flag_convert(a) | 0; } -template ::type> +template ::type> inline constexpr auto operator~(ExtendedEnum b) { return ~base::details::extended_flags_convert(b); } diff --git a/Telegram/SourceFiles/base/flat_map.h b/Telegram/SourceFiles/base/flat_map.h index d1dc28fd3..f94120ad0 100644 --- a/Telegram/SourceFiles/base/flat_map.h +++ b/Telegram/SourceFiles/base/flat_map.h @@ -1,35 +1,36 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once -#include #include "base/optional.h" +#include +#include namespace base { -template -class flat_map; +template class flat_map; -template -class flat_multi_map; +template class flat_multi_map; template class flat_multi_map_iterator_base_impl; @@ -46,8 +47,8 @@ class flat_multi_map_iterator_base_impl { using reference = reference_impl; using const_reference = typename flat_multi_map::const_reference; - flat_multi_map_iterator_base_impl(iterator_impl impl = iterator_impl()) : _impl(impl) { - } + flat_multi_map_iterator_base_impl(iterator_impl impl = iterator_impl()) + : _impl(impl) {} reference operator*() { return *_impl; @@ -112,89 +113,87 @@ class flat_multi_map_iterator_base_impl { private: iterator_impl _impl; friend class flat_multi_map; - }; -template -class flat_multi_map { +template class flat_multi_map { using self = flat_multi_map; class key_const_wrap { public: - key_const_wrap(const Key &value) : _value(value) { - } - key_const_wrap(Key &&value) : _value(std::move(value)) { - } - inline operator const Key&() const { + key_const_wrap(const Key &value) + : _value(value) {} + key_const_wrap(Key &&value) + : _value(std::move(value)) {} + inline operator const Key &() const { return _value; } friend inline bool operator<(const Key &a, const key_const_wrap &b) { - return a < ((const Key&)b); + return a < ((const Key &)b); } friend inline bool operator<(const key_const_wrap &a, const Key &b) { - return ((const Key&)a) < b; + return ((const Key &)a) < b; } friend inline bool operator<(const key_const_wrap &a, const key_const_wrap &b) { - return ((const Key&)a) < ((const Key&)b); + return ((const Key &)a) < ((const Key &)b); } private: Key _value; - }; using pair_type = std::pair; using impl = std::deque; - using iterator_base = flat_multi_map_iterator_base_impl; - using const_iterator_base = flat_multi_map_iterator_base_impl; - using reverse_iterator_base = flat_multi_map_iterator_base_impl; - using const_reverse_iterator_base = flat_multi_map_iterator_base_impl; + using iterator_base = + flat_multi_map_iterator_base_impl; + using const_iterator_base = flat_multi_map_iterator_base_impl; + using reverse_iterator_base = + flat_multi_map_iterator_base_impl; + using const_reverse_iterator_base = + flat_multi_map_iterator_base_impl; public: using value_type = pair_type; using size_type = typename impl::size_type; using difference_type = typename impl::difference_type; - using pointer = pair_type*; - using const_pointer = const pair_type*; - using reference = pair_type&; - using const_reference = const pair_type&; + using pointer = pair_type *; + using const_pointer = const pair_type *; + using reference = pair_type &; + using const_reference = const pair_type &; class const_iterator; class iterator : public iterator_base { public: using iterator_base::iterator_base; - iterator(const iterator_base &other) : iterator_base(other) { - } + iterator(const iterator_base &other) + : iterator_base(other) {} friend class const_iterator; - }; class const_iterator : public const_iterator_base { public: using const_iterator_base::const_iterator_base; - const_iterator(const_iterator_base other) : const_iterator_base(other) { - } - const_iterator(const iterator &other) : const_iterator_base(other._impl) { - } - + const_iterator(const_iterator_base other) + : const_iterator_base(other) {} + const_iterator(const iterator &other) + : const_iterator_base(other._impl) {} }; class const_reverse_iterator; class reverse_iterator : public reverse_iterator_base { public: using reverse_iterator_base::reverse_iterator_base; - reverse_iterator(reverse_iterator_base other) : reverse_iterator_base(other) { - } + reverse_iterator(reverse_iterator_base other) + : reverse_iterator_base(other) {} friend class const_reverse_iterator; - }; class const_reverse_iterator : public const_reverse_iterator_base { public: using const_reverse_iterator_base::const_reverse_iterator_base; - const_reverse_iterator(const_reverse_iterator_base other) : const_reverse_iterator_base(other) { - } - const_reverse_iterator(const reverse_iterator &other) : const_reverse_iterator_base(other._impl) { - } - + const_reverse_iterator(const_reverse_iterator_base other) + : const_reverse_iterator_base(other) {} + const_reverse_iterator(const reverse_iterator &other) + : const_reverse_iterator_base(other._impl) {} }; size_type size() const { @@ -279,8 +278,7 @@ class flat_multi_map { auto where = getUpperBound(value.first); return _impl.insert(where, std::move(value)); } - template - iterator emplace(Args&&... args) { + template iterator emplace(Args &&... args) { return insert(value_type(std::forward(args)...)); } @@ -371,11 +369,9 @@ class flat_multi_map { std::pair getEqualRange(const Key &key) const { return std::equal_range(_impl.begin(), _impl.end(), key, Comparator()); } - }; -template -class flat_map : public flat_multi_map { +template class flat_map : public flat_multi_map { using parent = flat_multi_map; using pair_type = typename parent::pair_type; @@ -413,8 +409,7 @@ class flat_map : public flat_multi_map { } return this->end(); } - template - iterator emplace(Args&&... args) { + template iterator emplace(Args &&... args) { return this->insert(value_type(std::forward(args)...)); } @@ -431,15 +426,15 @@ class flat_map : public flat_multi_map { Type &operator[](const Key &key) { if (this->empty() || (key < this->front().first)) { - this->_impl.push_front({ key, Type() }); + this->_impl.push_front({key, Type()}); return this->front().second; } else if (this->back().first < key) { - this->_impl.push_back({ key, Type() }); + this->_impl.push_back({key, Type()}); return this->back().second; } auto where = this->getLowerBound(key); if (key < where->first) { - return this->_impl.insert(where, { key, Type() })->second; + return this->_impl.insert(where, {key, Type()})->second; } return where->second; } @@ -453,7 +448,6 @@ class flat_map : public flat_multi_map { this->erase(it); return std::move(result); } - }; } // namespace base diff --git a/Telegram/SourceFiles/base/flat_map_tests.cpp b/Telegram/SourceFiles/base/flat_map_tests.cpp deleted file mode 100644 index 88a83a2ee..000000000 --- a/Telegram/SourceFiles/base/flat_map_tests.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ -#include "catch.hpp" - -#include "base/flat_map.h" -#include - -using namespace std; - -TEST_CASE("flat_maps should keep items sorted by key", "[flat_map]") { - base::flat_map v; - v.emplace(0, "a"); - v.emplace(5, "b"); - v.emplace(4, "d"); - v.emplace(2, "e"); - - auto checkSorted = [&] { - auto prev = v.begin(); - REQUIRE(prev != v.end()); - for (auto i = prev + 1; i != v.end(); prev = i, ++i) { - REQUIRE(prev->first < i->first); - } - }; - REQUIRE(v.size() == 4); - checkSorted(); - - SECTION("adding item puts it in the right position") { - v.emplace(3, "c"); - REQUIRE(v.size() == 5); - REQUIRE(v.find(3) != v.end()); - checkSorted(); - } -} diff --git a/Telegram/SourceFiles/base/flat_set.h b/Telegram/SourceFiles/base/flat_set.h index 7e578d334..6360b878e 100644 --- a/Telegram/SourceFiles/base/flat_set.h +++ b/Telegram/SourceFiles/base/flat_set.h @@ -1,40 +1,39 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once +#include #include namespace base { -template -class flat_set; +template class flat_set; -template -class flat_multi_set; +template class flat_multi_set; -template -class flat_multi_set_iterator_base_impl; +template class flat_multi_set_iterator_base_impl; -template -class flat_multi_set_iterator_base_impl { +template class flat_multi_set_iterator_base_impl { public: using iterator_category = typename iterator_impl::iterator_category; @@ -43,8 +42,8 @@ class flat_multi_set_iterator_base_impl { using pointer = typename flat_multi_set::pointer; using reference = typename flat_multi_set::reference; - flat_multi_set_iterator_base_impl(iterator_impl impl = iterator_impl()) : _impl(impl) { - } + flat_multi_set_iterator_base_impl(iterator_impl impl = iterator_impl()) + : _impl(impl) {} reference operator*() const { return *_impl; @@ -100,35 +99,32 @@ class flat_multi_set_iterator_base_impl { private: iterator_impl _impl; friend class flat_multi_set; - }; -template -class flat_multi_set { +template class flat_multi_set { using self = flat_multi_set; class const_wrap { public: - const_wrap(const Type &value) : _value(value) { - } - const_wrap(Type &&value) : _value(std::move(value)) { - } - inline operator const Type&() const { + const_wrap(const Type &value) + : _value(value) {} + const_wrap(Type &&value) + : _value(std::move(value)) {} + inline operator const Type &() const { return _value; } friend inline bool operator<(const Type &a, const const_wrap &b) { - return a < ((const Type&)b); + return a < ((const Type &)b); } friend inline bool operator<(const const_wrap &a, const Type &b) { - return ((const Type&)a) < b; + return ((const Type &)a) < b; } friend inline bool operator<(const const_wrap &a, const const_wrap &b) { - return ((const Type&)a) < ((const Type&)b); + return ((const Type &)a) < ((const Type &)b); } private: Type _value; - }; using impl = std::deque; @@ -142,50 +138,47 @@ class flat_multi_set { using value_type = Type; using size_type = typename impl::size_type; using difference_type = typename impl::difference_type; - using pointer = const Type*; - using reference = const Type&; + using pointer = const Type *; + using reference = const Type &; class const_iterator; class iterator : public iterator_base { public: using iterator_base::iterator_base; - iterator(const iterator_base &other) : iterator_base(other) { - } + iterator(const iterator_base &other) + : iterator_base(other) {} friend class const_iterator; - }; class const_iterator : public const_iterator_base { public: using const_iterator_base::const_iterator_base; - const_iterator(const_iterator_base other) : const_iterator_base(other) { - } - const_iterator(const iterator &other) : const_iterator_base(other._impl) { - } - + const_iterator(const_iterator_base other) + : const_iterator_base(other) {} + const_iterator(const iterator &other) + : const_iterator_base(other._impl) {} }; class const_reverse_iterator; class reverse_iterator : public reverse_iterator_base { public: using reverse_iterator_base::reverse_iterator_base; - reverse_iterator(reverse_iterator_base other) : reverse_iterator_base(other) { - } + reverse_iterator(reverse_iterator_base other) + : reverse_iterator_base(other) {} friend class const_reverse_iterator; - }; class const_reverse_iterator : public const_reverse_iterator_base { public: using const_reverse_iterator_base::const_reverse_iterator_base; - const_reverse_iterator(const_reverse_iterator_base other) : const_reverse_iterator_base(other) { - } - const_reverse_iterator(const reverse_iterator &other) : const_reverse_iterator_base(other._impl) { - } - + const_reverse_iterator(const_reverse_iterator_base other) + : const_reverse_iterator_base(other) {} + const_reverse_iterator(const reverse_iterator &other) + : const_reverse_iterator_base(other._impl) {} }; flat_multi_set() = default; template ::iterator_category> - flat_multi_set(Iterator first, Iterator last) : _impl(first, last) { + flat_multi_set(Iterator first, Iterator last) + : _impl(first, last) { std::sort(_impl.begin(), _impl.end()); } @@ -265,8 +258,7 @@ class flat_multi_set { auto where = getUpperBound(value); return _impl.insert(where, std::move(value)); } - template - iterator emplace(Args&&... args) { + template iterator emplace(Args &&... args) { return insert(Type(std::forward(args)...)); } @@ -349,11 +341,9 @@ class flat_multi_set { std::pair getEqualRange(const Type &value) const { return std::equal_range(_impl.begin(), _impl.end(), value); } - }; -template -class flat_set : public flat_multi_set { +template class flat_set : public flat_multi_set { using parent = flat_multi_set; public: @@ -364,10 +354,11 @@ class flat_set : public flat_multi_set { flat_set() = default; template ::iterator_category> - flat_set(Iterator first, Iterator last) : parent(first, last) { - this->_impl.erase(std::unique(this->_impl.begin(), this->_impl.end(), [](auto &&a, auto &&b) { - return !(a < b); - }), this->_impl.end()); + flat_set(Iterator first, Iterator last) + : parent(first, last) { + this->_impl.erase( + std::unique(this->_impl.begin(), this->_impl.end(), [](auto &&a, auto &&b) { return !(a < b); }), + this->_impl.end()); } iterator insert(const Type &value) { @@ -398,8 +389,7 @@ class flat_set : public flat_multi_set { } return this->end(); } - template - iterator emplace(Args&&... args) { + template iterator emplace(Args &&... args) { return this->insert(Type(std::forward(args)...)); } @@ -413,7 +403,6 @@ class flat_set : public flat_multi_set { const_iterator find(const Type &value) const { return this->findFirst(value); } - }; } // namespace base diff --git a/Telegram/SourceFiles/base/flat_set_tests.cpp b/Telegram/SourceFiles/base/flat_set_tests.cpp deleted file mode 100644 index 675b0bdaf..000000000 --- a/Telegram/SourceFiles/base/flat_set_tests.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ -#include "catch.hpp" - -#include "base/flat_set.h" - -TEST_CASE("flat_sets should keep items sorted", "[flat_set]") { - base::flat_set v; - v.insert(0); - v.insert(5); - v.insert(4); - v.insert(2); - - auto checkSorted = [&] { - auto prev = v.begin(); - REQUIRE(prev != v.end()); - for (auto i = prev + 1; i != v.end(); prev = i, ++i) { - REQUIRE(*prev < *i); - } - }; - REQUIRE(v.size() == 4); - checkSorted(); - - SECTION("adding item puts it in the right position") { - v.insert(3); - REQUIRE(v.size() == 5); - REQUIRE(v.find(3) != v.end()); - checkSorted(); - } -} diff --git a/Telegram/SourceFiles/base/functors.h b/Telegram/SourceFiles/base/functors.h index bdf905e1e..67df1a351 100644 --- a/Telegram/SourceFiles/base/functors.h +++ b/Telegram/SourceFiles/base/functors.h @@ -1,40 +1,41 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once +#include + namespace base { namespace functors { struct abs_helper { - template ()), - typename = decltype(-std::declval())> - constexpr Type operator()(Type value) const { + template ()), typename = decltype(-std::declval())> + constexpr Type operator()(Type value) const { return (0 < value) ? value : (-value); } }; -constexpr auto abs = abs_helper {}; +constexpr auto abs = abs_helper{}; -template -inline auto add(Type a) { +template inline auto add(Type a) { return [a](auto b) { return a + b; }; }; diff --git a/Telegram/SourceFiles/base/lambda.h b/Telegram/SourceFiles/base/lambda.h index 48742ce75..3a1d1ef0c 100644 --- a/Telegram/SourceFiles/base/lambda.h +++ b/Telegram/SourceFiles/base/lambda.h @@ -1,27 +1,49 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once +#include // std::max_align_t #include +#ifndef CUSTOM_LAMBDA_WRAP + +#include "base/unique_function.h" +#include + +namespace base { + +namespace lambda_internal { + +template struct lambda_call_type { using type = decltype(&Lambda::operator()); }; + +} // namespace lambda_internal + +template using lambda_call_type_t = typename lambda_internal::lambda_call_type::type; + +} // namespace base + +#else // CUSTOM_LAMBDA_WRAP + #ifndef Assert #define LambdaAssertDefined #define Assert(v) ((v) ? ((void)0) : std::abort()) @@ -41,237 +63,189 @@ template class lambda; namespace lambda_internal { -template -struct type_resolver; +template struct type_resolver; -template -struct type_resolver { +template struct type_resolver { using type = lambda; static constexpr auto is_mutable = false; }; -template -struct type_resolver { +template struct type_resolver { using type = lambda_once; static constexpr auto is_mutable = true; }; -template -struct type_helper { +template struct type_helper { using type = typename type_resolver::type; static constexpr auto is_mutable = type_resolver::is_mutable; }; } // namespace lambda_internal -template -using lambda_type = typename lambda_internal::type_helper>::type; - -template -constexpr bool lambda_is_mutable = lambda_internal::type_helper>::is_mutable; +template using lambda_type = typename lambda_internal::type_helper>::type; namespace lambda_internal { constexpr auto kFullStorageSize = 32U; -static_assert(kFullStorageSize % sizeof(void*) == 0, "Invalid pointer size!"); +static_assert(kFullStorageSize % sizeof(void *) == 0, "Invalid pointer size!"); -constexpr auto kStorageSize = kFullStorageSize - sizeof(void*); +constexpr auto kStorageSize = kFullStorageSize - sizeof(void *); using alignment = std::max_align_t; -template -constexpr bool is_large = (sizeof(std::decay_t) > kStorageSize); +template constexpr bool is_large = (sizeof(std::decay_t) > kStorageSize); [[noreturn]] inline void bad_construct_copy(void *lambda, const void *source) { Unexpected("base::lambda bad_construct_copy() called!"); } -template -[[noreturn]] Return bad_const_call(const void *lambda, Args...) { +template [[noreturn]] Return bad_const_call(const void *lambda, Args...) { Unexpected("base::lambda bad_const_call() called!"); } -template -struct vtable_base { - using construct_copy_other_type = void(*)(void *, const void *); // dst, src - using construct_move_other_type = void(*)(void *, void *); // dst, src - using const_call_type = Return(*)(const void *, Args...); - using call_type = Return(*)(void *, Args...); - using destruct_type = void(*)(const void *); +template struct vtable_base { + using construct_copy_other_type = void (*)(void *, const void *); // dst, src + using construct_move_other_type = void (*)(void *, void *); // dst, src + using const_call_type = Return (*)(const void *, Args...); + using call_type = Return (*)(void *, Args...); + using destruct_type = void (*)(const void *); vtable_base() = delete; vtable_base(const vtable_base &other) = delete; vtable_base &operator=(const vtable_base &other) = delete; - vtable_base( - construct_copy_other_type construct_copy_other, - construct_move_other_type construct_move_other, - const_call_type const_call, - call_type call, - destruct_type destruct) - : construct_copy_other(construct_copy_other) - , construct_move_other(construct_move_other) - , const_call(const_call) - , call(call) - , destruct(destruct) { - } + vtable_base(construct_copy_other_type construct_copy_other, construct_move_other_type construct_move_other, + const_call_type const_call, call_type call, destruct_type destruct) + : construct_copy_other(construct_copy_other) + , construct_move_other(construct_move_other) + , const_call(const_call) + , call(call) + , destruct(destruct) {} const construct_copy_other_type construct_copy_other; const construct_move_other_type construct_move_other; const const_call_type const_call; const call_type call; const destruct_type destruct; - }; -template struct vtable_once_impl; +template struct vtable_once_impl; -template +template struct vtable_once_impl : public vtable_base { using JustLambda = std::decay_t; using LambdaPtr = std::unique_ptr; using Parent = vtable_base; static void construct_move_other_method(void *storage, void *source) { - auto source_lambda_ptr = static_cast(source); + auto source_lambda_ptr = static_cast(source); new (storage) LambdaPtr(std::move(*source_lambda_ptr)); } static Return call_method(void *storage, Args... args) { - return (**static_cast(storage))(std::forward(args)...); + return (**static_cast(storage))(std::forward(args)...); } static void destruct_method(const void *storage) { - static_cast(storage)->~LambdaPtr(); - } - vtable_once_impl() : Parent( - &bad_construct_copy, - &vtable_once_impl::construct_move_other_method, - &bad_const_call, - &vtable_once_impl::call_method, - &vtable_once_impl::destruct_method) { + static_cast(storage)->~LambdaPtr(); } + vtable_once_impl() + : Parent(&bad_construct_copy, &vtable_once_impl::construct_move_other_method, &bad_const_call, + &vtable_once_impl::call_method, &vtable_once_impl::destruct_method) {} // Used directly. static void construct_move_lambda_method(void *storage, void *source) { - auto source_lambda = static_cast(source); - new (storage) LambdaPtr(std::make_unique(static_cast(*source_lambda))); + auto source_lambda = static_cast(source); + new (storage) LambdaPtr(std::make_unique(static_cast(*source_lambda))); } protected: - vtable_once_impl( - typename Parent::construct_copy_other_type construct_copy_other, - typename Parent::const_call_type const_call - ) : Parent( - construct_copy_other, - &vtable_once_impl::construct_move_other_method, - const_call, - &vtable_once_impl::call_method, - &vtable_once_impl::destruct_method) { - } - + vtable_once_impl(typename Parent::construct_copy_other_type construct_copy_other, + typename Parent::const_call_type const_call) + : Parent(construct_copy_other, &vtable_once_impl::construct_move_other_method, const_call, + &vtable_once_impl::call_method, &vtable_once_impl::destruct_method) {} }; -template +template struct vtable_once_impl : public vtable_base { using JustLambda = std::decay_t; using Parent = vtable_base; static void construct_move_other_method(void *storage, void *source) { - auto source_lambda = static_cast(source); - new (storage) JustLambda(static_cast(*source_lambda)); + auto source_lambda = static_cast(source); + new (storage) JustLambda(static_cast(*source_lambda)); } static Return call_method(void *storage, Args... args) { - return (*static_cast(storage))(std::forward(args)...); + return (*static_cast(storage))(std::forward(args)...); } static void destruct_method(const void *storage) { - static_cast(storage)->~JustLambda(); - } - vtable_once_impl() : Parent( - &bad_construct_copy, - &vtable_once_impl::construct_move_other_method, - &bad_const_call, - &vtable_once_impl::call_method, - &vtable_once_impl::destruct_method) { + static_cast(storage)->~JustLambda(); } + vtable_once_impl() + : Parent(&bad_construct_copy, &vtable_once_impl::construct_move_other_method, &bad_const_call, + &vtable_once_impl::call_method, &vtable_once_impl::destruct_method) {} // Used directly. static void construct_move_lambda_method(void *storage, void *source) { - auto source_lambda = static_cast(source); - new (storage) JustLambda(static_cast(*source_lambda)); + auto source_lambda = static_cast(source); + new (storage) JustLambda(static_cast(*source_lambda)); } protected: - vtable_once_impl( - typename Parent::construct_copy_other_type construct_copy_other, - typename Parent::const_call_type const_call - ) : Parent( - construct_copy_other, - &vtable_once_impl::construct_move_other_method, - const_call, - &vtable_once_impl::call_method, - &vtable_once_impl::destruct_method) { - } - + vtable_once_impl(typename Parent::construct_copy_other_type construct_copy_other, + typename Parent::const_call_type const_call) + : Parent(construct_copy_other, &vtable_once_impl::construct_move_other_method, const_call, + &vtable_once_impl::call_method, &vtable_once_impl::destruct_method) {} }; -template +template struct vtable_once : public vtable_once_impl, Return, Args...> { static const vtable_once instance; }; -template +template const vtable_once vtable_once::instance = {}; -template struct vtable_impl; +template struct vtable_impl; -template +template struct vtable_impl : public vtable_once_impl { using JustLambda = std::decay_t; using LambdaPtr = std::unique_ptr; using Parent = vtable_once_impl; static void construct_copy_other_method(void *storage, const void *source) { - auto source_lambda = static_cast(source); + auto source_lambda = static_cast(source); new (storage) LambdaPtr(std::make_unique(*source_lambda->get())); } static Return const_call_method(const void *storage, Args... args) { - auto lambda_ptr = static_cast(storage)->get(); - return (*static_cast(lambda_ptr))(std::forward(args)...); + auto lambda_ptr = static_cast(storage)->get(); + return (*static_cast(lambda_ptr))(std::forward(args)...); } - vtable_impl() : Parent( - &vtable_impl::construct_copy_other_method, - &vtable_impl::const_call_method - ) { - } - + vtable_impl() + : Parent(&vtable_impl::construct_copy_other_method, &vtable_impl::const_call_method) {} }; -template +template struct vtable_impl : public vtable_once_impl { using JustLambda = std::decay_t; using Parent = vtable_once_impl; static void construct_copy_other_method(void *storage, const void *source) { - auto source_lambda = static_cast(source); + auto source_lambda = static_cast(source); new (storage) JustLambda(static_cast(*source_lambda)); } static Return const_call_method(const void *storage, Args... args) { - return (*static_cast(storage))(std::forward(args)...); + return (*static_cast(storage))(std::forward(args)...); } - vtable_impl() : Parent( - &vtable_impl::construct_copy_other_method, - &vtable_impl::const_call_method - ) { - } - + vtable_impl() + : Parent(&vtable_impl::construct_copy_other_method, &vtable_impl::const_call_method) {} }; -template +template struct vtable : public vtable_impl, Return, Args...> { static const vtable instance; }; -template +template const vtable vtable::instance = {}; } // namespace lambda_internal -template -class lambda_once { +template class lambda_once { using VTable = lambda_internal::vtable_base; public: @@ -344,12 +318,14 @@ class lambda_once { } // Copy / move construct / assign from an arbitrary type. - template ()(std::declval()...)),Return>::value>> + template ()(std::declval()...)), Return>::value>> lambda_once(Lambda other) { data_.vtable = &lambda_internal::vtable_once::instance; lambda_internal::vtable_once::construct_move_lambda_method(data_.storage, &other); } - template ()(std::declval()...)),Return>::value>> + template ()(std::declval()...)), Return>::value>> lambda_once &operator=(Lambda other) { if (data_.vtable) { data_.vtable->destruct(data_.storage); @@ -381,8 +357,7 @@ class lambda_once { } protected: - struct Private { - }; + struct Private {}; lambda_once(const VTable *vtable, const Private &) { data_.vtable = vtable; } @@ -396,38 +371,39 @@ class lambda_once { char raw_[lambda_internal::kFullStorageSize]; Data data_; }; - }; -template -class lambda final : public lambda_once { +template class lambda final : public lambda_once { using Parent = lambda_once; public: lambda() = default; // Move construct / assign from the same type. - lambda(lambda &&other) : Parent(std::move(other)) { - } + lambda(lambda &&other) + : Parent(std::move(other)) {} lambda &operator=(lambda &&other) { Parent::operator=(std::move(other)); return *this; } // Copy construct / assign from the same type. - lambda(const lambda &other) : Parent(other) { - } + lambda(const lambda &other) + : Parent(other) {} lambda &operator=(const lambda &other) { Parent::operator=(other); return *this; } // Copy / move construct / assign from an arbitrary type. - template ()(std::declval()...)),Return>::value>> - lambda(Lambda other) : Parent(&lambda_internal::vtable::instance, typename Parent::Private()) { + template ()(std::declval()...)), Return>::value>> + lambda(Lambda other) + : Parent(&lambda_internal::vtable::instance, typename Parent::Private()) { lambda_internal::vtable::construct_move_lambda_method(this->data_.storage, &other); } - template ()(std::declval()...)),Return>::value>> + template ()(std::declval()...)), Return>::value>> lambda &operator=(Lambda other) { if (this->data_.vtable) { this->data_.vtable->destruct(this->data_.storage); @@ -447,7 +423,6 @@ class lambda final : public lambda_once { std::swap(*this, other); } } - }; } // namespace base @@ -459,3 +434,5 @@ class lambda final : public lambda_once { #ifdef LambdaUnexpectedDefined #undef Unexpected #endif // LambdaUnexpectedDefined + +#endif // CUSTOM_LAMBDA_WRAP diff --git a/Telegram/SourceFiles/base/lambda_guard.h b/Telegram/SourceFiles/base/lambda_guard.h index c68825d3c..368bac48e 100644 --- a/Telegram/SourceFiles/base/lambda_guard.h +++ b/Telegram/SourceFiles/base/lambda_guard.h @@ -1,162 +1,98 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once +#include "base/lambda.h" +#include "base/weak_unique_ptr.h" #include -namespace base { - -// Guard lambda call by one or many QObject* weak pointers. +// Guard lambda call by QObject* or enable_weak_from_this* pointers. +namespace base { namespace lambda_internal { -template -class guard_data { +template class guard_with_QObject { public: - using return_type = typename lambda_type::return_type; - - template - inline guard_data(PointersAndLambda&&... qobjectsAndLambda) : _lambda(init(_pointers, std::forward(qobjectsAndLambda)...)) { + template + guard_with_QObject(const QObject *object, OtherLambda &&other) + : _guard(object) + , _callable(std::forward(other)) {} + + template ()(std::declval()...))> + Return operator()(OtherArgs &&... args) { + return _guard ? _callable(std::forward(args)...) : Return(); } - inline guard_data(const guard_data &other) : _lambda(other._lambda) { - for (auto i = 0; i != N; ++i) { - _pointers[i] = other._pointers[i]; - } - } - - template - inline return_type operator()(Args&&... args) { - for (int i = 0; i != N; ++i) { - if (!_pointers[i]) { - return return_type(); - } - } - return _lambda(std::forward(args)...); - } - - template - inline return_type operator()(Args&&... args) const { - for (int i = 0; i != N; ++i) { - if (!_pointers[i]) { - return return_type(); - } - } - return _lambda(std::forward(args)...); + template ()(std::declval()...))> + Return operator()(OtherArgs &&... args) const { + return _guard ? _callable(std::forward(args)...) : Return(); } private: - template - Lambda init(QPointer *pointers, QObject *qobject, PointersAndLambda&&... qobjectsAndLambda) { - *pointers = qobject; - return init(++pointers, std::forward(qobjectsAndLambda)...); - } - Lambda init(QPointer *pointers, Lambda &&lambda) { - return std::move(lambda); - } - - QPointer _pointers[N]; - Lambda _lambda; - + QPointer _guard; + Lambda _callable; }; -template -class guard { +template class guard_with_weak { public: - using return_type = typename lambda_type::return_type; - - template - inline guard(Pointer &&qobject, Other &&other, PointersAndLambda&&... qobjectsAndLambda) : _data(std::make_unique>(std::forward(qobject), std::forward(other), std::forward(qobjectsAndLambda)...)) { - static_assert(1 + 1 + sizeof...(PointersAndLambda) == N + 1, "Wrong argument count!"); - } - - inline guard(const guard &other) : _data(std::make_unique>(static_cast &>(*other._data))) { - } - - inline guard(guard &&other) : _data(std::move(other._data)) { + template + guard_with_weak(const base::enable_weak_from_this *object, OtherLambda &&other) + : _guard(base::make_weak_unique(object)) + , _callable(std::forward(other)) {} + + template ()(std::declval()...))> + Return operator()(OtherArgs &&... args) { + return _guard ? _callable(std::forward(args)...) : Return{}; } - inline guard &operator=(const guard &&other) { - _data = std::move(other._data); - return *this; - } - - inline guard &operator=(guard &&other) { - _data = std::move(other._data); - return *this; - } - - template - inline return_type operator()(Args&&... args) { - return (*_data)(std::forward(args)...); - } - - template - inline return_type operator()(Args&&... args) const { - return (*_data)(std::forward(args)...); - } - - bool isNull() const { - return !_data; + template ()(std::declval()...))> + Return operator()(OtherArgs &&... args) const { + return _guard ? _callable(std::forward(args)...) : Return{}; } private: - mutable std::unique_ptr> _data; - + base::weak_unique_ptr _guard; + Lambda _callable; }; -template -struct guard_type; - -template -struct guard_type { - using type = typename guard_type::type; -}; - -template -struct guard_type { - using type = guard; -}; - -template -struct guard_type_helper { - static constexpr int N = sizeof...(PointersAndLambda); - using type = typename guard_type::type; +template struct lambda_call_type> { + using type = lambda_call_type_t; }; -template -using guard_t = typename guard_type_helper::type; - -template -struct type_helper> { - using type = typename type_helper::type; - static constexpr auto is_mutable = type_helper::is_mutable; +template struct lambda_call_type> { + using type = lambda_call_type_t; }; } // namespace lambda_internal -template -inline lambda_internal::guard_t lambda_guarded(PointersAndLambda&&... qobjectsAndLambda) { - static_assert(sizeof...(PointersAndLambda) > 0, "Lambda should be passed here."); - return lambda_internal::guard_t(std::forward(qobjectsAndLambda)...); +template inline auto lambda_guarded(const QObject *object, Lambda &&lambda) { + using Guarded = lambda_internal::guard_with_QObject>; + return Guarded(object, std::forward(lambda)); +} + +template inline auto lambda_guarded(const base::enable_weak_from_this *object, Lambda &&lambda) { + using Guarded = lambda_internal::guard_with_weak>; + return Guarded(object, std::forward(lambda)); } } // namespace base diff --git a/Telegram/SourceFiles/base/object_ptr.h b/Telegram/SourceFiles/base/object_ptr.h new file mode 100644 index 000000000..1d1a1e571 --- /dev/null +++ b/Telegram/SourceFiles/base/object_ptr.h @@ -0,0 +1,124 @@ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// +#pragma once + +#include "core/utils.h" // @todo used for base::take +#include +#include + +// Smart pointer for QObject*, has move semantics, destroys object if it doesn't have a parent. +template class object_ptr { +public: + object_ptr(std::nullptr_t) {} + + // No default constructor, but constructors with at least + // one argument are simply make functions. + template + explicit object_ptr(Parent &&parent, Args &&... args) + : _object(new Object(std::forward(parent), std::forward(args)...)) {} + + object_ptr(const object_ptr &other) = delete; + object_ptr &operator=(const object_ptr &other) = delete; + object_ptr(object_ptr &&other) + : _object(base::take(other._object)) {} + object_ptr &operator=(object_ptr &&other) { + auto temp = std::move(other); + destroy(); + std::swap(_object, temp._object); + return *this; + } + + template ::value>> + object_ptr(object_ptr &&other) + : _object(base::take(other._object)) {} + + template ::value>> + object_ptr &operator=(object_ptr &&other) { + _object = base::take(other._object); + return *this; + } + + object_ptr &operator=(std::nullptr_t) { + _object = nullptr; + return *this; + } + + // So we can pass this pointer to methods like connect(). + Object *data() const { + return static_cast(_object.data()); + } + operator Object *() const { + return data(); + } + + explicit operator bool() const { + return _object != nullptr; + } + + Object *operator->() const { + return data(); + } + Object &operator*() const { + return *data(); + } + + // Use that instead "= new Object(parent, ...)" + template void create(Parent &&parent, Args &&... args) { + destroy(); + _object = new Object(std::forward(parent), std::forward(args)...); + } + void destroy() { + delete base::take(_object); + } + void destroyDelayed() { + if (_object) { + if (auto widget = base::up_cast(data())) { + widget->hide(); + } + base::take(_object)->deleteLater(); + } + } + + ~object_ptr() { + if (auto pointer = _object) { + if (!pointer->parent()) { + destroy(); + } + } + } + + template + friend object_ptr static_object_cast(object_ptr source); + +private: + template friend class object_ptr; + + QPointer _object; +}; + +template +inline object_ptr static_object_cast(object_ptr source) { + auto result = object_ptr(nullptr); + result._object = static_cast(base::take(source._object).data()); + return std::move(result); +} diff --git a/Telegram/SourceFiles/base/observer.cpp b/Telegram/SourceFiles/base/observer.cpp index 071470da6..f5eb1b942 100644 --- a/Telegram/SourceFiles/base/observer.cpp +++ b/Telegram/SourceFiles/base/observer.cpp @@ -1,24 +1,27 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "base/observer.h" +#include "facades.h" namespace base { namespace internal { @@ -30,7 +33,7 @@ struct ObservableListWrap { ~ObservableListWrap() { CantUseObservables = true; } - OrderedSet list; + std::set list; }; ObservableListWrap &PendingObservables() { @@ -53,13 +56,13 @@ void RegisterPendingObservable(ObservableCallHandlers *handlers) { void UnregisterActiveObservable(ObservableCallHandlers *handlers) { if (CantUseObservables) return; - ActiveObservables().list.remove(handlers); + ActiveObservables().list.erase(handlers); } void UnregisterObservable(ObservableCallHandlers *handlers) { if (CantUseObservables) return; - PendingObservables().list.remove(handlers); - ActiveObservables().list.remove(handlers); + PendingObservables().list.erase(handlers); + ActiveObservables().list.erase(handlers); } } // namespace internal diff --git a/Telegram/SourceFiles/base/observer.h b/Telegram/SourceFiles/base/observer.h index 362c6d42b..90b5cb4a3 100644 --- a/Telegram/SourceFiles/base/observer.h +++ b/Telegram/SourceFiles/base/observer.h @@ -1,59 +1,54 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once -#include -#include +#include "base/assertion.h" #include "base/type_traits.h" +#include "core/utils.h" +#include +#include +#include namespace base { namespace internal { -using ObservableCallHandlers = base::lambda; +using ObservableCallHandlers = Fn; void RegisterPendingObservable(ObservableCallHandlers *handlers); void UnregisterActiveObservable(ObservableCallHandlers *handlers); void UnregisterObservable(ObservableCallHandlers *handlers); -template -struct SubscriptionHandlerHelper { - using type = base::lambda)>; -}; +template struct SubscriptionHandlerHelper { using type = Fn)>; }; -template <> -struct SubscriptionHandlerHelper { - using type = base::lambda; -}; +template <> struct SubscriptionHandlerHelper { using type = Fn; }; -template -using SubscriptionHandler = typename SubscriptionHandlerHelper::type; +template using SubscriptionHandler = typename SubscriptionHandlerHelper::type; // Required because QShared/WeakPointer can't point to void. -class BaseObservableData { -}; +class BaseObservableData {}; -template -class CommonObservableData; +template class CommonObservableData; -template -class ObservableData; +template class ObservableData; } // namespace internal @@ -62,8 +57,9 @@ class Subscription { Subscription() = default; Subscription(const Subscription &) = delete; Subscription &operator=(const Subscription &) = delete; - Subscription(Subscription &&other) : _node(base::take(other._node)), _removeAndDestroyMethod(other._removeAndDestroyMethod) { - } + Subscription(Subscription &&other) + : _node(base::take(other._node)) + , _removeAndDestroyMethod(other._removeAndDestroyMethod) {} Subscription &operator=(Subscription &&other) { qSwap(_node, other._node); qSwap(_removeAndDestroyMethod, other._removeAndDestroyMethod); @@ -83,34 +79,30 @@ class Subscription { private: struct Node { - Node(const QSharedPointer &observable) : observable(observable) { - } + Node(const QSharedPointer &observable) + : observable(observable) {} Node *next = nullptr; Node *prev = nullptr; QWeakPointer observable; }; - using RemoveAndDestroyMethod = void(*)(Node*); - Subscription(Node *node, RemoveAndDestroyMethod removeAndDestroyMethod) : _node(node), _removeAndDestroyMethod(removeAndDestroyMethod) { - } + using RemoveAndDestroyMethod = void (*)(Node *); + Subscription(Node *node, RemoveAndDestroyMethod removeAndDestroyMethod) + : _node(node) + , _removeAndDestroyMethod(removeAndDestroyMethod) {} Node *_node = nullptr; RemoveAndDestroyMethod _removeAndDestroyMethod; - template - friend class internal::CommonObservableData; - - template - friend class internal::ObservableData; + template friend class internal::CommonObservableData; + template friend class internal::ObservableData; }; namespace internal { -template -class BaseObservable; +template class BaseObservable; -template -class CommonObservable { +template class CommonObservable { public: Subscription add_subscription(Handler &&handler) { if (!_data) { @@ -124,7 +116,6 @@ class CommonObservable { friend class CommonObservableData; friend class BaseObservable::is_fast_copy_type::value>; - }; template @@ -135,7 +126,6 @@ class BaseObservable : public internal::CommonObservab this->_data->notify(std::move(event), sync); } } - }; template @@ -152,18 +142,16 @@ class BaseObservable : public internal::CommonObserva this->_data->notify(std::move(event_copy), sync); } } - }; } // namespace internal namespace internal { -template -class CommonObservableData : public BaseObservableData { +template class CommonObservableData : public BaseObservableData { public: - CommonObservableData(CommonObservable *observable) : _observable(observable) { - } + CommonObservableData(CommonObservable *observable) + : _observable(observable) {} Subscription append(Handler &&handler) { auto node = new Node(_observable->_data, std::move(handler)); @@ -174,7 +162,7 @@ class CommonObservableData : public BaseObservableData { } else { _begin = _end = node; } - return { _end, &CommonObservableData::removeAndDestroyNode }; + return {_end, &CommonObservableData::removeAndDestroyNode}; } bool empty() const { @@ -183,8 +171,9 @@ class CommonObservableData : public BaseObservableData { private: struct Node : public Subscription::Node { - Node(const QSharedPointer &observer, Handler &&handler) : Subscription::Node(observer), handler(std::move(handler)) { - } + Node(const QSharedPointer &observer, Handler &&handler) + : Subscription::Node(observer) + , handler(std::move(handler)) {} Handler handler; }; @@ -196,13 +185,13 @@ class CommonObservableData : public BaseObservableData { node->next->prev = node->prev; } if (_begin == node) { - _begin = static_cast(node->next); + _begin = static_cast(node->next); } if (_end == node) { - _end = static_cast(node->prev); + _end = static_cast(node->prev); } if (_current == node) { - _current = static_cast(node->prev); + _current = static_cast(node->prev); } else if (!_begin) { _observable->_data.reset(); } @@ -210,18 +199,17 @@ class CommonObservableData : public BaseObservableData { static void removeAndDestroyNode(Subscription::Node *node) { if (auto that = node->observable.toStrongRef()) { - static_cast(that.data())->remove(node); + static_cast(that.data())->remove(node); } - delete static_cast(node); + delete static_cast(node); } - template - void notifyEnumerate(CallCurrent callCurrent) { + template void notifyEnumerate(CallCurrent callCurrent) { _current = _begin; do { callCurrent(); if (_current) { - _current = static_cast(_current->next); + _current = static_cast(_current->next); } else if (_begin) { _current = _begin; } else { @@ -245,11 +233,9 @@ class CommonObservableData : public BaseObservableData { ObservableCallHandlers _callHandlers; friend class ObservableData; - }; -template -class ObservableData : public CommonObservableData { +template class ObservableData : public CommonObservableData { public: using CommonObservableData::CommonObservableData; @@ -262,9 +248,7 @@ class ObservableData : public CommonObservableData { callHandlers(); } else { if (!this->_callHandlers) { - this->_callHandlers = [this]() { - callHandlers(); - }; + this->_callHandlers = [this]() { callHandlers(); }; } if (_events.empty()) { RegisterPendingObservable(&this->_callHandlers); @@ -282,9 +266,7 @@ class ObservableData : public CommonObservableData { _handling = true; auto events = base::take(_events); for (auto &event : events) { - this->notifyEnumerate([this, &event]() { - this->_current->handler(event); - }); + this->notifyEnumerate([this, &event]() { this->_current->handler(event); }); if (this->destroyMeIfEmpty()) { return; } @@ -295,11 +277,9 @@ class ObservableData : public CommonObservableData { std::deque _events; bool _handling = false; - }; -template -class ObservableData : public CommonObservableData { +template class ObservableData : public CommonObservableData { public: using CommonObservableData::CommonObservableData; @@ -312,9 +292,7 @@ class ObservableData : public CommonObservableData callHandlers(); } else { if (!this->_callHandlers) { - this->_callHandlers = [this]() { - callHandlers(); - }; + this->_callHandlers = [this]() { callHandlers(); }; } if (!_eventsCount) { RegisterPendingObservable(&this->_callHandlers); @@ -332,9 +310,7 @@ class ObservableData : public CommonObservableData _handling = true; auto eventsCount = base::take(_eventsCount); for (int i = 0; i != eventsCount; ++i) { - this->notifyEnumerate([this]() { - this->_current->handler(); - }); + this->notifyEnumerate([this]() { this->_current->handler(); }); if (this->destroyMeIfEmpty()) { return; } @@ -345,38 +321,36 @@ class ObservableData : public CommonObservableData int _eventsCount = 0; bool _handling = false; - }; template -class BaseObservable::is_fast_copy_type::value> : public internal::CommonObservable { +class BaseObservable::is_fast_copy_type::value> + : public internal::CommonObservable { public: void notify(bool sync = false) { if (this->_data) { this->_data->notify(sync); } } - }; } // namespace internal template > -class Observable : public internal::BaseObservable::is_fast_copy_type::value> { +class Observable + : public internal::BaseObservable::is_fast_copy_type::value> { public: Observable() = default; Observable(const Observable &other) = delete; Observable(Observable &&other) = delete; Observable &operator=(const Observable &other) = delete; Observable &operator=(Observable &&other) = delete; - }; -template -class Variable { +template class Variable { public: - Variable(parameter_type startValue = Type()) : _value(startValue) { - } + Variable(parameter_type startValue = Type()) + : _value(startValue) {} Variable(Variable &&other) = default; Variable &operator=(Variable &&other) = default; @@ -395,8 +369,7 @@ class Variable { } } - template - void process(Callback callback, bool sync = false) { + template void process(Callback callback, bool sync = false) { callback(_value); changed().notify(_value, sync); } @@ -408,35 +381,32 @@ class Variable { private: Type _value; mutable Observable _changed; - }; class Subscriber { protected: template - int subscribe(base::Observable &observable, Lambda &&handler) { + size_t subscribe(base::Observable &observable, Lambda &&handler) { _subscriptions.push_back(observable.add_subscription(std::forward(handler))); return _subscriptions.size(); } template - int subscribe(base::Observable *observable, Lambda &&handler) { + size_t subscribe(base::Observable *observable, Lambda &&handler) { return subscribe(*observable, std::forward(handler)); } - template - int subscribe(const base::Variable &variable, Lambda &&handler) { + template size_t subscribe(const base::Variable &variable, Lambda &&handler) { return subscribe(variable.changed(), std::forward(handler)); } - template - int subscribe(const base::Variable *variable, Lambda &&handler) { + template size_t subscribe(const base::Variable *variable, Lambda &&handler) { return subscribe(variable->changed(), std::forward(handler)); } - void unsubscribe(int index) { + void unsubscribe(size_t index) { if (!index) return; - auto count = static_cast(_subscriptions.size()); + auto count = _subscriptions.size(); Assert(index > 0 && index <= count); _subscriptions[index - 1].destroy(); if (index == count) { @@ -455,7 +425,6 @@ class Subscriber { private: std::vector _subscriptions; - }; void HandleObservables(); diff --git a/Telegram/SourceFiles/base/openssl_help.h b/Telegram/SourceFiles/base/openssl_help.h index 357462b86..bae86ea16 100644 --- a/Telegram/SourceFiles/base/openssl_help.h +++ b/Telegram/SourceFiles/base/openssl_help.h @@ -1,38 +1,42 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include -#include #include +#include +#include "base/assertion.h" +#include "core/utils.h" namespace openssl { class Context { public: - Context() : _data(BN_CTX_new()) { - } + Context() + : _data(BN_CTX_new()) {} Context(const Context &other) = delete; - Context(Context &&other) : _data(base::take(other._data)) { - } + Context(Context &&other) + : _data(base::take(other._data)) {} Context &operator=(const Context &other) = delete; Context &operator=(Context &&other) { _data = base::take(other._data); @@ -50,15 +54,14 @@ class Context { private: BN_CTX *_data = nullptr; - }; class BigNum { public: - BigNum() { - BN_init(raw()); - } - BigNum(const BigNum &other) : BigNum() { + BigNum() + : _data(BN_new()) {} + BigNum(const BigNum &other) + : BigNum() { *this = other; } BigNum &operator=(const BigNum &other) { @@ -71,10 +74,12 @@ class BigNum { BN_clear_free(raw()); } - explicit BigNum(unsigned int word) : BigNum() { + explicit BigNum(unsigned int word) + : BigNum() { setWord(word); } - explicit BigNum(base::const_byte_span bytes) : BigNum() { + explicit BigNum(base::const_byte_span bytes) + : BigNum() { setBytes(bytes); } @@ -84,7 +89,7 @@ class BigNum { } } void setBytes(base::const_byte_span bytes) { - if (!BN_bin2bn(reinterpret_cast(bytes.data()), bytes.size(), raw())) { + if (!BN_bin2bn(reinterpret_cast(bytes.data()), bytes.size(), raw())) { _failed = true; } } @@ -170,16 +175,19 @@ class BigNum { } auto length = BN_num_bytes(raw()); auto result = base::byte_vector(length, gsl::byte()); - auto resultSize = BN_bn2bin(raw(), reinterpret_cast(result.data())); + auto resultSize = BN_bn2bin(raw(), reinterpret_cast(result.data())); Assert(resultSize == length); return result; } BIGNUM *raw() { - return &_data; + return _data; } const BIGNUM *raw() const { - return &_data; + return _data; + } + BIGNUM *takeRaw() { + return base::take(_data); } bool failed() const { @@ -193,9 +201,8 @@ class BigNum { } private: - BIGNUM _data; + BIGNUM *_data = nullptr; mutable bool _failed = false; - }; inline BigNum operator-(const BigNum &a, const BigNum &b) { @@ -206,18 +213,20 @@ inline BigNum operator-(const BigNum &a, const BigNum &b) { inline base::byte_array Sha256(base::const_byte_span bytes) { auto result = base::byte_array(); - SHA256(reinterpret_cast(bytes.data()), bytes.size(), reinterpret_cast(result.data())); + SHA256(reinterpret_cast(bytes.data()), bytes.size(), + reinterpret_cast(result.data())); return result; } inline base::byte_array Sha1(base::const_byte_span bytes) { auto result = base::byte_array(); - SHA1(reinterpret_cast(bytes.data()), bytes.size(), reinterpret_cast(result.data())); + SHA1(reinterpret_cast(bytes.data()), bytes.size(), + reinterpret_cast(result.data())); return result; } inline int FillRandom(base::byte_span bytes) { - return RAND_bytes(reinterpret_cast(bytes.data()), bytes.size()); + return RAND_bytes(reinterpret_cast(bytes.data()), bytes.size()); } } // namespace openssl diff --git a/Telegram/SourceFiles/base/optional.h b/Telegram/SourceFiles/base/optional.h index bfb6ec8a0..cbc1e1883 100644 --- a/Telegram/SourceFiles/base/optional.h +++ b/Telegram/SourceFiles/base/optional.h @@ -1,26 +1,29 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "base/variant.h" +#include // for Expects namespace base { @@ -43,23 +46,21 @@ struct none_type { bool operator>=(none_type other) const { return true; } - }; constexpr none_type none = {}; -template -class optional_variant { +template class optional_variant { public: - optional_variant() : _impl(none) { - } - optional_variant(const optional_variant &other) : _impl(other._impl) { - } - optional_variant(optional_variant &&other) : _impl(std::move(other._impl)) { - } + optional_variant() + : _impl(none) {} + optional_variant(const optional_variant &other) + : _impl(other._impl) {} + optional_variant(optional_variant &&other) + : _impl(std::move(other._impl)) {} template >::value>> - optional_variant(T &&value) : _impl(std::forward(value)) { - } + optional_variant(T &&value) + : _impl(std::forward(value)) {} optional_variant &operator=(const optional_variant &other) { _impl = other._impl; return *this; @@ -96,65 +97,43 @@ class optional_variant { return _impl >= other._impl; } - template - decltype(auto) is() const { + template decltype(auto) is() const { return _impl.template is(); } - template - decltype(auto) get_unchecked() { + template decltype(auto) get_unchecked() { return _impl.template get_unchecked(); } - template - decltype(auto) get_unchecked() const { + template decltype(auto) get_unchecked() const { return _impl.template get_unchecked(); } private: variant _impl; - }; -template -inline T *get_if(optional_variant *v) { +template inline T *get_if(optional_variant *v) { return (v && v->template is()) ? &v->template get_unchecked() : nullptr; } -template -inline const T *get_if(const optional_variant *v) { +template inline const T *get_if(const optional_variant *v) { return (v && v->template is()) ? &v->template get_unchecked() : nullptr; } -template -class optional; +template class optional; -template -struct optional_wrap_once { - using type = optional; -}; +template struct optional_wrap_once { using type = optional; }; -template -struct optional_wrap_once> { - using type = optional; -}; +template struct optional_wrap_once> { using type = optional; }; -template -using optional_wrap_once_t = typename optional_wrap_once>::type; +template using optional_wrap_once_t = typename optional_wrap_once>::type; -template -struct optional_chain_result { - using type = optional_wrap_once_t; -}; +template struct optional_chain_result { using type = optional_wrap_once_t; }; -template <> -struct optional_chain_result { - using type = bool; -}; +template <> struct optional_chain_result { using type = bool; }; -template -using optional_chain_result_t = typename optional_chain_result::type; +template using optional_chain_result_t = typename optional_chain_result::type; -template -class optional : public optional_variant { +template class optional : public optional_variant { public: using optional_variant::optional_variant; @@ -178,37 +157,28 @@ class optional : public optional_variant { Expects(result != nullptr); return result; } - }; -template -optional_wrap_once_t make_optional(Type &&value) { - return optional_wrap_once_t { std::forward(value) }; +template optional_wrap_once_t make_optional(Type &&value) { + return optional_wrap_once_t{std::forward(value)}; } template -inline auto optional_chain( - const optional &value, - Method &method, - std::false_type) --> optional_chain_result_t { +inline auto optional_chain(const optional &value, Method &method, std::false_type) + -> optional_chain_result_t { return value ? make_optional(method(*value)) : none; } template -inline auto optional_chain( - const optional &value, - Method &method, - std::true_type) --> optional_chain_result_t { +inline auto optional_chain(const optional &value, Method &method, std::true_type) + -> optional_chain_result_t { return value ? (method(*value), true) : false; } template -inline auto operator|(const optional &value, Method method) --> optional_chain_result_t { +inline auto operator|(const optional &value, Method method) -> optional_chain_result_t { using is_void_return = std::is_same; - return optional_chain(value, method, is_void_return {}); + return optional_chain(value, method, is_void_return{}); } } // namespace base diff --git a/Telegram/SourceFiles/base/ordered_set.h b/Telegram/SourceFiles/base/ordered_set.h deleted file mode 100644 index 9305be4b9..000000000 --- a/Telegram/SourceFiles/base/ordered_set.h +++ /dev/null @@ -1,166 +0,0 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ -#pragma once - -#include - -// ordered set template based on QMap -template -class OrderedSet { - struct NullType { - }; - using Self = OrderedSet; - using Impl = QMap; - using IteratorImpl = typename Impl::iterator; - using ConstIteratorImpl = typename Impl::const_iterator; - Impl impl_; - -public: - OrderedSet() = default; - OrderedSet(const OrderedSet &other) = default; - OrderedSet(OrderedSet &&other) = default; - OrderedSet &operator=(const OrderedSet &other) = default; - OrderedSet &operator=(OrderedSet &&other) = default; - ~OrderedSet() = default; - - inline bool operator==(const Self &other) const { return impl_ == other.impl_; } - inline bool operator!=(const Self &other) const { return impl_ != other.impl_; } - inline int size() const { return impl_.size(); } - inline bool isEmpty() const { return impl_.isEmpty(); } - inline void detach() { return impl_.detach(); } - inline bool isDetached() const { return impl_.isDetached(); } - inline void clear() { return impl_.clear(); } - inline QList values() const { return impl_.keys(); } - inline const T &first() const { return impl_.firstKey(); } - inline const T &last() const { return impl_.lastKey(); } - - class const_iterator; - class iterator { - public: - typedef typename IteratorImpl::iterator_category iterator_category; - typedef typename IteratorImpl::difference_type difference_type; - typedef T value_type; - typedef T *pointer; - typedef T &reference; - - iterator() = default; - iterator(const iterator &other) = default; - iterator &operator=(const iterator &other) = default; - inline const T &operator*() const { return impl_.key(); } - inline const T *operator->() const { return &impl_.key(); } - inline bool operator==(const iterator &other) const { return impl_ == other.impl_; } - inline bool operator!=(const iterator &other) const { return impl_ != other.impl_; } - inline iterator &operator++() { ++impl_; return *this; } - inline iterator operator++(int) { return iterator(impl_++); } - inline iterator &operator--() { --impl_; return *this; } - inline iterator operator--(int) { return iterator(impl_--); } - inline iterator operator+(int j) const { return iterator(impl_ + j); } - inline iterator operator-(int j) const { return iterator(impl_ - j); } - inline iterator &operator+=(int j) { impl_ += j; return *this; } - inline iterator &operator-=(int j) { impl_ -= j; return *this; } - - friend class const_iterator; - inline bool operator==(const const_iterator &other) const { return impl_ == other.impl_; } - inline bool operator!=(const const_iterator &other) const { return impl_ != other.impl_; } - - private: - explicit iterator(const IteratorImpl &impl) : impl_(impl) { - } - IteratorImpl impl_; - friend class OrderedSet; - - }; - friend class iterator; - - class const_iterator { - public: - typedef typename IteratorImpl::iterator_category iterator_category; - typedef typename IteratorImpl::difference_type difference_type; - typedef T value_type; - typedef T *pointer; - typedef T &reference; - - const_iterator() = default; - const_iterator(const const_iterator &other) = default; - const_iterator &operator=(const const_iterator &other) = default; - const_iterator(const iterator &other) : impl_(other.impl_) { - } - const_iterator &operator=(const iterator &other) { - impl_ = other.impl_; - return *this; - } - inline const T &operator*() const { return impl_.key(); } - inline const T *operator->() const { return &impl_.key(); } - inline bool operator==(const const_iterator &other) const { return impl_ == other.impl_; } - inline bool operator!=(const const_iterator &other) const { return impl_ != other.impl_; } - inline const_iterator &operator++() { ++impl_; return *this; } - inline const_iterator operator++(int) { return const_iterator(impl_++); } - inline const_iterator &operator--() { --impl_; return *this; } - inline const_iterator operator--(int) { return const_iterator(impl_--); } - inline const_iterator operator+(int j) const { return const_iterator(impl_ + j); } - inline const_iterator operator-(int j) const { return const_iterator(impl_ - j); } - inline const_iterator &operator+=(int j) { impl_ += j; return *this; } - inline const_iterator &operator-=(int j) { impl_ -= j; return *this; } - - friend class iterator; - inline bool operator==(const iterator &other) const { return impl_ == other.impl_; } - inline bool operator!=(const iterator &other) const { return impl_ != other.impl_; } - - private: - explicit const_iterator(const ConstIteratorImpl &impl) : impl_(impl) { - } - ConstIteratorImpl impl_; - friend class OrderedSet; - - }; - friend class const_iterator; - - // STL style - inline iterator begin() { return iterator(impl_.begin()); } - inline const_iterator begin() const { return const_iterator(impl_.cbegin()); } - inline const_iterator constBegin() const { return const_iterator(impl_.cbegin()); } - inline const_iterator cbegin() const { return const_iterator(impl_.cbegin()); } - inline iterator end() { detach(); return iterator(impl_.end()); } - inline const_iterator end() const { return const_iterator(impl_.cend()); } - inline const_iterator constEnd() const { return const_iterator(impl_.cend()); } - inline const_iterator cend() const { return const_iterator(impl_.cend()); } - inline iterator erase(iterator it) { return iterator(impl_.erase(it.impl_)); } - - inline iterator insert(const T &value) { return iterator(impl_.insert(value, NullType())); } - inline iterator insert(const_iterator pos, const T &value) { return iterator(impl_.insert(pos.impl_, value, NullType())); } - inline int remove(const T &value) { return impl_.remove(value); } - inline bool contains(const T &value) const { return impl_.contains(value); } - - // more Qt - typedef iterator Iterator; - typedef const_iterator ConstIterator; - inline int count() const { return impl_.count(); } - inline iterator find(const T &value) { return iterator(impl_.find(value)); } - inline const_iterator find(const T &value) const { return const_iterator(impl_.constFind(value)); } - inline const_iterator constFind(const T &value) const { return const_iterator(impl_.constFind(value)); } - inline Self &unite(const Self &other) { impl_.unite(other.impl_); return *this; } - - // STL compatibility - typedef typename Impl::difference_type difference_type; - typedef typename Impl::size_type size_type; - inline bool empty() const { return impl_.empty(); } - -}; diff --git a/Telegram/SourceFiles/base/parse_helper.cpp b/Telegram/SourceFiles/base/parse_helper.cpp index a65bfa600..ee65d13a9 100644 --- a/Telegram/SourceFiles/base/parse_helper.cpp +++ b/Telegram/SourceFiles/base/parse_helper.cpp @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "base/parse_helper.h" namespace base { diff --git a/Telegram/SourceFiles/base/parse_helper.h b/Telegram/SourceFiles/base/parse_helper.h index 064736b89..9958bb5e8 100644 --- a/Telegram/SourceFiles/base/parse_helper.h +++ b/Telegram/SourceFiles/base/parse_helper.h @@ -1,24 +1,31 @@ -/* -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. +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// +#pragma once -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. +#include "base/assertion.h" +#include +#include -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ -#pragma once namespace base { namespace parse { @@ -28,11 +35,7 @@ QByteArray stripComments(const QByteArray &content); inline bool skipWhitespaces(const char *&from, const char *end) { Assert(from <= end); - while (from != end && ( - (*from == ' ') || - (*from == '\n') || - (*from == '\t') || - (*from == '\r'))) { + while (from != end && ((*from == ' ') || (*from == '\n') || (*from == '\t') || (*from == '\r'))) { ++from; } return (from != end); @@ -41,11 +44,8 @@ inline bool skipWhitespaces(const char *&from, const char *end) { inline QLatin1String readName(const char *&from, const char *end) { Assert(from <= end); auto start = from; - while (from != end && ( - (*from >= 'a' && *from <= 'z') || - (*from >= 'A' && *from <= 'Z') || - (*from >= '0' && *from <= '9') || - (*from == '_'))) { + while (from != end && ((*from >= 'a' && *from <= 'z') || (*from >= 'A' && *from <= 'Z') || + (*from >= '0' && *from <= '9') || (*from == '_'))) { ++from; } return QLatin1String(start, from - start); diff --git a/Telegram/SourceFiles/base/qthelp_regex.h b/Telegram/SourceFiles/base/qthelp_regex.h index 39c7739d0..2e34f9979 100644 --- a/Telegram/SourceFiles/base/qthelp_regex.h +++ b/Telegram/SourceFiles/base/qthelp_regex.h @@ -1,25 +1,29 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once +#include + #include "base/flags.h" namespace qthelp { @@ -28,10 +32,10 @@ class RegularExpressionMatch { public: RegularExpressionMatch(const QRegularExpressionMatch &other) = delete; RegularExpressionMatch(const RegularExpressionMatch &other) = delete; - RegularExpressionMatch(QRegularExpressionMatch &&match) : data_(std::move(match)) { - } - RegularExpressionMatch(RegularExpressionMatch &&other) : data_(std::move(other.data_)) { - } + RegularExpressionMatch(QRegularExpressionMatch &&match) + : data_(std::move(match)) {} + RegularExpressionMatch(RegularExpressionMatch &&other) + : data_(std::move(other.data_)) {} RegularExpressionMatch &operator=(const QRegularExpressionMatch &match) = delete; RegularExpressionMatch &operator=(const RegularExpressionMatch &other) = delete; RegularExpressionMatch &operator=(QRegularExpressionMatch &&match) { @@ -54,7 +58,6 @@ class RegularExpressionMatch { private: QRegularExpressionMatch data_; - }; enum class RegExOption { @@ -66,20 +69,26 @@ enum class RegExOption { InvertedGreediness = QRegularExpression::InvertedGreedinessOption, DontCapture = QRegularExpression::DontCaptureOption, UseUnicodeProperties = QRegularExpression::UseUnicodePropertiesOption, -#ifndef OS_MAC_OLD +#if (!defined(OS_MAC_OLD) && ((QT_VERSION < QT_VERSION_CHECK(5, 12, 0)) && (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)))) + /// @note These flags are introduced since Qt 5.4 and become deprecated in Qt 5.12, so we must + /// drop it conditionally. + /// See https://doc.qt.io/QT-5/qregularexpression.html#PatternOption-enum for details. OptimizeOnFirstUsage = QRegularExpression::OptimizeOnFirstUsageOption, DontAutomaticallyOptimize = QRegularExpression::DontAutomaticallyOptimizeOption, #endif // OS_MAC_OLD }; using RegExOptions = base::flags; -inline constexpr auto is_flag_type(RegExOption) { return true; }; +inline constexpr auto is_flag_type(RegExOption) { + return true; +}; inline RegularExpressionMatch regex_match(const QString &string, const QString &subject, RegExOptions options = 0) { auto qtOptions = QRegularExpression::PatternOptions(static_cast(options)); return RegularExpressionMatch(QRegularExpression(string, qtOptions).match(subject)); } -inline RegularExpressionMatch regex_match(const QString &string, const QStringRef &subjectRef, RegExOptions options = 0) { +inline RegularExpressionMatch regex_match(const QString &string, const QStringRef &subjectRef, + RegExOptions options = 0) { auto qtOptions = QRegularExpression::PatternOptions(static_cast(options)); #ifndef OS_MAC_OLD return RegularExpressionMatch(QRegularExpression(string, qtOptions).match(subjectRef)); diff --git a/Telegram/SourceFiles/base/qthelp_url.cpp b/Telegram/SourceFiles/base/qthelp_url.cpp index d3c4d9b1c..194decfb2 100644 --- a/Telegram/SourceFiles/base/qthelp_url.cpp +++ b/Telegram/SourceFiles/base/qthelp_url.cpp @@ -1,24 +1,28 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "base/qthelp_url.h" +#include "core/utils.h" +#include namespace qthelp { diff --git a/Telegram/SourceFiles/base/qthelp_url.h b/Telegram/SourceFiles/base/qthelp_url.h index 5b4204597..6f0dc62c8 100644 --- a/Telegram/SourceFiles/base/qthelp_url.h +++ b/Telegram/SourceFiles/base/qthelp_url.h @@ -1,25 +1,31 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once +#include +#include +#include + namespace qthelp { inline QString url_encode(const QString &part) { @@ -35,6 +41,7 @@ enum class UrlParamNameTransform { ToLower, }; // Parses a string like "p1=v1&p2=v2&..&pn=vn" to a map. -QMap url_parse_params(const QString ¶ms, UrlParamNameTransform transform = UrlParamNameTransform::NoTransform); +QMap url_parse_params(const QString ¶ms, + UrlParamNameTransform transform = UrlParamNameTransform::NoTransform); } // namespace qthelp diff --git a/Telegram/SourceFiles/base/runtime_composer.cpp b/Telegram/SourceFiles/base/runtime_composer.cpp index c88a1b0ac..2fb47fac8 100644 --- a/Telegram/SourceFiles/base/runtime_composer.cpp +++ b/Telegram/SourceFiles/base/runtime_composer.cpp @@ -1,35 +1,36 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "base/runtime_composer.h" +#include struct RuntimeComposerMetadatasMap { - QMap data; + QMap data; ~RuntimeComposerMetadatasMap() { - for_const (const RuntimeComposerMetadata *p, data) { - delete p; - } + for_const (const RuntimeComposerMetadata *p, data) { delete p; } } }; -const RuntimeComposerMetadata *GetRuntimeComposerMetadata(uint64 mask) { +const RuntimeComposerMetadata *GetRuntimeComposerMetadata(quint64 mask) { static RuntimeComposerMetadatasMap RuntimeComposerMetadatas; static QMutex RuntimeComposerMetadatasMutex; diff --git a/Telegram/SourceFiles/base/runtime_composer.h b/Telegram/SourceFiles/base/runtime_composer.h index 276f26c76..c59ff0eb5 100644 --- a/Telegram/SourceFiles/base/runtime_composer.h +++ b/Telegram/SourceFiles/base/runtime_composer.h @@ -1,41 +1,48 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once +#include +#include + +#include "base/assertion.h" +#include "core/utils.h" class RuntimeComposer; -typedef void(*RuntimeComponentConstruct)(void *location, RuntimeComposer *composer); -typedef void(*RuntimeComponentDestruct)(void *location); -typedef void(*RuntimeComponentMove)(void *location, void *waslocation); +typedef void (*RuntimeComponentConstruct)(void *location, RuntimeComposer *composer); +typedef void (*RuntimeComponentDestruct)(void *location); +typedef void (*RuntimeComponentMove)(void *location, void *waslocation); struct RuntimeComponentWrapStruct { // Don't init any fields, because it is only created in // global scope, so it will be filled by zeros from the start. RuntimeComponentWrapStruct() = default; - RuntimeComponentWrapStruct(std::size_t size, std::size_t align, RuntimeComponentConstruct construct, RuntimeComponentDestruct destruct, RuntimeComponentMove move) - : Size(size) - , Align(align) - , Construct(construct) - , Destruct(destruct) - , Move(move) { - } + RuntimeComponentWrapStruct(std::size_t size, std::size_t align, RuntimeComponentConstruct construct, + RuntimeComponentDestruct destruct, RuntimeComponentMove move) + : Size(size) + , Align(align) + , Construct(construct) + , Destruct(destruct) + , Move(move) {} std::size_t Size; std::size_t Align; RuntimeComponentConstruct Construct; @@ -43,16 +50,14 @@ struct RuntimeComponentWrapStruct { RuntimeComponentMove Move; }; -template -struct CeilDivideMinimumOne { +template struct CeilDivideMinimumOne { static constexpr int Result = ((Value / Denominator) + ((!Value || (Value % Denominator)) ? 1 : 0)); }; extern RuntimeComponentWrapStruct RuntimeComponentWraps[64]; extern QAtomicInt RuntimeComponentIndexLast; -template -struct RuntimeComponent { +template struct RuntimeComponent { RuntimeComponent() { // While there is no std::aligned_alloc(). static_assert(alignof(Type) <= alignof(std::max_align_t), "Components should align to std::max_align_t!"); @@ -72,19 +77,16 @@ struct RuntimeComponent { if (RuntimeComponentIndexLast.testAndSetOrdered(last, last + 1)) { Assert(last < 64); if (MyIndex.testAndSetOrdered(0, last + 1)) { - RuntimeComponentWraps[last] = RuntimeComponentWrapStruct( - sizeof(Type), - alignof(Type), - Type::RuntimeComponentConstruct, - Type::RuntimeComponentDestruct, - Type::RuntimeComponentMove); + RuntimeComponentWraps[last] = + RuntimeComponentWrapStruct(sizeof(Type), alignof(Type), Type::RuntimeComponentConstruct, + Type::RuntimeComponentDestruct, Type::RuntimeComponentMove); } break; } } return MyIndex.loadAcquire() - 1; } - static uint64 Bit() { + static quint64 Bit() { return (1ULL << Index()); } @@ -93,17 +95,17 @@ struct RuntimeComponent { new (location) Type(); } static void RuntimeComponentDestruct(void *location) { - ((Type*)location)->~Type(); + ((Type *)location)->~Type(); } static void RuntimeComponentMove(void *location, void *waslocation) { - *(Type*)location = std::move(*(Type*)waslocation); + *(Type *)location = std::move(*(Type *)waslocation); } - }; class RuntimeComposerMetadata { public: - RuntimeComposerMetadata(uint64 mask) : _mask(mask) { + RuntimeComposerMetadata(quint64 mask) + : _mask(mask) { for (int i = 0; i != 64; ++i) { auto componentBit = (1ULL << i); if (_mask & componentBit) { @@ -125,31 +127,31 @@ class RuntimeComposerMetadata { } // Meta pointer in the start. - std::size_t size = sizeof(const RuntimeComposerMetadata*); - std::size_t align = alignof(const RuntimeComposerMetadata*); - std::size_t offsets[64] = { 0 }; + std::size_t size = sizeof(const RuntimeComposerMetadata *); + std::size_t align = alignof(const RuntimeComposerMetadata *); + std::size_t offsets[64] = {0}; int last = 64; - bool equals(uint64 mask) const { + bool equals(quint64 mask) const { return _mask == mask; } - uint64 maskadd(uint64 mask) const { + quint64 maskadd(quint64 mask) const { return _mask | mask; } - uint64 maskremove(uint64 mask) const { + quint64 maskremove(quint64 mask) const { return _mask & (~mask); } private: - uint64 _mask; - + quint64 _mask; }; -const RuntimeComposerMetadata *GetRuntimeComposerMetadata(uint64 mask); +const RuntimeComposerMetadata *GetRuntimeComposerMetadata(quint64 mask); class RuntimeComposer { public: - RuntimeComposer(uint64 mask = 0) : _data(zerodata()) { + RuntimeComposer(quint64 mask = 0) + : _data(zerodata()) { if (mask) { auto meta = GetRuntimeComposerMetadata(mask); @@ -197,22 +199,19 @@ class RuntimeComposer { } } - template - bool Has() const { + template bool Has() const { return (_meta()->offsets[Type::Index()] >= sizeof(_meta())); } - template - Type *Get() { - return static_cast(_dataptr(_meta()->offsets[Type::Index()])); + template Type *Get() { + return static_cast(_dataptr(_meta()->offsets[Type::Index()])); } - template - const Type *Get() const { - return static_cast(_dataptr(_meta()->offsets[Type::Index()])); + template const Type *Get() const { + return static_cast(_dataptr(_meta()->offsets[Type::Index()])); } protected: - void UpdateComponents(uint64 mask = 0) { + void UpdateComponents(quint64 mask = 0) { if (!_meta()->equals(mask)) { RuntimeComposer tmp(mask); tmp.swap(*this); @@ -228,10 +227,10 @@ class RuntimeComposer { } } } - void AddComponents(uint64 mask = 0) { + void AddComponents(quint64 mask = 0) { UpdateComponents(_meta()->maskadd(mask)); } - void RemoveComponents(uint64 mask = 0) { + void RemoveComponents(quint64 mask = 0) { UpdateComponents(_meta()->maskremove(mask)); } @@ -241,19 +240,18 @@ class RuntimeComposer { return &ZeroRuntimeComposerMetadata; } - void *_dataptrunsafe(int skip) const { - return (char*)_data + skip; + void *_dataptrunsafe(size_t skip) const { + return (char *)_data + skip; } - void *_dataptr(int skip) const { + void *_dataptr(size_t skip) const { return (skip >= sizeof(_meta())) ? _dataptrunsafe(skip) : nullptr; } const RuntimeComposerMetadata *&_meta() const { - return *static_cast(_data); + return *static_cast(_data); } void *_data = nullptr; void swap(RuntimeComposer &other) { std::swap(_data, other._data); } - }; diff --git a/Telegram/SourceFiles/base/task_queue.cpp b/Telegram/SourceFiles/base/task_queue.cpp index 02395e481..6f1623c39 100644 --- a/Telegram/SourceFiles/base/task_queue.cpp +++ b/Telegram/SourceFiles/base/task_queue.cpp @@ -1,33 +1,40 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ -#include "base/task_queue.h" +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// -#include +#include "base/task_queue.h" +#include "base/assertion.h" +#include "facades.h" +#include +#include +#include #include +#include namespace base { namespace { auto MainThreadId = std::this_thread::get_id(); -const auto MaxThreadsCount = qMax(std::thread::hardware_concurrency(), 2U); +const auto MaxThreadsCount = std::max(std::thread::hardware_concurrency(), 2U); } // namespace @@ -46,20 +53,22 @@ class TaskQueue::TaskQueueList { void Insert(TaskQueue *queue, int list_index_); void Remove(TaskQueue *queue, int list_index_); - TaskQueue *Tail() { return &tail_; } - const TaskQueue *Tail() const { return &tail_; } + TaskQueue *Tail() { + return &tail_; + } + const TaskQueue *Tail() const { + return &tail_; + } - TaskQueue tail_ = { Type::Special, Priority::Normal }; + TaskQueue tail_ = {Type::Special, Priority::Normal}; TaskQueue *(lists_[kQueuesListsCount]); - }; class TaskQueue::TaskThreadPool { - struct Private { - }; + struct Private {}; public: - TaskThreadPool(const Private &) { } + TaskThreadPool(const Private &) {} static const std::shared_ptr &Instance(); void AddQueueTask(TaskQueue *queue, Task &&task); @@ -80,7 +89,6 @@ class TaskQueue::TaskThreadPool { bool stopped_ = false; int tasks_in_process_ = 0; int background_tasks_in_process_ = 0; - }; TaskQueue::TaskQueueList::TaskQueueList() { @@ -170,7 +178,7 @@ TaskQueue *TaskQueue::TaskQueueList::TakeFirst(int list_index_) { auto queue = lists_[list_index_]; Unregister(queue); -// log_msgs.push_back("Unregistered from list in TakeFirst"); + // log_msgs.push_back("Unregistered from list in TakeFirst"); return queue; } @@ -190,9 +198,7 @@ void TaskQueue::TaskThreadPool::AddQueueTask(TaskQueue *queue, Task &&task) { } } if (will_create_thread) { - threads_.emplace_back([this]() { - ThreadFunction(); - }); + threads_.emplace_back([this]() { ThreadFunction(); }); } else if (some_threads_are_vacant) { Assert(threads_count > tasks_in_process_); thread_condition_.wakeOne(); @@ -304,8 +310,8 @@ void TaskQueue::TaskThreadPool::ThreadFunction() { } TaskQueue::TaskQueue(Type type, Priority priority) -: type_(type) -, priority_(priority) { + : type_(type) + , priority_(priority) { if (type_ != Type::Main && type_ != Type::Special) { weak_thread_pool_ = TaskThreadPool::Instance(); } @@ -376,17 +382,17 @@ bool TaskQueue::IsMyThread() const { // Default queues. TaskQueue &TaskQueue::Main() { // static - static TaskQueue MainQueue { Type::Main, Priority::Normal }; + static TaskQueue MainQueue{Type::Main, Priority::Normal}; return MainQueue; } TaskQueue &TaskQueue::Normal() { // static - static TaskQueue NormalQueue { Type::Concurrent, Priority::Normal }; + static TaskQueue NormalQueue{Type::Concurrent, Priority::Normal}; return NormalQueue; } TaskQueue &TaskQueue::Background() { // static - static TaskQueue BackgroundQueue { Type::Concurrent, Priority::Background }; + static TaskQueue BackgroundQueue{Type::Concurrent, Priority::Background}; return BackgroundQueue; } diff --git a/Telegram/SourceFiles/base/task_queue.h b/Telegram/SourceFiles/base/task_queue.h index f444e8d0a..edf0741c6 100644 --- a/Telegram/SourceFiles/base/task_queue.h +++ b/Telegram/SourceFiles/base/task_queue.h @@ -1,30 +1,35 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once +#include "base/timer.h" +#include +#include #include namespace base { -using Task = lambda_once; +using Task = FnMut; // An attempt to create/use a TaskQueue or one of the default queues // after the main() has returned leads to an undefined behaviour. @@ -43,8 +48,8 @@ class TaskQueue { }; // Creating custom serial queues. - TaskQueue(Priority priority) : TaskQueue(Type::Serial, priority) { - } + TaskQueue(Priority priority) + : TaskQueue(Type::Serial, priority) {} // Default main and two concurrent queues. static TaskQueue &Main(); @@ -96,7 +101,6 @@ class TaskQueue { // Only for Serial queues: non-null value means a task is currently processed. bool *destroyed_flag_ = nullptr; - }; } // namespace base diff --git a/Telegram/SourceFiles/base/tests/CMakeLists.txt b/Telegram/SourceFiles/base/tests/CMakeLists.txt new file mode 100644 index 000000000..bfce1e534 --- /dev/null +++ b/Telegram/SourceFiles/base/tests/CMakeLists.txt @@ -0,0 +1,11 @@ +add_executable(tests_flags flags_tests.cpp) +target_link_libraries(tests_flags Qt5::Core) +add_test(NAME flagsTest COMMAND tests_flags) + +add_executable(tests_flat_map flat_map_tests.cpp) +target_link_libraries(tests_flat_map Qt5::Core) +add_test(NAME flatMapTest COMMAND tests_flat_map) + +add_executable(tests_flat_set flat_set_tests.cpp) +target_link_libraries(tests_flat_set Qt5::Core) +add_test(NAME flatSetTest COMMAND tests_flat_set) diff --git a/Telegram/SourceFiles/base/flags_tests.cpp b/Telegram/SourceFiles/base/tests/flags_tests.cpp similarity index 50% rename from Telegram/SourceFiles/base/flags_tests.cpp rename to Telegram/SourceFiles/base/tests/flags_tests.cpp index f2da24d53..43de5afa1 100644 --- a/Telegram/SourceFiles/base/flags_tests.cpp +++ b/Telegram/SourceFiles/base/tests/flags_tests.cpp @@ -1,31 +1,33 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// +#define CATCH_CONFIG_MAIN #include "catch.hpp" #include "base/flags.h" namespace MethodNamespace { -template -void TestFlags(Enum a, Enum b, Enum c) { +template void TestFlags(Enum a, Enum b, Enum c) { auto abc = a | b; abc |= c; auto test = abc != a; @@ -65,7 +67,9 @@ enum class Flag : int { two = (1 << 1), three = (1 << 2), }; -inline constexpr auto is_flag_type(Flag) { return true; } +inline constexpr auto is_flag_type(Flag) { + return true; +} class Class { public: @@ -74,7 +78,9 @@ class Class { two = (1 << 1), three = (1 << 0), }; - friend inline constexpr auto is_flag_type(Public) { return true; } + friend inline constexpr auto is_flag_type(Public) { + return true; + } static void TestPrivate(); @@ -84,8 +90,9 @@ class Class { two = (1 << 1), three = (1 << 2), }; - friend inline constexpr auto is_flag_type(Private) { return true; } - + friend inline constexpr auto is_flag_type(Private) { + return true; + } }; void Class::TestPrivate() { @@ -106,34 +113,24 @@ enum class Flag : int { namespace base { -template<> -struct extended_flags { - using type = FlagsNamespace::Flag; -}; +template <> struct extended_flags { using type = FlagsNamespace::Flag; }; } // namespace base TEST_CASE("flags operators on scoped enums", "[flags]") { SECTION("testing non-member flags") { - MethodNamespace::TestFlags( - FlagsNamespace::Flag::one, - FlagsNamespace::Flag::two, - FlagsNamespace::Flag::three); + MethodNamespace::TestFlags(FlagsNamespace::Flag::one, FlagsNamespace::Flag::two, FlagsNamespace::Flag::three); } SECTION("testing public member flags") { - MethodNamespace::TestFlags( - FlagsNamespace::Class::Public::one, - FlagsNamespace::Class::Public::two, - FlagsNamespace::Class::Public::three); + MethodNamespace::TestFlags(FlagsNamespace::Class::Public::one, FlagsNamespace::Class::Public::two, + FlagsNamespace::Class::Public::three); } SECTION("testing private member flags") { FlagsNamespace::Class::TestPrivate(); } SECTION("testing extended flags") { - MethodNamespace::TestFlags( - ExtendedNamespace::Flag::one, - ExtendedNamespace::Flag::two, - ExtendedNamespace::Flag::three); + MethodNamespace::TestFlags(ExtendedNamespace::Flag::one, ExtendedNamespace::Flag::two, + ExtendedNamespace::Flag::three); auto onetwo = FlagsNamespace::Flag::one | ExtendedNamespace::Flag::two; auto twoone = ExtendedNamespace::Flag::two | FlagsNamespace::Flag::one; diff --git a/Telegram/SourceFiles/base/tests/flat_map_tests.cpp b/Telegram/SourceFiles/base/tests/flat_map_tests.cpp new file mode 100644 index 000000000..9d312cf24 --- /dev/null +++ b/Telegram/SourceFiles/base/tests/flat_map_tests.cpp @@ -0,0 +1,54 @@ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// +#define CATCH_CONFIG_MAIN +#include "catch.hpp" + +#include "base/flat_map.h" +#include + +using namespace std; + +TEST_CASE("flat_maps should keep items sorted by key", "[flat_map]") { + base::flat_map v; + v.emplace(0, "a"); + v.emplace(5, "b"); + v.emplace(4, "d"); + v.emplace(2, "e"); + + auto checkSorted = [&] { + auto prev = v.begin(); + REQUIRE(prev != v.end()); + for (auto i = prev + 1; i != v.end(); prev = i, ++i) { + REQUIRE(prev->first < i->first); + } + }; + REQUIRE(v.size() == 4); + checkSorted(); + + SECTION("adding item puts it in the right position") { + v.emplace(3, "c"); + REQUIRE(v.size() == 5); + REQUIRE(v.find(3) != v.end()); + checkSorted(); + } +} diff --git a/Telegram/SourceFiles/base/tests/flat_set_tests.cpp b/Telegram/SourceFiles/base/tests/flat_set_tests.cpp new file mode 100644 index 000000000..7930508d6 --- /dev/null +++ b/Telegram/SourceFiles/base/tests/flat_set_tests.cpp @@ -0,0 +1,51 @@ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// +#define CATCH_CONFIG_MAIN +#include "catch.hpp" + +#include "base/flat_set.h" + +TEST_CASE("flat_sets should keep items sorted", "[flat_set]") { + base::flat_set v; + v.insert(0); + v.insert(5); + v.insert(4); + v.insert(2); + + auto checkSorted = [&] { + auto prev = v.begin(); + REQUIRE(prev != v.end()); + for (auto i = prev + 1; i != v.end(); prev = i, ++i) { + REQUIRE(*prev < *i); + } + }; + REQUIRE(v.size() == 4); + checkSorted(); + + SECTION("adding item puts it in the right position") { + v.insert(3); + REQUIRE(v.size() == 5); + REQUIRE(v.find(3) != v.end()); + checkSorted(); + } +} diff --git a/Telegram/SourceFiles/base/tests_main.cpp b/Telegram/SourceFiles/base/tests_main.cpp deleted file mode 100644 index 0696e477e..000000000 --- a/Telegram/SourceFiles/base/tests_main.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ -#define CATCH_CONFIG_RUNNER -#include "catch.hpp" -#include "reporters/catch_reporter_compact.hpp" -#include - -namespace Catch { - - struct MinimalReporter : CompactReporter { - MinimalReporter( ReporterConfig const& _config ) - : CompactReporter( _config ) - {} - - virtual void testRunEnded( TestRunStats const& _testRunStats ) { - printTotals( _testRunStats.totals ); - } - - private: - // Colour, message variants: - // - white: No tests ran. - // - red: Failed [both/all] N test cases, failed [both/all] M assertions. - // - white: Passed [both/all] N test cases (no assertions). - // - red: Failed N tests cases, failed M assertions. - // - green: Passed [both/all] N tests cases with M assertions. - - std::string bothOrAll( std::size_t count ) const { - return count == 1 ? std::string() : count == 2 ? "both " : "all " ; - } - - void printTotals( const Totals& totals ) const { - if( totals.testCases.total() == 0 ) { - } - else if( totals.testCases.failed == totals.testCases.total() ) { - Colour colour( Colour::ResultError ); - const std::string qualify_assertions_failed = - totals.assertions.failed == totals.assertions.total() ? - bothOrAll( totals.assertions.failed ) : std::string(); - stream << - "Failed " << bothOrAll( totals.testCases.failed ) - << pluralise( totals.testCases.failed, "test case" ) << ", " - "failed " << qualify_assertions_failed << - pluralise( totals.assertions.failed, "assertion" ) << '.'; - } - else if( totals.assertions.total() == 0 ) { - stream << - "Passed " << bothOrAll( totals.testCases.total() ) - << pluralise( totals.testCases.total(), "test case" ) - << " (no assertions)."; - } - else if( totals.assertions.failed ) { - Colour colour( Colour::ResultError ); - stream << - "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " - "failed " << pluralise( totals.assertions.failed, "assertion" ) << '.'; - } - else { - } - } - }; - - INTERNAL_CATCH_REGISTER_REPORTER( "minimal", MinimalReporter ) - -} // end namespace Catch - -int main(int argc, const char *argv[]) { - const char *catch_argv[] = { argv[0], "-r", "minimal" }; - constexpr auto catch_argc = sizeof(catch_argv) / sizeof(catch_argv[0]); - auto result = Catch::Session().run(catch_argc, catch_argv); - if (result == 0) { - for (auto i = 0; i != argc; ++i) { - if (argv[i] == QString("--touch") && i + 1 != argc) { - QFile(QFile::decodeName(argv[++i])).open(QIODevice::WriteOnly); - } - } - } - return (result < 0xff ? result : 0xff); -} - diff --git a/Telegram/SourceFiles/base/timer.cpp b/Telegram/SourceFiles/base/timer.cpp index d7438179e..b96bedfb6 100644 --- a/Telegram/SourceFiles/base/timer.cpp +++ b/Telegram/SourceFiles/base/timer.cpp @@ -1,24 +1,27 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "base/timer.h" +#include namespace base { namespace { @@ -30,10 +33,11 @@ QObject *TimersAdjuster() { } // namespace -Timer::Timer(base::lambda callback) : QObject(nullptr) -, _callback(std::move(callback)) -, _type(Qt::PreciseTimer) -, _adjusted(false) { +Timer::Timer(Fn callback) + : QObject(nullptr) + , _callback(std::move(callback)) + , _type(Qt::PreciseTimer) + , _adjusted(false) { setRepeat(Repeat::Interval); connect(TimersAdjuster(), &QObject::destroyed, this, [this] { adjust(); }, Qt::QueuedConnection); } @@ -106,7 +110,7 @@ void Timer::timerEvent(QTimerEvent *e) { } } -int DelayedCallTimer::call(TimeMs timeout, lambda_once callback, Qt::TimerType type) { +int DelayedCallTimer::call(TimeMs timeout, FnMut callback, Qt::TimerType type) { Expects(timeout >= 0); if (!callback) { return 0; diff --git a/Telegram/SourceFiles/base/timer.h b/Telegram/SourceFiles/base/timer.h index 7835b7faa..cc49d82e0 100644 --- a/Telegram/SourceFiles/base/timer.h +++ b/Telegram/SourceFiles/base/timer.h @@ -1,40 +1,43 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once -#include "base/lambda.h" #include "base/observer.h" +using TimeMs = qint64; + namespace base { class Timer final : private QObject { public: - Timer(base::lambda callback = base::lambda()); + Timer(Fn callback = Fn()); static Qt::TimerType DefaultType(TimeMs timeout) { constexpr auto kThreshold = TimeMs(1000); return (timeout > kThreshold) ? Qt::CoarseTimer : Qt::PreciseTimer; } - void setCallback(base::lambda callback) { + void setCallback(Fn callback) { _callback = std::move(callback); } @@ -68,7 +71,7 @@ class Timer final : private QObject { private: enum class Repeat : unsigned { - Interval = 0, + Interval = 0, SingleShot = 1, }; void start(TimeMs timeout, Qt::TimerType type, Repeat repeat); @@ -84,7 +87,7 @@ class Timer final : private QObject { return static_cast(_repeat); } - base::lambda _callback; + Fn _callback; TimeMs _next = 0; int _timeout = 0; int _timerId = 0; @@ -92,24 +95,22 @@ class Timer final : private QObject { Qt::TimerType _type : 2; bool _adjusted : 1; unsigned _repeat : 1; - }; class DelayedCallTimer final : private QObject { public: - int call(TimeMs timeout, lambda_once callback) { + int call(TimeMs timeout, FnMut callback) { return call(timeout, std::move(callback), Timer::DefaultType(timeout)); } - int call(TimeMs timeout, lambda_once callback, Qt::TimerType type); + int call(TimeMs timeout, FnMut callback, Qt::TimerType type); void cancel(int callId); protected: void timerEvent(QTimerEvent *e) override; private: - std::map> _callbacks; // Better to use flatmap. - + std::map> _callbacks; // Better to use flatmap. }; } // namespace base diff --git a/Telegram/SourceFiles/base/type_traits.h b/Telegram/SourceFiles/base/type_traits.h index 4979ce656..ba8dea8f2 100644 --- a/Telegram/SourceFiles/base/type_traits.h +++ b/Telegram/SourceFiles/base/type_traits.h @@ -1,130 +1,54 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once +#include + namespace base { -template -struct custom_is_fast_copy_type : public std::false_type { -}; +template struct custom_is_fast_copy_type : public std::false_type {}; // To make your own type a fast copy type just write: -// template <> -// struct base::custom_is_fast_copy_type : public std::true_type { -// }; +// template <> struct base::custom_is_fast_copy_type : public std::true_type {}; namespace internal { -template -struct type_list_contains; - -template -struct type_list_contains : public std::false_type { -}; - -template -struct type_list_contains : public std::integral_constant::value || type_list_contains::value> { -}; - -template -using is_std_unsigned_int = type_list_contains; - -template -using is_std_signed_int = type_list_contains; - -template -using is_std_integral = std::integral_constant::value || is_std_signed_int::value || type_list_contains::value>; - -template -using is_std_float = type_list_contains; - -template -using is_std_arith = std::integral_constant::value || is_std_float::value>; - -template -using is_std_fundamental = std::integral_constant::value || std::is_same::value>; - -template -struct is_pointer : public std::false_type { -}; - -template -struct is_pointer : public std::true_type { -}; - -template -struct is_member_pointer : public std::false_type { -}; - -template -struct is_member_pointer : public std::true_type { -}; - -template -using is_fast_copy_type = std::integral_constant::value || is_pointer::value || is_member_pointer::value || custom_is_fast_copy_type::value>; - -template -struct add_const_reference { - using type = const T &; -}; - -template <> -struct add_const_reference { - using type = void; -}; - template -using add_const_reference_t = typename add_const_reference::type; +using is_fast_copy_type = + std::integral_constant || std::is_pointer_v || std::is_member_pointer_v || + custom_is_fast_copy_type::value>; -template -struct remove_pointer { - using type = T; -}; - -template -struct remove_pointer { - using type = T; -}; - -template -using remove_pointer_t = typename remove_pointer::type; +template struct add_const_reference { using type = const T &; }; +template <> struct add_const_reference { using type = void; }; +template using add_const_reference_t = typename add_const_reference::type; } // namespace internal -template -struct type_traits { - using is_std_unsigned_int = internal::is_std_unsigned_int; - using is_std_signed_int = internal::is_std_signed_int; - using is_std_integral = internal::is_std_integral; - using is_std_float = internal::is_std_float; - using is_std_arith = internal::is_std_arith; - using is_std_fundamental = internal::is_std_fundamental; - using is_pointer = internal::is_pointer; - using is_member_pointer = internal::is_member_pointer; +template struct type_traits { using is_fast_copy_type = internal::is_fast_copy_type; using parameter_type = std::conditional_t>; - using pointed_type = internal::remove_pointer_t; }; -template -using parameter_type = typename type_traits::parameter_type; +template using parameter_type = typename type_traits::parameter_type; } // namespace base diff --git a/Telegram/SourceFiles/base/unique_function.h b/Telegram/SourceFiles/base/unique_function.h new file mode 100644 index 000000000..312291dab --- /dev/null +++ b/Telegram/SourceFiles/base/unique_function.h @@ -0,0 +1,151 @@ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// +#pragma once + +#include + +#ifndef Unexpected +#define Unexpected(message) std::abort() +#define UniqueFunctionUnexpected +#endif // Unexpected + +namespace base { +namespace details { + +template class moveable_callable_wrap { +public: + static_assert(std::is_move_constructible_v, "Should be at least moveable."); + + moveable_callable_wrap(Callable &&other) + : _value(std::move(other)) {} + moveable_callable_wrap &operator=(Callable &&other) { + _value = std::move(other); + return *this; + } + moveable_callable_wrap(moveable_callable_wrap &&other) + : _value(std::move(other._value)) {} + moveable_callable_wrap(const moveable_callable_wrap &other) + : _value(fail_construct()) {} + moveable_callable_wrap &operator=(moveable_callable_wrap &&other) { + _value = std::move(other._value); + return *this; + } + moveable_callable_wrap &operator=(const moveable_callable_wrap &other) { + return fail_assign(); + } + + template decltype(auto) operator()(Args &&... args) const { + return _value(std::forward(args)...); + } + +private: + [[noreturn]] Callable fail_construct() { + Unexpected("Attempt to copy-construct a move-only type."); + } + [[noreturn]] moveable_callable_wrap &fail_assign() { + Unexpected("Attempt to copy-assign a move-only type."); + } + + mutable Callable _value; +}; + +} // namespace details + +template class unique_function; + +template class unique_function final { +public: + unique_function(std::nullptr_t = nullptr) noexcept {} + unique_function(const unique_function &other) = delete; + unique_function &operator=(const unique_function &other) = delete; + + // Move construct / assign from the same type. + unique_function(unique_function &&other) + : _impl(std::move(other._impl)) {} + unique_function &operator=(unique_function &&other) { + _impl = std::move(other._impl); + return *this; + } + + template ()(std::declval()...)), Return>>> + unique_function(Callable &&other) + : unique_function(std::forward(other), std::is_copy_constructible>{}) {} + + template ()(std::declval()...)), Return>>> + unique_function &operator=(Callable &&other) { + using Decayed = std::decay_t; + if constexpr (std::is_copy_constructible_v) { + _impl = std::forward(other); + } else if constexpr (std::is_move_constructible_v) { + _impl = details::moveable_callable_wrap(std::forward(other)); + } else { + static_assert(false_t(other), "Should be moveable."); + } + return *this; + } + + void swap(unique_function &other) { + _impl.swap(other._impl); + } + + template Return operator()(OtherArgs &&... args) { + return _impl(std::forward(args)...); + } + + explicit operator bool() const { + return _impl.operator bool(); + } + + friend inline bool operator==(const unique_function &value, std::nullptr_t) noexcept { + return value._impl == nullptr; + } + friend inline bool operator==(std::nullptr_t, const unique_function &value) noexcept { + return value._impl == nullptr; + } + friend inline bool operator!=(const unique_function &value, std::nullptr_t) noexcept { + return value._impl != nullptr; + } + friend inline bool operator!=(std::nullptr_t, const unique_function &value) noexcept { + return value._impl != nullptr; + } + +private: + template + unique_function(Callable &&other, std::true_type) + : _impl(std::forward(other)) {} + + template + unique_function(Callable &&other, std::false_type) + : _impl(details::moveable_callable_wrap>(std::forward(other))) {} + + std::function _impl; +}; + +} // namespace base + +#ifdef UniqueFunctionUnexpected +#undef UniqueFunctionUnexpected +#undef Unexpected +#endif // UniqueFunctionUnexpectedb diff --git a/Telegram/SourceFiles/base/variant.h b/Telegram/SourceFiles/base/variant.h index 02a005c19..7ebd17ee5 100644 --- a/Telegram/SourceFiles/base/variant.h +++ b/Telegram/SourceFiles/base/variant.h @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include @@ -25,16 +27,13 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org // We use base::variant<> alias and base::get_if() helper while we don't have std::variant<>. namespace base { -template -using variant = mapbox::util::variant; +template using variant = mapbox::util::variant; -template -inline T *get_if(variant *v) { +template inline T *get_if(variant *v) { return (v && v->template is()) ? &v->template get_unchecked() : nullptr; } -template -inline const T *get_if(const variant *v) { +template inline const T *get_if(const variant *v) { return (v && v->template is()) ? &v->template get_unchecked() : nullptr; } diff --git a/Telegram/SourceFiles/base/virtual_method.h b/Telegram/SourceFiles/base/virtual_method.h deleted file mode 100644 index 4edebad4f..000000000 --- a/Telegram/SourceFiles/base/virtual_method.h +++ /dev/null @@ -1,717 +0,0 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ -#pragma once - -namespace base { - -template -class virtual_object; - -template -class virtual_method; - -template -class virtual_override; - -namespace virtual_methods { - -struct child_entry; -using is_parent_check = bool(*)(const child_entry &possible_parent); -struct child_entry { - is_parent_check check_is_parent; - int *table_index; -}; -using child_entries = std::vector; - -// Recursive method to find if some class is a child of some other class. -template -struct is_parent { - static inline bool check(const child_entry &possible_parent) { - // Generate a good error message if ConcreteObject is not a child of virtual_object<>. - using all_objects_must_derive_virtual_object = typename ConcreteObject::virtual_object_parent; - using ConcreteObjectParent = all_objects_must_derive_virtual_object; - return (possible_parent.check_is_parent == &is_parent::check) - || is_parent::check(possible_parent); - } -}; - -template <> -struct is_parent { - static inline bool check(const child_entry &possible_parent) { - return (possible_parent.check_is_parent == &is_parent::check); - } -}; - -// Just force the compiler not to optimize away the object that "enforce" points at. -inline void dont_optimize_away(void *enforce) { - static volatile void *result = nullptr; - if (result) { - result = enforce; - } -} - -template -struct dont_optimize_away_struct { -}; - -inline bool first_dispatch_fired(bool did_fire = false) { - static bool fired = false; - if (did_fire) { - fired = true; - } - return fired; -} - -template -class object_registrator { -public: - inline object_registrator() { - Assert(!first_dispatch_fired()); - Creator(child_entry { - &is_parent::check, - &_index, - }); - } - static inline int &Index() { - return _index; - } - -private: - static int _index; - -}; - -template -int object_registrator::_index = -1; - -class object_base { -protected: - virtual ~object_base() = default; - -}; - -template -struct multi_index_collector; -template -struct override_key_collector_helper; -template -struct table_fill_entry_helper; -template -struct table_count_size; - -} // namespace virtual_methods - -// This should be a base class for every child object in your hierarchy. -// It registers this child in the root virtual_objects classes list. -// Also it holds its own index in the classes list that is used for fast -// invoking of methods from the virtual tables in different virtual_methods. -template -class virtual_object : public ParentObject { -protected: - virtual ~virtual_object() { - virtual_methods::dont_optimize_away(&_virtual_object_registrator); - } - -private: - using virtual_object_parent = ParentObject; - - friend struct virtual_methods::is_parent; - template - friend struct virtual_methods::multi_index_collector; - template - friend struct virtual_methods::override_key_collector_helper; - template - friend class virtual_object; - template - friend class virtual_method; - - static inline void virtual_object_register_child(const virtual_methods::child_entry &entry) { - return ParentObject::virtual_object_register_child(entry); - } - - using virtual_object_registrator = virtual_methods::object_registrator; - static virtual_object_registrator _virtual_object_registrator; - using virtual_object_dont_optimize_away_registrator = virtual_methods::dont_optimize_away_struct; - - static inline int &virtual_object_child_index_static() { - return virtual_object_registrator::Index(); - } - int &virtual_object_child_index() override { - return virtual_object_child_index_static(); - } - -}; - -template -typename virtual_object::virtual_object_registrator virtual_object::_virtual_object_registrator = {}; - -// This should be a base class for the root of the whole hierarchy. -// It holds the table of all child classes in a list. -// This list is used by virtual_methods to generate virtual table. -template -class virtual_object : public virtual_methods::object_base { -protected: - virtual ~virtual_object() { - virtual_methods::dont_optimize_away(&_virtual_object_registrator); - } - -private: - using virtual_object_parent = void; - - friend struct virtual_methods::is_parent; - template - friend struct virtual_methods::table_count_size; - template - friend struct virtual_methods::multi_index_collector; - template - friend struct virtual_methods::override_key_collector_helper; - template - friend struct virtual_methods::table_fill_entry_helper; - template - friend class virtual_object; - template - friend class virtual_method; - - static inline virtual_methods::child_entries &virtual_object_get_child_entries() { - static virtual_methods::child_entries entries; - return entries; - } - - // Registers a new child class. - // After that on the next call to virtual_method::virtual_method_prepare_table() will - // generate a new virtual table for that virtual method. - static inline void virtual_object_register_child(const virtual_methods::child_entry &entry) { - auto &entries = virtual_object_get_child_entries(); - for (auto i = entries.begin(), e = entries.end(); i != e; ++i) { - if (entry.check_is_parent(*i)) { - *entry.table_index = (i - entries.begin()); - i = entries.insert(i, entry); - for (++i, e = entries.end(); i != e; ++i) { - ++*(i->table_index); - } - return; - } - } - *entry.table_index = entries.size(); - entries.push_back(entry); - } - - using virtual_object_registrator = virtual_methods::object_registrator; - static virtual_object_registrator _virtual_object_registrator; - using virtual_object_dont_optimize_away_registrator = virtual_methods::dont_optimize_away_struct; - - static inline int &virtual_object_child_index_static() { - return virtual_object_registrator::Index(); - } - virtual int &virtual_object_child_index() { - return virtual_object_child_index_static(); - } - -}; - -template -typename virtual_object::virtual_object_registrator virtual_object::_virtual_object_registrator = {}; - -namespace virtual_methods { - -template -struct is_virtual_argument : public std::integral_constant::is_pointer::value - ? std::is_base_of::pointed_type>::value - : false> { -}; - -template -class multi_int_wrap { -public: - inline multi_int_wrap(int *indices) : _indices(indices) { - } - inline multi_int_wrap subindex() const { - static_assert(N > 0, "Wrong multi_int_wrap created!"); - return multi_int_wrap(_indices + 1); - } - inline int ¤t() const { - return *_indices; - } - -private: - int *_indices; - -}; - -template -class multi_int_wrap<0, Instance> { -public: - inline multi_int_wrap(int *indices) { - } - inline int current() const { - return 1; - } - -}; - -template -using multi_index_wrap = multi_int_wrap; -template -using multi_size_wrap = multi_int_wrap; - -template -struct multi_index_collector { - static constexpr int N = sizeof...(ConcreteArgs) + 1; - static inline void call(multi_index_wrap indices, ConcreteArg arg, ConcreteArgs... args) { - indices.current() = computeIndex(is_virtual_argument(), arg); - multi_index_collector::call(indices.subindex(), args...); - } - - static inline int computeIndex(std::integral_constant, ConcreteArg arg) { - return 0; - } - static inline int computeIndex(std::integral_constant, ConcreteArg arg) { - return arg->virtual_object_child_index(); - } - -}; - -template <> -struct multi_index_collector<> { - static inline void call(multi_index_wrap<0> indices) { - } -}; - -template -class override_key; - -template -class multi_int { -public: - inline multi_int_wrap data_wrap() { - return multi_int_wrap(_indices); - } - - template - static inline multi_int collect(ConcreteArgs... args) { - multi_int result; - multi_index_collector::call(result.data_wrap(), args...); - return result; - } - - inline void reset() { - memset(_indices, 0, sizeof(_indices)); - } - - inline int value(int index) const { - return _indices[index]; - } - - inline void copy(multi_int_wrap other) { - memcpy(_indices, &other.current(), sizeof(_indices)); - } - -private: - int _indices[N] = { 0 }; - friend class override_key; - -}; - -template -using multi_index = multi_int; -template -using multi_size = multi_int; - -template -class table_data_wrap { -public: - inline table_data_wrap(Call *data, multi_size_wrap size) : _data(data), _size(size) { - } - inline table_data_wrap operator[](int index) const { - return table_data_wrap(_data + index * _size.subindex().current(), _size.subindex()); - } - inline Call &operator[](multi_index_wrap index) const { - return (*this)[index.current()][index.subindex()]; - } - inline int size() const { - return count_size(std::integral_constant()); - } - -private: - template - inline int count_size(std::integral_constant) const { - return _size.current() / _size.subindex().current(); - } - inline int count_size(std::integral_constant) const { - return _size.current(); - } - - Call *_data; - multi_size_wrap _size; - -}; - -template -class table_data_wrap { -public: - inline table_data_wrap(Call *data, multi_size_wrap<0> size) : _data(data) { - } - inline Call &operator[](multi_index_wrap<0> index) const { - return *_data; - } - -private: - Call *_data; - -}; - -template -class table_data_wrap; - -template -struct table_count_size { - static constexpr int N = sizeof...(Args) + 1; - static inline void call(multi_size_wrap index) { - auto subindex = index.subindex(); - table_count_size::call(subindex); - index.current() = count(is_virtual_argument()) * subindex.current(); - } - - static inline int count(std::integral_constant) { - return 1; - } - static inline int count(std::integral_constant) { - return base::type_traits::pointed_type::virtual_object_get_child_entries().size(); - } - -}; - -template <> -struct table_count_size<> { - static inline void call(multi_size_wrap<0> index) { - } -}; - -template -class table_data { -public: - inline table_data_wrap data_wrap() { - return table_data_wrap(_data.data(), _size.data_wrap()); - } - - inline Call &operator[](multi_index index) { - int flat_index = 0; - for (int i = 0; i != N - 1; ++i) { - flat_index += _size.value(i + 1) * index.value(i); - } - flat_index += index.value(N - 1); - return _data[flat_index]; - } - - template - inline bool changed() { - if (!_data.empty()) { - return false; - } - - multi_size size; - table_count_size::call(size.data_wrap()); - _size = size; - _data.resize(_size.value(0), nullptr); - return true; - } - -private: - std::vector _data; - multi_size _size; - -}; - -template -class table_data { -public: - inline table_data_wrap data_wrap() { - return table_data_wrap(&_call, multi_size_wrap<0>(nullptr)); - } - - inline Call &operator[](multi_index<0> index) { - return _call; - } - - inline bool changed() const { - return false; - } - -private: - Call _call = nullptr; - -}; - -template -struct table_fill_entry_helper; - -template -struct table_fill_entry_helper { - static constexpr int N = sizeof...(Args) + 1; - - static inline bool call(table_data_wrap table, multi_index_wrap index, Call &fill) { - auto start = index.current(); - for (auto i = start, count = table.size(); i != count; ++i) { - auto foundGoodType = good(is_virtual_argument(), start, index.current()); - if (foundGoodType) { - index.current() = i; - if (table_fill_entry_helper::call(table[i], index.subindex(), fill)) { - return true; - } - } - } - index.current() = start; - return false; - } - - static inline bool good(std::integral_constant, int start, int current) { - return (start == current); - } - static inline bool good(std::integral_constant, int start, int current) { - using BaseObject = typename base::type_traits::pointed_type; - auto &entries = BaseObject::virtual_object_get_child_entries(); - return (start == current) || entries[start].check_is_parent(entries[current]); - } - -}; - -template -struct table_fill_entry_helper { - static inline bool call(table_data_wrap table, multi_index_wrap<0> index, Call &fill) { - if (auto overrideMethod = table[index]) { - fill = overrideMethod; - return true; - } - return false; - } -}; - -template -struct table_fill_entry; - -template -struct table_fill_entry { - using Call = ReturnType(*)(BaseMethod*, Args...); - static inline void call(table_data_wrap table, multi_index_wrap index, Call &fill) { - table_fill_entry_helper::call(table, index, fill); - } -}; - -template -inline void fill_entry(table_data_wrap table, multi_index_wrap index, Call &fill) { - return virtual_methods::table_fill_entry::call(table, index, fill); -} - -template -struct override_key_collector_helper; - -template -struct override_key_collector_helper { - static inline void call(int **indices) { - setValue(is_virtual_argument(), indices); - override_key_collector_helper::call(indices); - } - - static inline void setValue(std::integral_constant, int **indices) { - indices[M] = nullptr; - } - static inline void setValue(std::integral_constant, int **indices) { - using ConcreteObject = typename base::type_traits::pointed_type; - using IsParentCheckStruct = is_parent; - using IsParentCheckPointer = decltype(&IsParentCheckStruct::check); - using override_key_collector_dont_optimize_away = dont_optimize_away_struct; - override_key_collector_dont_optimize_away dont_optimize_away_object; - (void)dont_optimize_away_object; - - // Check that is_parent<> can be instantiated. - // So every ConcreteObject is a valid child of virtual_object<>. - dont_optimize_away(reinterpret_cast(&IsParentCheckStruct::check)); - indices[M] = &ConcreteObject::virtual_object_child_index_static(); - } - -}; - -template -struct override_key_collector_helper { - static inline void call(int **indices) { - } -}; - -template -struct override_key_collector; - -template -struct override_key_collector { - static inline void call(int **indices) { - override_key_collector_helper<0, ConcreteArgs...>::call(indices); - } -}; - -template -class override_key { -public: - inline multi_index value() const { - multi_index result; - for (int i = 0; i != N; ++i) { - auto pointer = _indices[i]; - result._indices[i] = (pointer ? *pointer : 0); - } - return result; - } - - friend inline bool operator<(const override_key &k1, const override_key &k2) { - for (int i = 0; i != N; ++i) { - auto pointer1 = k1._indices[i], pointer2 = k2._indices[i]; - if (pointer1 < pointer2) { - return true; - } else if (pointer1 > pointer2) { - return false; - } - } - return false; - } - - template - inline void collect() { - override_key_collector::call(_indices); - } - -private: - int *_indices[N]; - -}; - -template -struct static_cast_helper; - -template -struct static_cast_helper { - static inline ReturnType call(BaseMethod *context, Args ...args) { - return ConcreteMethod::call(context, static_cast(args)...); - } -}; - -} // namespace virtual_methods - -// This is a base class for all your virtual methods. -// It dispatches a call to one of the registered virtual_overrides -// or calls the fallback method of the BaseMethod class. -template -class virtual_method { - static constexpr int N = sizeof...(Args); - using virtual_method_call = ReturnType(*)(BaseMethod *context, Args... args); - -public: - inline ReturnType call(Args... args) { - auto context = static_cast(this); - auto index = virtual_methods::multi_index::collect(args...); - auto &table = virtual_method_prepare_table(); - auto &entry = table[index]; - if (!entry) { - virtual_methods::fill_entry(table.data_wrap(), index.data_wrap(), entry); - if (!entry) { - entry = &virtual_method::virtual_method_base_instance; - } - } - return (*entry)(context, args...); - } - -private: - // This map of methods contains only the original registered overrides. - using virtual_method_override_key = virtual_methods::override_key; - using virtual_method_override_map = std::map; - static inline virtual_method_override_map &virtual_method_get_override_map() { - static virtual_method_override_map override_map; - return override_map; - } - - // This method generates and returns a virtual table which holds a method - // for any child in the hierarchy or nullptr if none of the virtual_overrides fit. - using virtual_method_table_data = virtual_methods::table_data; - static inline virtual_method_table_data &virtual_method_get_table_data() { - static virtual_method_table_data virtual_table; - return virtual_table; - } - - static inline virtual_method_table_data &virtual_method_prepare_table() { - auto &virtual_table = virtual_method_get_table_data(); - if (virtual_table.template changed()) { - virtual_methods::first_dispatch_fired(true); - - // The class hierarchy has changed - we need to generate the virtual table once again. - // All other handlers will be placed if they're called. - for (auto &i : virtual_method_get_override_map()) { - virtual_table[i.first.value()] = i.second; - } - } - return virtual_table; - } - - static ReturnType virtual_method_base_instance(BaseMethod *context, Args... args) { - return BaseMethod::default_call(context, args...); - } - - template - static ReturnType virtual_method_override_instance(BaseMethod *context, Args... args) { - return virtual_methods::static_cast_helper::call(context, args...); - } - - template - static inline void virtual_method_register_override() { - auto call = &virtual_method_override_instance; - - virtual_methods::override_key key; - key.template collect(); - - virtual_method_get_override_map()[key] = call; - } - - template - friend class virtual_override; - -}; - -template -class virtual_override { -protected: - virtual ~virtual_override() { - virtual_methods::dont_optimize_away(&_virtual_override_registrator); - } - -private: - class virtual_override_registrator { - public: - inline virtual_override_registrator() { - Assert(!virtual_methods::first_dispatch_fired()); - BaseMethod::template virtual_method_register_override(); - } - - }; - static virtual_override_registrator _virtual_override_registrator; - using virtual_override_dont_optimize_away_registrator = virtual_methods::dont_optimize_away_struct; - -}; - -template -typename virtual_override::virtual_override_registrator virtual_override::_virtual_override_registrator = {}; - -} // namespace base diff --git a/Telegram/SourceFiles/base/weak_unique_ptr.h b/Telegram/SourceFiles/base/weak_unique_ptr.h index dd74f6d43..cca032f8a 100644 --- a/Telegram/SourceFiles/base/weak_unique_ptr.h +++ b/Telegram/SourceFiles/base/weak_unique_ptr.h @@ -1,39 +1,43 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once +#include +// @todo replace this with std::experimental::observer_ptr +#include +#include + namespace base { class enable_weak_from_this; -template -class weak_unique_ptr; +template class weak_unique_ptr; class enable_weak_from_this { public: enable_weak_from_this() = default; - enable_weak_from_this(const enable_weak_from_this &other) noexcept { - } - enable_weak_from_this(enable_weak_from_this &&other) noexcept { - } + enable_weak_from_this(const enable_weak_from_this &other) noexcept {} + enable_weak_from_this(enable_weak_from_this &&other) noexcept {} enable_weak_from_this &operator=(const enable_weak_from_this &other) noexcept { return *this; } @@ -42,31 +46,29 @@ class enable_weak_from_this { } private: - template - friend class weak_unique_ptr; + template friend class weak_unique_ptr; - std::shared_ptr getGuarded() { + std::shared_ptr getGuarded() const { if (!_guarded) { - _guarded = std::make_shared(static_cast(this)); + _guarded = std::make_shared( + const_cast(static_cast(this))); } return _guarded; } - std::shared_ptr _guarded; - + mutable std::shared_ptr _guarded; }; -template -class weak_unique_ptr { +template class weak_unique_ptr { public: weak_unique_ptr() = default; - weak_unique_ptr(T *value) : _guarded(value ? value->getGuarded() : std::shared_ptr()) { - } - weak_unique_ptr(const std::unique_ptr &value) : weak_unique_ptr(value.get()) { - } + weak_unique_ptr(T *value) + : _guarded(value ? value->getGuarded() : std::shared_ptr()) {} + weak_unique_ptr(const std::unique_ptr &value) + : weak_unique_ptr(value.get()) {} weak_unique_ptr &operator=(T *value) { - _guarded = value ? value->getGuarded() : std::shared_ptr(); + _guarded = value ? value->getGuarded() : std::shared_ptr(); return *this; } weak_unique_ptr &operator=(const std::unique_ptr &value) { @@ -75,7 +77,7 @@ class weak_unique_ptr { T *get() const noexcept { if (auto shared = _guarded.lock()) { - return static_cast(*shared); + return static_cast(*shared); } return nullptr; } @@ -90,50 +92,44 @@ class weak_unique_ptr { } private: - std::weak_ptr _guarded; - + std::weak_ptr _guarded; }; -template -inline bool operator==(const weak_unique_ptr &pointer, std::nullptr_t) { +template inline bool operator==(const weak_unique_ptr &pointer, std::nullptr_t) { return (pointer.get() == nullptr); } -template -inline bool operator==(std::nullptr_t, const weak_unique_ptr &pointer) { +template inline bool operator==(std::nullptr_t, const weak_unique_ptr &pointer) { return (pointer == nullptr); } -template -inline bool operator!=(const weak_unique_ptr &pointer, std::nullptr_t) { +template inline bool operator!=(const weak_unique_ptr &pointer, std::nullptr_t) { return !(pointer == nullptr); } -template -inline bool operator!=(std::nullptr_t, const weak_unique_ptr &pointer) { +template inline bool operator!=(std::nullptr_t, const weak_unique_ptr &pointer) { return !(pointer == nullptr); } -template -weak_unique_ptr make_weak_unique(T *value) { +template weak_unique_ptr make_weak_unique(T *value) { return weak_unique_ptr(value); } -template -weak_unique_ptr make_weak_unique(const std::unique_ptr &value) { +template weak_unique_ptr make_weak_unique(const std::unique_ptr &value) { return weak_unique_ptr(value); } } // namespace base #ifdef QT_VERSION -template -inline void InvokeQueued(base::enable_weak_from_this *context, Lambda &&lambda) { +template inline void InvokeQueued(base::enable_weak_from_this *context, Lambda &&lambda) { QObject proxy; - QObject::connect(&proxy, &QObject::destroyed, QCoreApplication::instance(), [guard = base::make_weak_unique(context), lambda = std::forward(lambda)] { - if (guard) { - lambda(); - } - }, Qt::QueuedConnection); + QObject::connect(&proxy, &QObject::destroyed, QCoreApplication::instance(), + [guard = base::make_weak_unique(context), lambda = std::forward(lambda)] { + if (guard) { + lambda(); + } + }, + Qt::QueuedConnection); } #endif // QT_VERSION diff --git a/Telegram/SourceFiles/base/zlib_help.h b/Telegram/SourceFiles/base/zlib_help.h index 1aad0ea46..ee1fd4db7 100644 --- a/Telegram/SourceFiles/base/zlib_help.h +++ b/Telegram/SourceFiles/base/zlib_help.h @@ -1,38 +1,41 @@ -/* -WARNING! All changes made in this file will be lost! -Created from 'colors.palette' by 'codegen_style' - -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. +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// +#pragma once -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. +#include -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ -#pragma once +#include "minizip/unzip.h" +#include "minizip/zip.h" -#include "zip.h" -#include "unzip.h" +#include "logs.h" namespace zlib { namespace internal { class InMemoryFile { public: - InMemoryFile(const QByteArray &data = QByteArray()) : _data(data) { - } + InMemoryFile(const QByteArray &data = QByteArray()) + : _data(data) {} zlib_filefunc_def funcs() { zlib_filefunc_def result; @@ -70,7 +73,7 @@ class InMemoryFile { return this; } - uLong read(voidpf stream, void* buf, uLong size) { + uLong read(voidpf stream, void *buf, uLong size) { uLong toRead = 0; if (!_error) { if (_data.size() > int(_position)) { @@ -85,7 +88,7 @@ class InMemoryFile { return toRead; } - uLong write(voidpf stream, const void* buf, uLong size) { + uLong write(voidpf stream, const void *buf, uLong size) { if (_data.size() < int(_position + size)) { _data.resize(_position + size); } @@ -123,38 +126,37 @@ class InMemoryFile { return _error; } - static voidpf Open(voidpf opaque, const char* filename, int mode) { - return static_cast(opaque)->open(filename, mode); + static voidpf Open(voidpf opaque, const char *filename, int mode) { + return static_cast(opaque)->open(filename, mode); } - static uLong Read(voidpf opaque, voidpf stream, void* buf, uLong size) { - return static_cast(opaque)->read(stream, buf, size); + static uLong Read(voidpf opaque, voidpf stream, void *buf, uLong size) { + return static_cast(opaque)->read(stream, buf, size); } - static uLong Write(voidpf opaque, voidpf stream, const void* buf, uLong size) { - return static_cast(opaque)->write(stream, buf, size); + static uLong Write(voidpf opaque, voidpf stream, const void *buf, uLong size) { + return static_cast(opaque)->write(stream, buf, size); } static int Close(voidpf opaque, voidpf stream) { - return static_cast(opaque)->close(stream); + return static_cast(opaque)->close(stream); } static int Error(voidpf opaque, voidpf stream) { - return static_cast(opaque)->error(stream); + return static_cast(opaque)->error(stream); } static long Tell(voidpf opaque, voidpf stream) { - return static_cast(opaque)->tell(stream); + return static_cast(opaque)->tell(stream); } static long Seek(voidpf opaque, voidpf stream, uLong offset, int origin) { - return static_cast(opaque)->seek(stream, offset, origin); + return static_cast(opaque)->seek(stream, offset, origin); } uLong _position = 0; int _error = 0; QByteArray _data; - }; } // namespace internal @@ -164,7 +166,8 @@ constexpr int kCaseInsensitive = 2; class FileToRead { public: - FileToRead(const QByteArray &content) : _data(content) { + FileToRead(const QByteArray &content) + : _data(content) { auto funcs = _data.funcs(); if (!(_handle = unzOpen2(nullptr, &funcs))) { _error = -1; @@ -185,26 +188,12 @@ class FileToRead { return error(); } - int getCurrentFileInfo( - unz_file_info *pfile_info, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize - ) { + int getCurrentFileInfo(unz_file_info *pfile_info, char *szFileName, uLong fileNameBufferSize, void *extraField, + uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize) { if (error() == UNZ_OK) { - _error = _handle ? unzGetCurrentFileInfo( - _handle, - pfile_info, - szFileName, - fileNameBufferSize, - extraField, - extraFieldBufferSize, - szComment, - commentBufferSize - ) : -1; + _error = _handle ? unzGetCurrentFileInfo(_handle, pfile_info, szFileName, fileNameBufferSize, extraField, + extraFieldBufferSize, szComment, commentBufferSize) : + -1; } return error(); } @@ -236,16 +225,18 @@ class FileToRead { } QByteArray readCurrentFileContent(int fileSizeLimit) { - unz_file_info fileInfo = { 0 }; + unz_file_info fileInfo = {0}; if (getCurrentFileInfo(&fileInfo, nullptr, 0, nullptr, 0, nullptr, 0) != UNZ_OK) { LOG(("Error: could not get current file info in a zip file.")); return QByteArray(); } auto size = fileInfo.uncompressed_size; - if (size > static_cast(fileSizeLimit)) { + if (size > static_cast(fileSizeLimit)) { if (_error == UNZ_OK) _error = -1; - LOG(("Error: current file is too large (should be less than %1, got %2) in a zip file.").arg(fileSizeLimit).arg(size)); + LOG(("Error: current file is too large (should be less than %1, got %2) in a zip file.") + .arg(fileSizeLimit) + .arg(size)); return QByteArray(); } if (openCurrentFile() != UNZ_OK) { @@ -304,7 +295,6 @@ class FileToRead { internal::InMemoryFile _data; unzFile _handle = nullptr; int _error = 0; - }; class FileToWrite { @@ -316,35 +306,18 @@ class FileToWrite { } } - int openNewFile( - const char *filename, - const zip_fileinfo *zipfi, - const void *extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level - ) { + int openNewFile(const char *filename, const zip_fileinfo *zipfi, const void *extrafield_local, + uInt size_extrafield_local, const void *extrafield_global, uInt size_extrafield_global, + const char *comment, int method, int level) { if (error() == ZIP_OK) { - _error = _handle ? zipOpenNewFileInZip( - _handle, - filename, - zipfi, - extrafield_local, - size_extrafield_local, - extrafield_global, - size_extrafield_global, - comment, - method, - level - ) : -1; + _error = _handle ? zipOpenNewFileInZip(_handle, filename, zipfi, extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, comment, method, level) : + -1; } return error(); } - int writeInFile(const void* buf, unsigned len) { + int writeInFile(const void *buf, unsigned len) { if (error() == ZIP_OK) { _error = _handle ? zipWriteInFileInZip(_handle, buf, len) : -1; } @@ -384,7 +357,6 @@ class FileToWrite { internal::InMemoryFile _data; zipFile _handle = nullptr; int _error = 0; - }; } // namespace zlib diff --git a/Telegram/SourceFiles/boxes/about_box.cpp b/Telegram/SourceFiles/boxes/about_box.cpp index 6f2ed8504..6d88a88ac 100644 --- a/Telegram/SourceFiles/boxes/about_box.cpp +++ b/Telegram/SourceFiles/boxes/about_box.cpp @@ -1,54 +1,61 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/about_box.h" +#include +#include "application.h" +#include "boxes/confirm_box.h" +#include "config.h" #include "lang/lang_keys.h" #include "mainwidget.h" #include "mainwindow.h" -#include "autoupdater.h" -#include "boxes/confirm_box.h" -#include "application.h" +#include "platform/platform_file_utilities.h" +#include "styles/style_boxes.h" #include "ui/widgets/buttons.h" #include "ui/widgets/labels.h" -#include "styles/style_boxes.h" -#include "platform/platform_file_utilities.h" AboutBox::AboutBox(QWidget *parent) -: _version(this, lng_about_version(lt_version, QString::fromLatin1(AppVersionStr.c_str()) + (cAlphaVersion() ? " alpha" : "") + (cBetaVersion() ? qsl(" beta %1").arg(cBetaVersion()) : QString())), st::aboutVersionLink) -, _text1(this, lang(lng_about_text_1), Ui::FlatLabel::InitType::Rich, st::aboutLabel) -, _text2(this, lang(lng_about_text_2), Ui::FlatLabel::InitType::Rich, st::aboutLabel) -, _text3(this, st::aboutLabel) { -} + : _version(this, + lng_about_version(lt_version, QString::fromLatin1(AppVersionStr.c_str()) + + (cAlphaVersion() ? " alpha" : "") + + (cBetaVersion() ? qsl(" beta %1").arg(cBetaVersion()) : QString())), + st::aboutVersionLink) + , _text1(this, lang(lng_about_text_1), Ui::FlatLabel::InitType::Rich, st::aboutLabel) + , _text2(this, lang(lng_about_text_2), Ui::FlatLabel::InitType::Rich, st::aboutLabel) + , _text3(this, st::aboutLabel) {} void AboutBox::prepare() { - constexpr auto test = std::is_convertible::value; - setTitle([] { return qsl("Telegram Desktop"); }); + setTitle([] { return str_const_toString(AppName); }); addButton(langFactory(lng_close), [this] { closeBox(); }); - _text3->setRichText(lng_about_text_3(lt_faq_open, qsl("[a href=\"%1\"]").arg(telegramFaqLink()), lt_faq_close, qsl("[/a]"))); + _text3->setRichText( + lng_about_text_3(lt_faq_open, qsl("[a href=\"%1\"]").arg(telegramFaqLink()), lt_faq_close, qsl("[/a]"))); _version->setClickedCallback([this] { showVersionHistory(); }); - setDimensions(st::aboutWidth, st::aboutTextTop + _text1->height() + st::aboutSkip + _text2->height() + st::aboutSkip + _text3->height()); + setDimensions(st::aboutWidth, st::aboutTextTop + _text1->height() + st::aboutSkip + _text2->height() + + st::aboutSkip + _text3->height()); } void AboutBox::resizeEvent(QResizeEvent *e) { @@ -61,23 +68,7 @@ void AboutBox::resizeEvent(QResizeEvent *e) { } void AboutBox::showVersionHistory() { - if (cRealBetaVersion()) { - auto url = qsl("https://tdesktop.com/"); - switch (cPlatform()) { - case dbipWindows: url += qsl("win/%1.zip"); break; - case dbipMac: url += qsl("mac/%1.zip"); break; - case dbipMacOld: url += qsl("mac32/%1.zip"); break; - case dbipLinux32: url += qsl("linux32/%1.tar.xz"); break; - case dbipLinux64: url += qsl("linux/%1.tar.xz"); break; - } - url = url.arg(qsl("tbeta%1_%2").arg(cRealBetaVersion()).arg(countBetaVersionSignature(cRealBetaVersion()))); - - Application::clipboard()->setText(url); - - Ui::show(Box("The link to the current private beta version of Telegram Desktop was copied to the clipboard.")); - } else { - QDesktopServices::openUrl(qsl("https://desktop.telegram.org/changelog")); - } + QDesktopServices::openUrl(lang(lng_url_changelog)); } void AboutBox::keyPressEvent(QKeyEvent *e) { @@ -91,7 +82,7 @@ void AboutBox::keyPressEvent(QKeyEvent *e) { QString telegramFaqLink() { auto result = qsl("https://telegram.org/faq"); auto language = Lang::Current().id(); - for (auto faqLanguage : { "de", "es", "it", "ko", "br" }) { + for (auto faqLanguage : {"de", "es", "it", "ko", "br"}) { if (language.startsWith(QLatin1String(faqLanguage))) { result.append('/').append(faqLanguage); } diff --git a/Telegram/SourceFiles/boxes/about_box.h b/Telegram/SourceFiles/boxes/about_box.h index 624eab40c..69fb52abb 100644 --- a/Telegram/SourceFiles/boxes/about_box.h +++ b/Telegram/SourceFiles/boxes/about_box.h @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "boxes/abstract_box.h" @@ -29,7 +31,7 @@ class FlatLabel; class AboutBox : public BoxContent { public: - AboutBox(QWidget*); + AboutBox(QWidget *); protected: void prepare() override; @@ -44,7 +46,6 @@ class AboutBox : public BoxContent { object_ptr _text1; object_ptr _text2; object_ptr _text3; - }; QString telegramFaqLink(); diff --git a/Telegram/SourceFiles/boxes/abstract_box.cpp b/Telegram/SourceFiles/boxes/abstract_box.cpp index 91dd88f7c..1fca80504 100644 --- a/Telegram/SourceFiles/boxes/abstract_box.cpp +++ b/Telegram/SourceFiles/boxes/abstract_box.cpp @@ -1,41 +1,44 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/abstract_box.h" +#include +#include "lang/lang_keys.h" +#include "mainwidget.h" +#include "mainwindow.h" +#include "storage/localstorage.h" #include "styles/style_boxes.h" #include "styles/style_profile.h" -#include "storage/localstorage.h" -#include "lang/lang_keys.h" #include "ui/effects/widget_fade_wrap.h" #include "ui/widgets/buttons.h" -#include "ui/widgets/scroll_area.h" #include "ui/widgets/labels.h" -#include "mainwidget.h" -#include "mainwindow.h" +#include "ui/widgets/scroll_area.h" -QPointer BoxContent::addButton(base::lambda textFactory, base::lambda clickCallback) { +QPointer BoxContent::addButton(Fn textFactory, Fn clickCallback) { return addButton(std::move(textFactory), std::move(clickCallback), st::defaultBoxButton); } -QPointer BoxContent::addLeftButton(base::lambda textFactory, base::lambda clickCallback) { +QPointer BoxContent::addLeftButton(Fn textFactory, Fn clickCallback) { return getDelegate()->addLeftButton(std::move(textFactory), std::move(clickCallback), st::defaultBoxButton); } @@ -104,12 +107,13 @@ void BoxContent::onDraggingScrollDelta(int delta) { } void BoxContent::onDraggingScrollTimer() { - auto delta = (_draggingScrollDelta > 0) ? qMin(_draggingScrollDelta * 3 / 20 + 1, int32(MaxScrollSpeed)) : qMax(_draggingScrollDelta * 3 / 20 - 1, -int32(MaxScrollSpeed)); + auto delta = (_draggingScrollDelta > 0) ? std::min(_draggingScrollDelta * 3 / 20 + 1, qint32(MaxScrollSpeed)) : + std::max(_draggingScrollDelta * 3 / 20 - 1, -qint32(MaxScrollSpeed)); _scroll->scrollToY(_scroll->scrollTop() + delta); } void BoxContent::updateInnerVisibleTopBottom() { - if (auto widget = static_cast(_scroll ? _scroll->widget() : nullptr)) { + if (auto widget = static_cast(_scroll ? _scroll->widget() : nullptr)) { auto top = _scroll->scrollTop(); widget->setVisibleTopBottom(top, top + _scroll->height()); } @@ -209,9 +213,10 @@ void BoxContent::paintEvent(QPaintEvent *e) { } } -AbstractBox::AbstractBox(QWidget *parent, Window::Controller *controller, object_ptr content) : LayerWidget(parent) -, _controller(controller) -, _content(std::move(content)) { +AbstractBox::AbstractBox(QWidget *parent, Window::Controller *controller, object_ptr content) + : LayerWidget(parent) + , _controller(controller) + , _content(std::move(content)) { subscribe(Lang::Current().updated(), [this] { refreshLang(); }); _content->setParent(this); _content->setDelegate(this); @@ -262,7 +267,9 @@ void AbstractBox::paintEvent(QPaintEvent *e) { void AbstractBox::paintAdditionalTitle(Painter &p) { p.setFont(st::boxLayerTitleAdditionalFont); p.setPen(st::boxTitleAdditionalFg); - p.drawTextLeft(_titleLeft + (_title ? _title->width() : 0) + st::boxLayerTitleAdditionalSkip, _titleTop + st::boxTitleFont->ascent - st::boxLayerTitleAdditionalFont->ascent, width(), _additionalTitle); + p.drawTextLeft(_titleLeft + (_title ? _title->width() : 0) + st::boxLayerTitleAdditionalSkip, + _titleTop + st::boxTitleFont->ascent - st::boxLayerTitleAdditionalFont->ascent, width(), + _additionalTitle); } void AbstractBox::parentResized() { @@ -272,7 +279,7 @@ void AbstractBox::parentResized() { update(); } -void AbstractBox::setTitle(base::lambda titleFactory) { +void AbstractBox::setTitle(Fn titleFactory) { _titleFactory = std::move(titleFactory); refreshTitle(); } @@ -293,7 +300,7 @@ void AbstractBox::refreshTitle() { } } -void AbstractBox::setAdditionalTitle(base::lambda additionalFactory) { +void AbstractBox::setAdditionalTitle(Fn additionalFactory) { _additionalTitleFactory = std::move(additionalFactory); refreshAdditionalTitle(); } @@ -336,7 +343,7 @@ void AbstractBox::updateTitlePosition() { _titleLeft = _layerType ? st::boxLayerTitlePosition.x() : st::boxTitlePosition.x(); _titleTop = _layerType ? st::boxLayerTitlePosition.y() : st::boxTitlePosition.y(); if (_title) { - _title->resizeToWidth(qMin(_title->naturalWidth(), width() - _titleLeft * 2)); + _title->resizeToWidth(std::min(_title->naturalWidth(), width() - _titleLeft * 2)); _title->moveToLeft(_titleLeft, _titleTop); } } @@ -348,7 +355,8 @@ void AbstractBox::clearButtons() { _leftButton.destroy(); } -QPointer AbstractBox::addButton(base::lambda textFactory, base::lambda clickCallback, const style::RoundButton &st) { +QPointer AbstractBox::addButton(Fn textFactory, Fn clickCallback, + const style::RoundButton &st) { _buttons.push_back(object_ptr(this, std::move(textFactory), st)); auto result = QPointer(_buttons.back()); result->setClickedCallback(std::move(clickCallback)); @@ -357,7 +365,8 @@ QPointer AbstractBox::addButton(base::lambda textFac return result; } -QPointer AbstractBox::addLeftButton(base::lambda textFactory, base::lambda clickCallback, const style::RoundButton &st) { +QPointer AbstractBox::addLeftButton(Fn textFactory, Fn clickCallback, + const style::RoundButton &st) { _leftButton = object_ptr(this, std::move(textFactory), st); auto result = QPointer(_leftButton); result->setClickedCallback(std::move(clickCallback)); @@ -378,7 +387,8 @@ void AbstractBox::setDimensions(int newWidth, int maxHeight) { auto newGeometry = geometry(); auto parentHeight = parentWidget()->height(); if (newGeometry.top() + newGeometry.height() + st::boxVerticalMargin > parentHeight) { - auto newTop = qMax(parentHeight - int(st::boxVerticalMargin) - newGeometry.height(), (parentHeight - newGeometry.height()) / 2); + auto newTop = std::max(parentHeight - int(st::boxVerticalMargin) - newGeometry.height(), + (parentHeight - newGeometry.height()) / 2); if (newTop != newGeometry.top()) { move(newGeometry.left(), newTop); } @@ -391,7 +401,7 @@ void AbstractBox::setDimensions(int newWidth, int maxHeight) { } int AbstractBox::countRealHeight() const { - return qMin(_fullHeight, parentWidget()->height() - 2 * st::boxVerticalMargin); + return std::min(_fullHeight, parentWidget()->height() - 2 * st::boxVerticalMargin); } int AbstractBox::countFullHeight() const { @@ -421,11 +431,11 @@ void AbstractBox::keyPressEvent(QKeyEvent *e) { } } -BoxLayerTitleShadow::BoxLayerTitleShadow(QWidget *parent) : Ui::PlainShadow(parent, st::boxLayerTitleShadow) { -} +BoxLayerTitleShadow::BoxLayerTitleShadow(QWidget *parent) + : Ui::PlainShadow(parent, st::boxLayerTitleShadow) {} -BoxContentDivider::BoxContentDivider(QWidget *parent) : TWidget(parent) { -} +BoxContentDivider::BoxContentDivider(QWidget *parent) + : TWidget(parent) {} int BoxContentDivider::resizeGetHeight(int newWidth) { return st::rightsDividerHeight; @@ -436,6 +446,7 @@ void BoxContentDivider::paintEvent(QPaintEvent *e) { p.fillRect(e->rect(), st::contactsAboutBg); auto dividerFillTop = myrtlrect(0, 0, width(), st::profileDividerTop.height()); st::profileDividerTop.fill(p, dividerFillTop); - auto dividerFillBottom = myrtlrect(0, height() - st::profileDividerBottom.height(), width(), st::profileDividerBottom.height()); + auto dividerFillBottom = + myrtlrect(0, height() - st::profileDividerBottom.height(), width(), st::profileDividerBottom.height()); st::profileDividerBottom.fill(p, dividerFillBottom); } diff --git a/Telegram/SourceFiles/boxes/abstract_box.h b/Telegram/SourceFiles/boxes/abstract_box.h index 90a3b2775..faa1bd4c7 100644 --- a/Telegram/SourceFiles/boxes/abstract_box.h +++ b/Telegram/SourceFiles/boxes/abstract_box.h @@ -1,26 +1,31 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once +#include "base/observer.h" #include "layerwidget.h" +#include "ui/text/text_entity.h" +#include "ui/twidget.h" #include "ui/widgets/shadow.h" namespace Ui { @@ -28,8 +33,7 @@ class RoundButton; class IconButton; class ScrollArea; class FlatLabel; -template -class WidgetFadeWrap; +template class WidgetFadeWrap; } // namespace Ui namespace Window { @@ -43,19 +47,20 @@ class BoxContentDelegate { virtual Window::Controller *controller() const = 0; virtual void setLayerType(bool layerType) = 0; - virtual void setTitle(base::lambda titleFactory) = 0; - virtual void setAdditionalTitle(base::lambda additionalFactory) = 0; + virtual void setTitle(Fn titleFactory) = 0; + virtual void setAdditionalTitle(Fn additionalFactory) = 0; virtual void clearButtons() = 0; - virtual QPointer addButton(base::lambda textFactory, base::lambda clickCallback, const style::RoundButton &st) = 0; - virtual QPointer addLeftButton(base::lambda textFactory, base::lambda clickCallback, const style::RoundButton &st) = 0; + virtual QPointer addButton(Fn textFactory, Fn clickCallback, + const style::RoundButton &st) = 0; + virtual QPointer addLeftButton(Fn textFactory, Fn clickCallback, + const style::RoundButton &st) = 0; virtual void updateButtonsPositions() = 0; virtual void setDimensions(int newWidth, int maxHeight) = 0; virtual void setNoContentMargin(bool noContentMargin) = 0; virtual bool isBoxShown() const = 0; virtual void closeBox() = 0; - }; class BoxContent : public TWidget, protected base::Subscriber { @@ -73,26 +78,27 @@ class BoxContent : public TWidget, protected base::Subscriber { getDelegate()->closeBox(); } - void setTitle(base::lambda titleFactory) { + void setTitle(Fn titleFactory) { if (titleFactory) { - getDelegate()->setTitle([titleFactory] { return TextWithEntities { titleFactory(), EntitiesInText() }; }); + getDelegate()->setTitle([titleFactory] { return TextWithEntities{titleFactory(), EntitiesInText()}; }); } else { - getDelegate()->setTitle(base::lambda()); + getDelegate()->setTitle(Fn()); } } - void setTitle(base::lambda titleFactory) { + void setTitle(Fn titleFactory) { getDelegate()->setTitle(std::move(titleFactory)); } - void setAdditionalTitle(base::lambda additional) { + void setAdditionalTitle(Fn additional) { getDelegate()->setAdditionalTitle(std::move(additional)); } void clearButtons() { getDelegate()->clearButtons(); } - QPointer addButton(base::lambda textFactory, base::lambda clickCallback); - QPointer addLeftButton(base::lambda textFactory, base::lambda clickCallback); - QPointer addButton(base::lambda textFactory, base::lambda clickCallback, const style::RoundButton &st) { + QPointer addButton(Fn textFactory, Fn clickCallback); + QPointer addLeftButton(Fn textFactory, Fn clickCallback); + QPointer addButton(Fn textFactory, Fn clickCallback, + const style::RoundButton &st) { return getDelegate()->addButton(std::move(textFactory), std::move(clickCallback), st); } void updateButtonsGeometry() { @@ -148,16 +154,14 @@ public slots: return result; } - template - QPointer setInnerWidget(object_ptr inner, int topSkip = 0) { + template QPointer setInnerWidget(object_ptr inner, int topSkip = 0) { auto result = QPointer(inner.data()); setInnerTopSkip(topSkip); setInner(std::move(inner)); return result; } - template - object_ptr takeInnerWidget() { + template object_ptr takeInnerWidget() { return static_object_cast(doTakeInnerWidget()); } @@ -192,13 +196,12 @@ private slots: bool _preparing = false; bool _noContentMargin = false; int _innerTopSkip = 0; - object_ptr _scroll = { nullptr }; - object_ptr> _topShadow = { nullptr }; - object_ptr> _bottomShadow = { nullptr }; + object_ptr _scroll = {nullptr}; + object_ptr> _topShadow = {nullptr}; + object_ptr> _bottomShadow = {nullptr}; - object_ptr _draggingScrollTimer = { nullptr }; + object_ptr _draggingScrollTimer = {nullptr}; int _draggingScrollDelta = 0; - }; class AbstractBox : public LayerWidget, public BoxContentDelegate, protected base::Subscriber { @@ -211,12 +214,14 @@ class AbstractBox : public LayerWidget, public BoxContentDelegate, protected bas void parentResized() override; void setLayerType(bool layerType) override; - void setTitle(base::lambda titleFactory) override; - void setAdditionalTitle(base::lambda additionalFactory) override; + void setTitle(Fn titleFactory) override; + void setAdditionalTitle(Fn additionalFactory) override; void clearButtons() override; - QPointer addButton(base::lambda textFactory, base::lambda clickCallback, const style::RoundButton &st) override; - QPointer addLeftButton(base::lambda textFactory, base::lambda clickCallback, const style::RoundButton &st) override; + QPointer addButton(Fn textFactory, Fn clickCallback, + const style::RoundButton &st) override; + QPointer addLeftButton(Fn textFactory, Fn clickCallback, + const style::RoundButton &st) override; void updateButtonsPositions() override; void setDimensions(int newWidth, int maxHeight) override; @@ -270,23 +275,21 @@ class AbstractBox : public LayerWidget, public BoxContentDelegate, protected bas int _maxContentHeight = 0; object_ptr _content; - object_ptr _title = { nullptr }; - base::lambda _titleFactory; + object_ptr _title = {nullptr}; + Fn _titleFactory; QString _additionalTitle; - base::lambda _additionalTitleFactory; + Fn _additionalTitleFactory; int _titleLeft = 0; int _titleTop = 0; bool _layerType = false; std::vector> _buttons; - object_ptr _leftButton = { nullptr }; - + object_ptr _leftButton = {nullptr}; }; class BoxLayerTitleShadow : public Ui::PlainShadow { public: BoxLayerTitleShadow(QWidget *parent); - }; class BoxContentDivider : public TWidget { @@ -296,7 +299,6 @@ class BoxContentDivider : public TWidget { protected: int resizeGetHeight(int newWidth) override; void paintEvent(QPaintEvent *e) override; - }; enum CreatingGroupType { diff --git a/Telegram/SourceFiles/boxes/add_contact_box.cpp b/Telegram/SourceFiles/boxes/add_contact_box.cpp index 04d1a890e..07585b712 100644 --- a/Telegram/SourceFiles/boxes/add_contact_box.cpp +++ b/Telegram/SourceFiles/boxes/add_contact_box.cpp @@ -1,46 +1,50 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/add_contact_box.h" -#include "styles/style_boxes.h" -#include "styles/style_dialogs.h" -#include "lang/lang_keys.h" -#include "messenger.h" -#include "mtproto/sender.h" +#include "apiwrap.h" +#include "auth_session.h" #include "base/flat_set.h" #include "boxes/confirm_box.h" -#include "boxes/photo_crop_box.h" #include "boxes/peer_list_controllers.h" +#include "boxes/photo_crop_box.h" #include "core/file_utilities.h" -#include "ui/widgets/checkbox.h" -#include "ui/widgets/buttons.h" -#include "ui/widgets/input_fields.h" -#include "ui/widgets/labels.h" -#include "ui/toast/toast.h" -#include "ui/special_buttons.h" +#include "lang/lang_keys.h" #include "mainwidget.h" #include "mainwindow.h" -#include "apiwrap.h" +#include "messenger.h" +#include "mtproto/sender.h" #include "observer_peer.h" -#include "auth_session.h" +#include "styles/style_boxes.h" +#include "styles/style_dialogs.h" +#include "ui/special_buttons.h" +#include "ui/toast/toast.h" +#include "ui/widgets/buttons.h" +#include "ui/widgets/checkbox.h" +#include "ui/widgets/input_fields.h" +#include "ui/widgets/labels.h" +#include +#include namespace { @@ -57,9 +61,7 @@ style::InputField CreateBioFieldStyle() { } // namespace QString PeerFloodErrorText(PeerFloodType type) { - auto link = textcmdLink( - Messenger::Instance().createInternalLinkFull(qsl("spambot")), - lang(lng_cant_more_info)); + auto link = textcmdLink(Messenger::Instance().createInternalLinkFull(qsl("spambot")), lang(lng_cant_more_info)); if (type == PeerFloodType::InviteGroup) { return lng_cant_invite_not_contact(lt_more_info, link); } @@ -68,7 +70,7 @@ QString PeerFloodErrorText(PeerFloodType type) { class RevokePublicLinkBox::Inner : public TWidget, private MTP::Sender { public: - Inner(QWidget *parent, base::lambda revokeCallback); + Inner(QWidget *parent, Fn revokeCallback); protected: void mouseMoveEvent(QMouseEvent *e) override; @@ -78,10 +80,10 @@ class RevokePublicLinkBox::Inner : public TWidget, private MTP::Sender { private: struct ChatRow { - ChatRow(not_null peer) : peer(peer) { - } + ChatRow(not_null peer) + : peer(peer) {} - not_null peer; + not_null peer; Text name, status; }; void paintChat(Painter &p, const ChatRow &row, bool selected) const; @@ -96,28 +98,27 @@ class RevokePublicLinkBox::Inner : public TWidget, private MTP::Sender { int _rowHeight = 0; int _revokeWidth = 0; - base::lambda _revokeCallback; + Fn _revokeCallback; mtpRequestId _revokeRequestId = 0; QPointer _weakRevokeConfirmBox; - }; -AddContactBox::AddContactBox(QWidget*, QString fname, QString lname, QString phone) -: _first(this, st::defaultInputField, langFactory(lng_signup_firstname), fname) -, _last(this, st::defaultInputField, langFactory(lng_signup_lastname), lname) -, _phone(this, st::defaultInputField, langFactory(lng_contact_phone), phone) -, _invertOrder(langFirstNameGoesSecond()) { +AddContactBox::AddContactBox(QWidget *, QString fname, QString lname, QString phone) + : _first(this, st::defaultInputField, langFactory(lng_signup_firstname), fname) + , _last(this, st::defaultInputField, langFactory(lng_signup_lastname), lname) + , _phone(this, st::defaultInputField, langFactory(lng_contact_phone), phone) + , _invertOrder(langFirstNameGoesSecond()) { if (!phone.isEmpty()) { _phone->setDisabled(true); } } -AddContactBox::AddContactBox(QWidget*, UserData *user) -: _user(user) -, _first(this, st::defaultInputField, langFactory(lng_signup_firstname), user->firstName) -, _last(this, st::defaultInputField, langFactory(lng_signup_lastname), user->lastName) -, _phone(this, st::defaultInputField, langFactory(lng_contact_phone), user->phone()) -, _invertOrder(langFirstNameGoesSecond()) { +AddContactBox::AddContactBox(QWidget *, UserData *user) + : _user(user) + , _first(this, st::defaultInputField, langFactory(lng_signup_firstname), user->firstName) + , _last(this, st::defaultInputField, langFactory(lng_signup_lastname), user->lastName) + , _phone(this, st::defaultInputField, langFactory(lng_contact_phone), user->phone()) + , _invertOrder(langFirstNameGoesSecond()) { _phone->setDisabled(true); } @@ -128,7 +129,8 @@ void AddContactBox::prepare() { if (_user) { setTitle(langFactory(lng_edit_contact_title)); } else { - auto readyToAdd = !_phone->getLastText().isEmpty() && (!_first->getLastText().isEmpty() || !_last->getLastText().isEmpty()); + auto readyToAdd = + !_phone->getLastText().isEmpty() && (!_first->getLastText().isEmpty() || !_last->getLastText().isEmpty()); setTitle(langFactory(readyToAdd ? lng_confirm_contact_data : lng_enter_contact_data)); } updateButtons(); @@ -137,7 +139,9 @@ void AddContactBox::prepare() { connect(_last, SIGNAL(submitted(bool)), this, SLOT(onSubmit())); connect(_phone, SIGNAL(submitted(bool)), this, SLOT(onSubmit())); - setDimensions(st::boxWideWidth, st::contactPadding.top() + _first->height() + st::contactSkip + _last->height() + st::contactPhoneSkip + _phone->height() + st::contactPadding.bottom() + st::boxPadding.bottom()); + setDimensions(st::boxWideWidth, st::contactPadding.top() + _first->height() + st::contactSkip + _last->height() + + st::contactPhoneSkip + _phone->height() + st::contactPadding.bottom() + + st::boxPadding.bottom()); } void AddContactBox::setInnerFocus() { @@ -157,7 +161,9 @@ void AddContactBox::paintEvent(QPaintEvent *e) { p.setPen(st::boxTextFg); p.setFont(st::boxTextFont); auto textHeight = height() - st::contactPadding.top() - st::contactPadding.bottom() - st::boxPadding.bottom(); - p.drawText(QRect(st::boxPadding.left(), st::contactPadding.top(), width() - st::boxPadding.left() - st::boxPadding.right(), textHeight), lng_contact_not_joined(lt_name, _sentName), style::al_topleft); + p.drawText(QRect(st::boxPadding.left(), st::contactPadding.top(), + width() - st::boxPadding.left() - st::boxPadding.right(), textHeight), + lng_contact_not_joined(lt_name, _sentName), style::al_topleft); } else { st::contactUserIcon.paint(p, st::boxPadding.left(), _first->y() + st::contactIconTop, width()); st::contactPhoneIcon.paint(p, st::boxPadding.left(), _phone->y() + st::contactIconTop, width()); @@ -167,17 +173,22 @@ void AddContactBox::paintEvent(QPaintEvent *e) { void AddContactBox::resizeEvent(QResizeEvent *e) { BoxContent::resizeEvent(e); - _first->resize(width() - st::boxPadding.left() - st::contactPadding.left() - st::boxPadding.right(), _first->height()); + _first->resize(width() - st::boxPadding.left() - st::contactPadding.left() - st::boxPadding.right(), + _first->height()); _last->resize(_first->width(), _last->height()); _phone->resize(_first->width(), _last->height()); if (_invertOrder) { _last->moveToLeft(st::boxPadding.left() + st::contactPadding.left(), st::contactPadding.top()); - _first->moveToLeft(st::boxPadding.left() + st::contactPadding.left(), _last->y() + _last->height() + st::contactSkip); - _phone->moveToLeft(st::boxPadding.left() + st::contactPadding.left(), _first->y() + _first->height() + st::contactPhoneSkip); + _first->moveToLeft(st::boxPadding.left() + st::contactPadding.left(), + _last->y() + _last->height() + st::contactSkip); + _phone->moveToLeft(st::boxPadding.left() + st::contactPadding.left(), + _first->y() + _first->height() + st::contactPhoneSkip); } else { _first->moveToLeft(st::boxPadding.left() + st::contactPadding.left(), st::contactPadding.top()); - _last->moveToLeft(st::boxPadding.left() + st::contactPadding.left(), _first->y() + _first->height() + st::contactSkip); - _phone->moveToLeft(st::boxPadding.left() + st::contactPadding.left(), _last->y() + _last->height() + st::contactPhoneSkip); + _last->moveToLeft(st::boxPadding.left() + st::contactPadding.left(), + _first->y() + _first->height() + st::contactSkip); + _phone->moveToLeft(st::boxPadding.left() + st::contactPadding.left(), + _last->y() + _last->height() + st::contactPhoneSkip); } } @@ -221,13 +232,17 @@ void AddContactBox::onSave() { } _sentName = firstName; if (_user) { - _contactId = rand_value(); - QVector v(1, MTP_inputPhoneContact(MTP_long(_contactId), MTP_string(_user->phone()), MTP_string(firstName), MTP_string(lastName))); - _addRequest = MTP::send(MTPcontacts_ImportContacts(MTP_vector(v)), rpcDone(&AddContactBox::onSaveUserDone), rpcFail(&AddContactBox::onSaveUserFail)); + _contactId = rand_value(); + QVector v(1, MTP_inputPhoneContact(MTP_long(_contactId), MTP_string(_user->phone()), + MTP_string(firstName), MTP_string(lastName))); + _addRequest = MTP::send(MTPcontacts_ImportContacts(MTP_vector(v)), + rpcDone(&AddContactBox::onSaveUserDone), rpcFail(&AddContactBox::onSaveUserFail)); } else { - _contactId = rand_value(); - QVector v(1, MTP_inputPhoneContact(MTP_long(_contactId), MTP_string(phone), MTP_string(firstName), MTP_string(lastName))); - _addRequest = MTP::send(MTPcontacts_ImportContacts(MTP_vector(v)), rpcDone(&AddContactBox::onImportDone)); + _contactId = rand_value(); + QVector v(1, MTP_inputPhoneContact(MTP_long(_contactId), MTP_string(phone), + MTP_string(firstName), MTP_string(lastName))); + _addRequest = MTP::send(MTPcontacts_ImportContacts(MTP_vector(v)), + rpcDone(&AddContactBox::onImportDone)); } } @@ -305,12 +320,12 @@ void AddContactBox::updateButtons() { } } -GroupInfoBox::GroupInfoBox(QWidget*, CreatingGroupType creating, bool fromTypeChoose) -: _creating(creating) -, _fromTypeChoose(fromTypeChoose) -, _photo(this, st::newGroupPhotoSize, st::newGroupPhotoIconPosition) -, _title(this, st::defaultInputField, langFactory(_creating == CreatingGroupChannel ? lng_dlg_new_channel_name : lng_dlg_new_group_name)) { -} +GroupInfoBox::GroupInfoBox(QWidget *, CreatingGroupType creating, bool fromTypeChoose) + : _creating(creating) + , _fromTypeChoose(fromTypeChoose) + , _photo(this, st::newGroupPhotoSize, st::newGroupPhotoIconPosition) + , _title(this, st::defaultInputField, + langFactory(_creating == CreatingGroupChannel ? lng_dlg_new_channel_name : lng_dlg_new_group_name)) {} void GroupInfoBox::prepare() { setMouseTracking(true); @@ -329,7 +344,8 @@ void GroupInfoBox::prepare() { connect(_title, SIGNAL(submitted(bool)), this, SLOT(onNameSubmit())); - addButton(langFactory(_creating == CreatingGroupChannel ? lng_create_group_create : lng_create_group_next), [this] { onNext(); }); + addButton(langFactory(_creating == CreatingGroupChannel ? lng_create_group_create : lng_create_group_next), + [this] { onNext(); }); addButton(langFactory(_fromTypeChoose ? lng_create_group_back : lng_cancel), [this] { closeBox(); }); setupPhotoButton(); @@ -341,23 +357,26 @@ void GroupInfoBox::setupPhotoButton() { _photo->setClickedCallback(App::LambdaDelayed(st::defaultActiveButton.ripple.hideDuration, this, [this] { auto imgExtensions = cImgExtensions(); auto filter = qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;") + FileDialog::AllFilesFilter(); - FileDialog::GetOpenPath(lang(lng_choose_image), filter, base::lambda_guarded(this, [this](const FileDialog::OpenResult &result) { - if (result.remoteContent.isEmpty() && result.paths.isEmpty()) { - return; - } - - QImage img; - if (!result.remoteContent.isEmpty()) { - img = App::readImage(result.remoteContent); - } else { - img = App::readImage(result.paths.front()); - } - if (img.isNull() || img.width() > 10 * img.height() || img.height() > 10 * img.width()) { - return; - } - auto box = Ui::show(Box(img, (_creating == CreatingGroupChannel) ? peerFromChannel(0) : peerFromChat(0)), KeepOtherLayers); - connect(box, SIGNAL(ready(const QImage&)), this, SLOT(onPhotoReady(const QImage&))); - })); + FileDialog::GetOpenPath( + lang(lng_choose_image), filter, base::lambda_guarded(this, [this](const FileDialog::OpenResult &result) { + if (result.remoteContent.isEmpty() && result.paths.isEmpty()) { + return; + } + + QImage img; + if (!result.remoteContent.isEmpty()) { + img = App::readImage(result.remoteContent); + } else { + img = App::readImage(result.paths.front()); + } + if (img.isNull() || img.width() > 10 * img.height() || img.height() > 10 * img.width()) { + return; + } + auto box = Ui::show( + Box(img, (_creating == CreatingGroupChannel) ? peerFromChannel(0) : peerFromChat(0)), + KeepOtherLayers); + connect(box, SIGNAL(ready(const QImage &)), this, SLOT(onPhotoReady(const QImage &))); + })); })); } @@ -368,14 +387,20 @@ void GroupInfoBox::setInnerFocus() { void GroupInfoBox::resizeEvent(QResizeEvent *e) { BoxContent::resizeEvent(e); - _photo->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::boxPadding.top() + st::newGroupInfoPadding.top()); + _photo->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), + st::boxPadding.top() + st::newGroupInfoPadding.top()); auto nameLeft = st::newGroupPhotoSize + st::newGroupNamePosition.x(); - _title->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right() - nameLeft, _title->height()); - _title->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left() + nameLeft, st::boxPadding.top() + st::newGroupInfoPadding.top() + st::newGroupNamePosition.y()); + _title->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right() - nameLeft, + _title->height()); + _title->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left() + nameLeft, + st::boxPadding.top() + st::newGroupInfoPadding.top() + st::newGroupNamePosition.y()); if (_description) { - _description->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right(), _description->height()); - _description->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::boxPadding.top() + st::newGroupInfoPadding.top() + st::newGroupPhotoSize + st::newGroupDescriptionPadding.top()); + _description->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right(), + _description->height()); + _description->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), + st::boxPadding.top() + st::newGroupInfoPadding.top() + st::newGroupPhotoSize + + st::newGroupDescriptionPadding.top()); } } @@ -390,7 +415,8 @@ void GroupInfoBox::onNameSubmit() { } } -void GroupInfoBox::createGroup(not_null selectUsersBox, const QString &title, const std::vector> &users) { +void GroupInfoBox::createGroup(not_null selectUsersBox, const QString &title, + const std::vector> &users) { if (_creationRequestId) return; auto inputs = QVector(); @@ -402,61 +428,61 @@ void GroupInfoBox::createGroup(not_null selectUsersBox, const QStr inputs.push_back(user->inputUser); } } - _creationRequestId = request(MTPmessages_CreateChat(MTP_vector(inputs), MTP_string(title))).done([this](const MTPUpdates &result) { - Ui::hideLayer(); - - App::main()->sentUpdatesReceived(result); - - auto success = base::make_optional(&result) - | [](auto updates) -> base::optional*> { - switch (updates->type()) { - case mtpc_updates: - return &updates->c_updates().vchats.v; - case mtpc_updatesCombined: - return &updates->c_updatesCombined().vchats.v; - } - LOG(("API Error: unexpected update cons %1 (GroupInfoBox::creationDone)").arg(updates->type())); - return base::none; - } - | [](auto chats) { - return (!chats->empty() && chats->front().type() == mtpc_chat) - ? base::make_optional(chats) - : base::none; - } - | [](auto chats) { - return App::chat(chats->front().c_chat().vid.v); - } - | [this](not_null chat) { - if (!_photoImage.isNull()) { - Messenger::Instance().uploadProfilePhoto(_photoImage, chat->id); - } - Ui::showPeerHistory(chat, ShowAtUnreadMsgId); - }; - if (!success) { - LOG(("API Error: chat not found in updates (ContactsBox::creationDone)")); - } - }).fail([this, selectUsersBox](const RPCError &error) { - _creationRequestId = 0; - if (error.type() == qstr("NO_CHAT_TITLE")) { - auto guard = weak(this); - selectUsersBox->closeBox(); - if (guard) { - _title->showError(); - } - } else if (error.type() == qstr("USERS_TOO_FEW")) { - } else if (error.type() == qstr("PEER_FLOOD")) { - Ui::show(Box(PeerFloodErrorText(PeerFloodType::InviteGroup)), KeepOtherLayers); - } else if (error.type() == qstr("USER_RESTRICTED")) { - Ui::show(Box(lang(lng_cant_do_this)), KeepOtherLayers); - } - }).send(); + _creationRequestId = + request(MTPmessages_CreateChat(MTP_vector(inputs), MTP_string(title))) + .done([this](const MTPUpdates &result) { + Ui::hideLayer(); + + App::main()->sentUpdatesReceived(result); + + auto success = + base::make_optional(&result) | [](auto updates) -> base::optional *> { + switch (updates->type()) { + case mtpc_updates: return &updates->c_updates().vchats.v; + case mtpc_updatesCombined: return &updates->c_updatesCombined().vchats.v; + } + LOG(("API Error: unexpected update cons %1 (GroupInfoBox::creationDone)").arg(updates->type())); + return base::none; + } | [](auto chats) { + return (!chats->empty() && chats->front().type() == mtpc_chat) ? base::make_optional(chats) : + base::none; + } | [](auto chats) { + return App::chat(chats->front().c_chat().vid.v); + } | [this](not_null chat) { + if (!_photoImage.isNull()) { + Messenger::Instance().uploadProfilePhoto(_photoImage, chat->id); + } + Ui::showPeerHistory(chat, ShowAtUnreadMsgId); + }; + if (!success) { + LOG(("API Error: chat not found in updates (ContactsBox::creationDone)")); + } + }) + .fail([this, selectUsersBox](const RPCError &error) { + _creationRequestId = 0; + if (error.type() == qstr("NO_CHAT_TITLE")) { + auto guard = weak(this); + selectUsersBox->closeBox(); + if (guard) { + _title->showError(); + } + } else if (error.type() == qstr("USERS_TOO_FEW")) { + } else if (error.type() == qstr("PEER_FLOOD")) { + Ui::show(Box(PeerFloodErrorText(PeerFloodType::InviteGroup)), KeepOtherLayers); + } else if (error.type() == qstr("USER_RESTRICTED")) { + Ui::show(Box(lang(lng_cant_do_this)), KeepOtherLayers); + } + }) + .send(); } void GroupInfoBox::onNext() { if (_creationRequestId) return; auto title = TextUtilities::PrepareForSending(_title->getLastText()); - auto description = _description ? TextUtilities::PrepareForSending(_description->getLastText(), TextUtilities::PrepareTextOption::CheckLinks) : QString(); + auto description = _description ? TextUtilities::PrepareForSending(_description->getLastText(), + TextUtilities::PrepareTextOption::CheckLinks) : + QString(); if (title.isEmpty()) { _title->setFocus(); _title->showError(); @@ -465,7 +491,7 @@ void GroupInfoBox::onNext() { if (_creating != CreatingGroupGroup) { createChannel(title, description); } else { - auto initBox = [title, weak = weak(this)](not_null box) { + auto initBox = [title, weak = weak(this)](not_null box) { box->addButton(langFactory(lng_create_group_create), [box, title, weak] { if (weak) { auto rows = box->peerListCollectSelectedRows(); @@ -476,68 +502,65 @@ void GroupInfoBox::onNext() { }); box->addButton(langFactory(lng_cancel), [box] { box->closeBox(); }); }; - Ui::show(Box(std::make_unique(nullptr), std::move(initBox)), KeepOtherLayers); + Ui::show(Box(std::make_unique(nullptr), std::move(initBox)), + KeepOtherLayers); } } void GroupInfoBox::createChannel(const QString &title, const QString &description) { bool mega = false; auto flags = mega ? MTPchannels_CreateChannel::Flag::f_megagroup : MTPchannels_CreateChannel::Flag::f_broadcast; - _creationRequestId = request(MTPchannels_CreateChannel(MTP_flags(flags), MTP_string(title), MTP_string(description))).done([this](const MTPUpdates &result) { - App::main()->sentUpdatesReceived(result); - - auto success = base::make_optional(&result) - | [](auto updates) -> base::optional*> { - switch (updates->type()) { - case mtpc_updates: - return &updates->c_updates().vchats.v; - case mtpc_updatesCombined: - return &updates->c_updatesCombined().vchats.v; - } - LOG(("API Error: unexpected update cons %1 (GroupInfoBox::createChannel)").arg(updates->type())); - return base::none; - } - | [](auto chats) { - return (!chats->empty() && chats->front().type() == mtpc_channel) - ? base::make_optional(chats) - : base::none; - } - | [](auto chats) { - return App::channel(chats->front().c_channel().vid.v); - } - | [this](not_null channel) { - if (!_photoImage.isNull()) { - Messenger::Instance().uploadProfilePhoto( - _photoImage, - channel->id); - } - _createdChannel = channel; - _creationRequestId = request( - MTPchannels_ExportInvite(_createdChannel->inputChannel) - ).done([this](const MTPExportedChatInvite &result) { - _creationRequestId = 0; - if (result.type() == mtpc_chatInviteExported) { - auto link = qs(result.c_chatInviteExported().vlink); - _createdChannel->setInviteLink(link); - } - Ui::show(Box(_createdChannel)); - }).send(); - }; - if (!success) { - LOG(("API Error: channel not found in updates (GroupInfoBox::creationDone)")); - closeBox(); - } - }).fail([this](const RPCError &error) { - _creationRequestId = 0; - if (error.type() == "NO_CHAT_TITLE") { - _title->setFocus(); - _title->showError(); - } else if (error.type() == qstr("USER_RESTRICTED")) { - Ui::show(Box(lang(lng_cant_do_this))); - } else if (error.type() == qstr("CHANNELS_TOO_MUCH")) { - Ui::show(Box(lang(lng_cant_do_this))); // TODO - } - }).send(); + _creationRequestId = + request(MTPchannels_CreateChannel(MTP_flags(flags), MTP_string(title), MTP_string(description))) + .done([this](const MTPUpdates &result) { + App::main()->sentUpdatesReceived(result); + + auto success = + base::make_optional(&result) | [](auto updates) -> base::optional *> { + switch (updates->type()) { + case mtpc_updates: return &updates->c_updates().vchats.v; + case mtpc_updatesCombined: return &updates->c_updatesCombined().vchats.v; + } + LOG(("API Error: unexpected update cons %1 (GroupInfoBox::createChannel)").arg(updates->type())); + return base::none; + } | [](auto chats) { + return (!chats->empty() && chats->front().type() == mtpc_channel) ? base::make_optional(chats) : + base::none; + } | [](auto chats) { + return App::channel(chats->front().c_channel().vid.v); + } | [this](not_null channel) { + if (!_photoImage.isNull()) { + Messenger::Instance().uploadProfilePhoto(_photoImage, channel->id); + } + _createdChannel = channel; + _creationRequestId = request(MTPchannels_ExportInvite(_createdChannel->inputChannel)) + .done([this](const MTPExportedChatInvite &result) { + _creationRequestId = 0; + if (result.type() == mtpc_chatInviteExported) { + auto link = qs(result.c_chatInviteExported().vlink); + _createdChannel->setInviteLink(link); + } + Ui::show(Box(_createdChannel)); + }) + .send(); + }; + if (!success) { + LOG(("API Error: channel not found in updates (GroupInfoBox::creationDone)")); + closeBox(); + } + }) + .fail([this](const RPCError &error) { + _creationRequestId = 0; + if (error.type() == "NO_CHAT_TITLE") { + _title->setFocus(); + _title->showError(); + } else if (error.type() == qstr("USER_RESTRICTED")) { + Ui::show(Box(lang(lng_cant_do_this))); + } else if (error.type() == qstr("CHANNELS_TOO_MUCH")) { + Ui::show(Box(lang(lng_cant_do_this))); // TODO + } + }) + .send(); } void GroupInfoBox::onDescriptionResized() { @@ -546,9 +569,11 @@ void GroupInfoBox::onDescriptionResized() { } void GroupInfoBox::updateMaxHeight() { - auto newHeight = st::boxPadding.top() + st::newGroupInfoPadding.top() + st::newGroupPhotoSize + st::boxPadding.bottom() + st::newGroupInfoPadding.bottom(); + auto newHeight = st::boxPadding.top() + st::newGroupInfoPadding.top() + st::newGroupPhotoSize + + st::boxPadding.bottom() + st::newGroupInfoPadding.bottom(); if (_description) { - newHeight += st::newGroupDescriptionPadding.top() + _description->height() + st::newGroupDescriptionPadding.bottom(); + newHeight += + st::newGroupDescriptionPadding.top() + _description->height() + st::newGroupDescriptionPadding.bottom(); } setDimensions(st::boxWideWidth, newHeight); } @@ -558,24 +583,34 @@ void GroupInfoBox::onPhotoReady(const QImage &img) { _photo->setImage(_photoImage); } -SetupChannelBox::SetupChannelBox(QWidget*, ChannelData *channel, bool existing) -: _channel(channel) -, _existing(existing) -, _privacyGroup(std::make_shared>(Privacy::Public)) -, _public(this, _privacyGroup, Privacy::Public, lang(channel->isMegagroup() ? lng_create_public_group_title : lng_create_public_channel_title), st::defaultBoxCheckbox) -, _private(this, _privacyGroup, Privacy::Private, lang(channel->isMegagroup() ? lng_create_private_group_title : lng_create_private_channel_title), st::defaultBoxCheckbox) -, _aboutPublicWidth(st::boxWideWidth - st::boxPadding.left() - st::boxButtonPadding.right() - st::newGroupPadding.left() - st::defaultRadio.diameter - st::defaultBoxCheckbox.textPosition.x()) -, _aboutPublic(st::defaultTextStyle, lang(channel->isMegagroup() ? lng_create_public_group_about : lng_create_public_channel_about), _defaultOptions, _aboutPublicWidth) -, _aboutPrivate(st::defaultTextStyle, lang(channel->isMegagroup() ? lng_create_private_group_about : lng_create_private_channel_about), _defaultOptions, _aboutPublicWidth) -, _link(this, st::setupChannelLink, base::lambda(), channel->username, true) { -} +SetupChannelBox::SetupChannelBox(QWidget *, ChannelData *channel, bool existing) + : _channel(channel) + , _existing(existing) + , _privacyGroup(std::make_shared>(Privacy::Public)) + , _public(this, _privacyGroup, Privacy::Public, + lang(channel->isMegagroup() ? lng_create_public_group_title : lng_create_public_channel_title), + st::defaultBoxCheckbox) + , _private(this, _privacyGroup, Privacy::Private, + lang(channel->isMegagroup() ? lng_create_private_group_title : lng_create_private_channel_title), + st::defaultBoxCheckbox) + , _aboutPublicWidth(st::boxWideWidth - st::boxPadding.left() - st::boxButtonPadding.right() - + st::newGroupPadding.left() - st::defaultRadio.diameter - + st::defaultBoxCheckbox.textPosition.x()) + , _aboutPublic(st::defaultTextStyle, + lang(channel->isMegagroup() ? lng_create_public_group_about : lng_create_public_channel_about), + _defaultOptions, _aboutPublicWidth) + , _aboutPrivate(st::defaultTextStyle, + lang(channel->isMegagroup() ? lng_create_private_group_about : lng_create_private_channel_about), + _defaultOptions, _aboutPublicWidth) + , _link(this, st::setupChannelLink, Fn(), channel->username, true) {} void SetupChannelBox::prepare() { _aboutPublicHeight = _aboutPublic.countHeight(_aboutPublicWidth); setMouseTracking(true); - _checkRequestId = MTP::send(MTPchannels_CheckUsername(_channel->inputChannel, MTP_string("preston")), RPCDoneHandlerPtr(), rpcFail(&SetupChannelBox::onFirstCheckFail)); + _checkRequestId = MTP::send(MTPchannels_CheckUsername(_channel->inputChannel, MTP_string("preston")), + RPCDoneHandlerPtr(), rpcFail(&SetupChannelBox::onFirstCheckFail)); addButton(langFactory(lng_settings_save), [this] { onSave(); }); addButton(langFactory(_existing ? lng_cancel : lng_create_group_skip), [this] { closeBox(); }); @@ -587,11 +622,12 @@ void SetupChannelBox::prepare() { connect(&_checkTimer, SIGNAL(timeout()), this, SLOT(onCheck())); _privacyGroup->setChangedCallback([this](Privacy value) { privacyChanged(value); }); - subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(Notify::PeerUpdate::Flag::InviteLinkChanged, [this](const Notify::PeerUpdate &update) { - if (update.peer == _channel) { - rtlupdate(_invitationLink); - } - })); + subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(Notify::PeerUpdate::Flag::InviteLinkChanged, + [this](const Notify::PeerUpdate &update) { + if (update.peer == _channel) { + rtlupdate(_invitationLink); + } + })); subscribe(boxClosing, [this] { if (!_existing) { AddParticipantsBoxController::Start(_channel); @@ -610,7 +646,9 @@ void SetupChannelBox::setInnerFocus() { } void SetupChannelBox::updateMaxHeight() { - auto newHeight = st::boxPadding.top() + st::newGroupPadding.top() + _public->heightNoMargins() + _aboutPublicHeight + st::newGroupSkip + _private->heightNoMargins() + _aboutPrivate.countHeight(_aboutPublicWidth) + st::newGroupSkip + st::newGroupPadding.bottom(); + auto newHeight = st::boxPadding.top() + st::newGroupPadding.top() + _public->heightNoMargins() + + _aboutPublicHeight + st::newGroupSkip + _private->heightNoMargins() + + _aboutPrivate.countHeight(_aboutPublicWidth) + st::newGroupSkip + st::newGroupPadding.bottom(); if (!_channel->isMegagroup() || _privacyGroup->value() == Privacy::Public) { newHeight += st::newGroupLinkPadding.top() + _link->height() + st::newGroupLinkPadding.bottom(); } @@ -638,16 +676,22 @@ void SetupChannelBox::paintEvent(QPaintEvent *e) { p.fillRect(e->rect(), st::boxBg); p.setPen(st::newGroupAboutFg); - QRect aboutPublic(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultRadio.diameter + st::defaultBoxCheckbox.textPosition.x(), _public->bottomNoMargins(), _aboutPublicWidth, _aboutPublicHeight); + QRect aboutPublic(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultRadio.diameter + + st::defaultBoxCheckbox.textPosition.x(), + _public->bottomNoMargins(), _aboutPublicWidth, _aboutPublicHeight); _aboutPublic.drawLeft(p, aboutPublic.x(), aboutPublic.y(), aboutPublic.width(), width()); - QRect aboutPrivate(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultRadio.diameter + st::defaultBoxCheckbox.textPosition.x(), _private->bottomNoMargins(), _aboutPublicWidth, _aboutPublicHeight); + QRect aboutPrivate(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultRadio.diameter + + st::defaultBoxCheckbox.textPosition.x(), + _private->bottomNoMargins(), _aboutPublicWidth, _aboutPublicHeight); _aboutPrivate.drawLeft(p, aboutPrivate.x(), aboutPrivate.y(), aboutPrivate.width(), width()); if (!_channel->isMegagroup() || !_link->isHidden()) { p.setPen(st::boxTextFg); p.setFont(st::newGroupLinkFont); - p.drawTextLeft(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultInputField.textMargins.left(), _link->y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop, width(), lang(_link->isHidden() ? lng_create_group_invite_link : lng_create_group_link)); + p.drawTextLeft(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultInputField.textMargins.left(), + _link->y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop, width(), + lang(_link->isHidden() ? lng_create_group_invite_link : lng_create_group_link)); } if (_link->isHidden()) { @@ -656,18 +700,25 @@ void SetupChannelBox::paintEvent(QPaintEvent *e) { option.setWrapMode(QTextOption::WrapAnywhere); p.setFont(_linkOver ? st::boxTextFont->underline() : st::boxTextFont); p.setPen(st::defaultLinkButton.color); - auto inviteLinkText = _channel->inviteLink().isEmpty() ? lang(lng_group_invite_create) : _channel->inviteLink(); + auto inviteLinkText = + _channel->inviteLink().isEmpty() ? lang(lng_group_invite_create) : _channel->inviteLink(); p.drawText(_invitationLink, inviteLinkText, option); } } else { if (!_errorText.isEmpty()) { p.setPen(st::boxTextFgError); p.setFont(st::boxTextFont); - p.drawTextRight(st::boxPadding.right(), _link->y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::boxTextFont->ascent, width(), _errorText); + p.drawTextRight(st::boxPadding.right(), + _link->y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + + st::newGroupLinkFont->ascent - st::boxTextFont->ascent, + width(), _errorText); } else if (!_goodText.isEmpty()) { p.setPen(st::boxTextFgGood); p.setFont(st::boxTextFont); - p.drawTextRight(st::boxPadding.right(), _link->y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::boxTextFont->ascent, width(), _goodText); + p.drawTextRight(st::boxPadding.right(), + _link->y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + + st::newGroupLinkFont->ascent - st::boxTextFont->ascent, + width(), _goodText); } } } @@ -675,12 +726,18 @@ void SetupChannelBox::paintEvent(QPaintEvent *e) { void SetupChannelBox::resizeEvent(QResizeEvent *e) { BoxContent::resizeEvent(e); - _public->moveToLeft(st::boxPadding.left() + st::newGroupPadding.left(), st::boxPadding.top() + st::newGroupPadding.top()); - _private->moveToLeft(st::boxPadding.left() + st::newGroupPadding.left(), _public->bottomNoMargins() + _aboutPublicHeight + st::newGroupSkip); + _public->moveToLeft(st::boxPadding.left() + st::newGroupPadding.left(), + st::boxPadding.top() + st::newGroupPadding.top()); + _private->moveToLeft(st::boxPadding.left() + st::newGroupPadding.left(), + _public->bottomNoMargins() + _aboutPublicHeight + st::newGroupSkip); - _link->resize(width() - st::boxPadding.left() - st::newGroupLinkPadding.left() - st::boxPadding.right(), _link->height()); - _link->moveToLeft(st::boxPadding.left() + st::newGroupLinkPadding.left(), _private->bottomNoMargins() + _aboutPrivate.countHeight(_aboutPublicWidth) + st::newGroupSkip + st::newGroupPadding.bottom() + st::newGroupLinkPadding.top()); - _invitationLink = QRect(_link->x(), _link->y() + (_link->height() / 2) - st::boxTextFont->height, _link->width(), 2 * st::boxTextFont->height); + _link->resize(width() - st::boxPadding.left() - st::newGroupLinkPadding.left() - st::boxPadding.right(), + _link->height()); + _link->moveToLeft(st::boxPadding.left() + st::newGroupLinkPadding.left(), + _private->bottomNoMargins() + _aboutPrivate.countHeight(_aboutPublicWidth) + st::newGroupSkip + + st::newGroupPadding.bottom() + st::newGroupLinkPadding.top()); + _invitationLink = QRect(_link->x(), _link->y() + (_link->height() / 2) - st::boxTextFont->height, _link->width(), + 2 * st::boxTextFont->height); } void SetupChannelBox::mouseMoveEvent(QMouseEvent *e) { @@ -717,7 +774,9 @@ void SetupChannelBox::onSave() { if (_privacyGroup->value() == Privacy::Private) { if (_existing) { _sentUsername = QString(); - _saveRequestId = MTP::send(MTPchannels_UpdateUsername(_channel->inputChannel, MTP_string(_sentUsername)), rpcDone(&SetupChannelBox::onUpdateDone), rpcFail(&SetupChannelBox::onUpdateFail)); + _saveRequestId = + MTP::send(MTPchannels_UpdateUsername(_channel->inputChannel, MTP_string(_sentUsername)), + rpcDone(&SetupChannelBox::onUpdateDone), rpcFail(&SetupChannelBox::onUpdateFail)); } else { closeBox(); } @@ -733,7 +792,8 @@ void SetupChannelBox::onSave() { } _sentUsername = link; - _saveRequestId = MTP::send(MTPchannels_UpdateUsername(_channel->inputChannel, MTP_string(_sentUsername)), rpcDone(&SetupChannelBox::onUpdateDone), rpcFail(&SetupChannelBox::onUpdateFail)); + _saveRequestId = MTP::send(MTPchannels_UpdateUsername(_channel->inputChannel, MTP_string(_sentUsername)), + rpcDone(&SetupChannelBox::onUpdateDone), rpcFail(&SetupChannelBox::onUpdateFail)); } void SetupChannelBox::onChange() { @@ -745,8 +805,8 @@ void SetupChannelBox::onChange() { } _checkTimer.stop(); } else { - int32 len = name.size(); - for (int32 i = 0; i < len; ++i) { + qint32 len = name.size(); + for (qint32 i = 0; i < len; ++i) { QChar ch = name.at(i); if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z') && (ch < '0' || ch > '9') && ch != '_') { if (_errorText != lang(lng_create_channel_link_bad_symbols)) { @@ -780,7 +840,8 @@ void SetupChannelBox::onCheck() { QString link = _link->text().trimmed(); if (link.size() >= MinUsernameLength) { _checkUsername = link; - _checkRequestId = MTP::send(MTPchannels_CheckUsername(_channel->inputChannel, MTP_string(link)), rpcDone(&SetupChannelBox::onCheckDone), rpcFail(&SetupChannelBox::onCheckFail)); + _checkRequestId = MTP::send(MTPchannels_CheckUsername(_channel->inputChannel, MTP_string(link)), + rpcDone(&SetupChannelBox::onCheckDone), rpcFail(&SetupChannelBox::onCheckFail)); } } @@ -788,11 +849,13 @@ void SetupChannelBox::privacyChanged(Privacy value) { if (value == Privacy::Public) { if (_tooMuchUsernames) { _privacyGroup->setValue(Privacy::Private); - Ui::show(Box(base::lambda_guarded(this, [this] { - _tooMuchUsernames = false; - _privacyGroup->setValue(Privacy::Public); - onCheck(); - })), KeepOtherLayers); + Ui::show(Box(base::lambda_guarded(this, + [this] { + _tooMuchUsernames = false; + _privacyGroup->setValue(Privacy::Public); + onCheck(); + })), + KeepOtherLayers); return; } _link->show(); @@ -841,7 +904,9 @@ bool SetupChannelBox::onUpdateFail(const RPCError &error) { void SetupChannelBox::onCheckDone(const MTPBool &result) { _checkRequestId = 0; - QString newError = (mtpIsTrue(result) || _checkUsername == _channel->username) ? QString() : lang(lng_create_channel_link_occupied); + QString newError = (mtpIsTrue(result) || _checkUsername == _channel->username) ? + QString() : + lang(lng_create_channel_link_occupied); QString newGood = newError.isEmpty() ? lang(lng_create_channel_link_available) : QString(); if (_errorText != newError || _goodText != newGood) { _errorText = newError; @@ -883,8 +948,9 @@ bool SetupChannelBox::onCheckFail(const RPCError &error) { void SetupChannelBox::showRevokePublicLinkBoxForEdit() { closeBox(); Ui::show(Box([channel = _channel, existing = _existing]() { - Ui::show(Box(channel, existing), KeepOtherLayers); - }), KeepOtherLayers); + Ui::show(Box(channel, existing), KeepOtherLayers); + }), + KeepOtherLayers); } bool SetupChannelBox::onFirstCheckFail(const RPCError &error) { @@ -909,12 +975,13 @@ bool SetupChannelBox::onFirstCheckFail(const RPCError &error) { return true; } -EditNameTitleBox::EditNameTitleBox(QWidget*, not_null peer) -: _peer(peer) -, _first(this, st::defaultInputField, langFactory(_peer->isUser() ? lng_signup_firstname : lng_dlg_new_group_name), _peer->isUser() ? _peer->asUser()->firstName : _peer->name) -, _last(this, st::defaultInputField, langFactory(lng_signup_lastname), peer->isUser() ? peer->asUser()->lastName : QString()) -, _invertOrder(!peer->isChat() && langFirstNameGoesSecond()) { -} +EditNameTitleBox::EditNameTitleBox(QWidget *, not_null peer) + : _peer(peer) + , _first(this, st::defaultInputField, langFactory(_peer->isUser() ? lng_signup_firstname : lng_dlg_new_group_name), + _peer->isUser() ? _peer->asUser()->firstName : _peer->name) + , _last(this, st::defaultInputField, langFactory(lng_signup_lastname), + peer->isUser() ? peer->asUser()->lastName : QString()) + , _invertOrder(!peer->isChat() && langFirstNameGoesSecond()) {} void EditNameTitleBox::prepare() { auto newHeight = st::contactPadding.top() + _first->height(); @@ -972,14 +1039,17 @@ void EditNameTitleBox::onSubmit() { void EditNameTitleBox::resizeEvent(QResizeEvent *e) { BoxContent::resizeEvent(e); - _first->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right(), _first->height()); + _first->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right(), + _first->height()); _last->resize(_first->size()); if (_invertOrder) { _last->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::contactPadding.top()); - _first->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _last->y() + _last->height() + st::contactSkip); + _first->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), + _last->y() + _last->height() + st::contactSkip); } else { _first->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::contactPadding.top()); - _last->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _first->y() + _first->height() + st::contactSkip); + _last->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), + _first->y() + _first->height() + st::contactSkip); } } @@ -1005,9 +1075,12 @@ void EditNameTitleBox::onSave() { _sentName = first; if (_peer == App::self()) { auto flags = MTPaccount_UpdateProfile::Flag::f_first_name | MTPaccount_UpdateProfile::Flag::f_last_name; - _requestId = MTP::send(MTPaccount_UpdateProfile(MTP_flags(flags), MTP_string(first), MTP_string(last), MTPstring()), rpcDone(&EditNameTitleBox::onSaveSelfDone), rpcFail(&EditNameTitleBox::onSaveSelfFail)); + _requestId = + MTP::send(MTPaccount_UpdateProfile(MTP_flags(flags), MTP_string(first), MTP_string(last), MTPstring()), + rpcDone(&EditNameTitleBox::onSaveSelfDone), rpcFail(&EditNameTitleBox::onSaveSelfFail)); } else if (_peer->isChat()) { - _requestId = MTP::send(MTPmessages_EditChatTitle(_peer->asChat()->inputChat, MTP_string(first)), rpcDone(&EditNameTitleBox::onSaveChatDone), rpcFail(&EditNameTitleBox::onSaveChatFail)); + _requestId = MTP::send(MTPmessages_EditChatTitle(_peer->asChat()->inputChat, MTP_string(first)), + rpcDone(&EditNameTitleBox::onSaveChatDone), rpcFail(&EditNameTitleBox::onSaveChatFail)); } } @@ -1064,13 +1137,13 @@ void EditNameTitleBox::onSaveChatDone(const MTPUpdates &updates) { closeBox(); } -EditBioBox::EditBioBox(QWidget*, not_null self) : BoxContent() -, _dynamicFieldStyle(CreateBioFieldStyle()) -, _self(self) -, _bio(this, _dynamicFieldStyle, langFactory(lng_bio_placeholder), _self->about()) -, _countdown(this, QString(), Ui::FlatLabel::InitType::Simple, st::editBioCountdownLabel) -, _about(this, lang(lng_bio_about), Ui::FlatLabel::InitType::Simple, st::aboutRevokePublicLabel) { -} +EditBioBox::EditBioBox(QWidget *, not_null self) + : BoxContent() + , _dynamicFieldStyle(CreateBioFieldStyle()) + , _self(self) + , _bio(this, _dynamicFieldStyle, langFactory(lng_bio_placeholder), _self->about()) + , _countdown(this, QString(), Ui::FlatLabel::InitType::Simple, st::editBioCountdownLabel) + , _about(this, lang(lng_bio_about), Ui::FlatLabel::InitType::Simple, st::aboutRevokePublicLabel) {} void EditBioBox::prepare() { setTitle(langFactory(lng_bio_title)); @@ -1090,7 +1163,8 @@ void EditBioBox::prepare() { } void EditBioBox::updateMaxHeight() { - auto newHeight = st::contactPadding.top() + _bio->height() + st::boxLittleSkip + _about->height() + st::boxPadding.bottom() + st::contactPadding.bottom(); + auto newHeight = st::contactPadding.top() + _bio->height() + st::boxLittleSkip + _about->height() + + st::boxPadding.bottom() + st::contactPadding.bottom(); setDimensions(st::boxWideWidth, newHeight); } @@ -1103,7 +1177,7 @@ void EditBioBox::handleBioUpdated() { cursor.setPosition(position); _bio->setTextCursor(cursor); } - auto countLeft = qMax(kMaxBioLength - text.size(), 0); + auto countLeft = std::max(kMaxBioLength - text.size(), 0); _countdown->setText(QString::number(countLeft)); } @@ -1114,7 +1188,8 @@ void EditBioBox::setInnerFocus() { void EditBioBox::resizeEvent(QResizeEvent *e) { BoxContent::resizeEvent(e); - _bio->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right(), _bio->height()); + _bio->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right(), + _bio->height()); _bio->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::contactPadding.top()); _countdown->moveToRight(st::boxPadding.right(), _bio->y() + _dynamicFieldStyle.textMargins.top()); _about->moveToLeft(st::boxPadding.left(), _bio->y() + _bio->height() + st::boxLittleSkip); @@ -1127,23 +1202,27 @@ void EditBioBox::save() { _sentBio = text; auto flags = MTPaccount_UpdateProfile::Flag::f_about; - _requestId = request(MTPaccount_UpdateProfile(MTP_flags(flags), MTPstring(), MTPstring(), MTP_string(text))).done([this](const MTPUser &result) { - App::feedUsers(MTP_vector(1, result)); - _self->setAbout(_sentBio); - closeBox(); - }).send(); -} - -EditChannelBox::EditChannelBox(QWidget*, not_null channel) -: _channel(channel) -, _title(this, st::defaultInputField, langFactory(_channel->isMegagroup() ? lng_dlg_new_group_name : lng_dlg_new_channel_name), _channel->name) -, _description(this, st::newGroupDescription, langFactory(lng_create_group_description), _channel->about()) -, _sign(this, lang(lng_edit_sign_messages), channel->addsSignature(), st::defaultBoxCheckbox) -, _inviteGroup(std::make_shared>(channel->anyoneCanAddMembers() ? Invites::Everybody : Invites::OnlyAdmins)) -, _inviteEverybody(this, _inviteGroup, Invites::Everybody, lang(lng_edit_group_invites_everybody)) -, _inviteOnlyAdmins(this, _inviteGroup, Invites::OnlyAdmins, lang(lng_edit_group_invites_only_admins)) -, _publicLink(this, lang(channel->isPublic() ? lng_profile_edit_public_link : lng_profile_create_public_link), st::boxLinkButton) { -} + _requestId = request(MTPaccount_UpdateProfile(MTP_flags(flags), MTPstring(), MTPstring(), MTP_string(text))) + .done([this](const MTPUser &result) { + App::feedUsers(MTP_vector(1, result)); + _self->setAbout(_sentBio); + closeBox(); + }) + .send(); +} + +EditChannelBox::EditChannelBox(QWidget *, not_null channel) + : _channel(channel) + , _title(this, st::defaultInputField, + langFactory(_channel->isMegagroup() ? lng_dlg_new_group_name : lng_dlg_new_channel_name), _channel->name) + , _description(this, st::newGroupDescription, langFactory(lng_create_group_description), _channel->about()) + , _sign(this, lang(lng_edit_sign_messages), channel->addsSignature(), st::defaultBoxCheckbox) + , _inviteGroup(std::make_shared>(channel->anyoneCanAddMembers() ? Invites::Everybody : + Invites::OnlyAdmins)) + , _inviteEverybody(this, _inviteGroup, Invites::Everybody, lang(lng_edit_group_invites_everybody)) + , _inviteOnlyAdmins(this, _inviteGroup, Invites::OnlyAdmins, lang(lng_edit_group_invites_only_admins)) + , _publicLink(this, lang(channel->isPublic() ? lng_profile_edit_public_link : lng_profile_create_public_link), + st::boxLinkButton) {} void EditChannelBox::prepare() { setTitle(langFactory(_channel->isMegagroup() ? lng_edit_group : lng_edit_channel_title)); @@ -1151,11 +1230,12 @@ void EditChannelBox::prepare() { addButton(langFactory(lng_settings_save), [this] { onSave(); }); addButton(langFactory(lng_cancel), [this] { closeBox(); }); - subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(Notify::PeerUpdate::Flag::NameChanged, [this](const Notify::PeerUpdate &update) { - if (update.peer == _channel) { - handleChannelNameChange(); - } - })); + subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(Notify::PeerUpdate::Flag::NameChanged, + [this](const Notify::PeerUpdate &update) { + if (update.peer == _channel) { + handleChannelNameChange(); + } + })); setMouseTracking(true); @@ -1209,16 +1289,19 @@ bool EditChannelBox::canEditInvites() const { void EditChannelBox::updateMaxHeight() { auto newHeight = st::newGroupInfoPadding.top() + _title->height(); - newHeight += st::newGroupDescriptionPadding.top() + _description->height() + st::newGroupDescriptionPadding.bottom(); + newHeight += + st::newGroupDescriptionPadding.top() + _description->height() + st::newGroupDescriptionPadding.bottom(); if (canEditSignatures()) { - newHeight += st::newGroupPublicLinkPadding.top() + _sign->heightNoMargins() + st::newGroupPublicLinkPadding.bottom(); + newHeight += + st::newGroupPublicLinkPadding.top() + _sign->heightNoMargins() + st::newGroupPublicLinkPadding.bottom(); } if (canEditInvites()) { newHeight += st::boxTitleHeight + _inviteEverybody->heightNoMargins(); newHeight += st::boxLittleSkip + _inviteOnlyAdmins->heightNoMargins(); } if (_channel->canEditUsername()) { - newHeight += st::newGroupPublicLinkPadding.top() + _publicLink->height() + st::newGroupPublicLinkPadding.bottom(); + newHeight += + st::newGroupPublicLinkPadding.top() + _publicLink->height() + st::newGroupPublicLinkPadding.bottom(); } newHeight += st::boxPadding.bottom() + st::newGroupInfoPadding.bottom(); setDimensions(st::boxWideWidth, newHeight); @@ -1227,23 +1310,37 @@ void EditChannelBox::updateMaxHeight() { void EditChannelBox::resizeEvent(QResizeEvent *e) { BoxContent::resizeEvent(e); - _title->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right(), _title->height()); - _title->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::newGroupInfoPadding.top() + st::newGroupNamePosition.y()); + _title->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right(), + _title->height()); + _title->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), + st::newGroupInfoPadding.top() + st::newGroupNamePosition.y()); - _description->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right(), _description->height()); - _description->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _title->y() + _title->height() + st::newGroupDescriptionPadding.top()); + _description->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right(), + _description->height()); + _description->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), + _title->y() + _title->height() + st::newGroupDescriptionPadding.top()); - _sign->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _description->y() + _description->height() + st::newGroupDescriptionPadding.bottom() + st::newGroupPublicLinkPadding.top()); + _sign->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), + _description->y() + _description->height() + st::newGroupDescriptionPadding.bottom() + + st::newGroupPublicLinkPadding.top()); - _inviteEverybody->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _description->y() + _description->height() + st::boxTitleHeight); - _inviteOnlyAdmins->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _inviteEverybody->bottomNoMargins() + st::boxLittleSkip); + _inviteEverybody->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), + _description->y() + _description->height() + st::boxTitleHeight); + _inviteOnlyAdmins->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), + _inviteEverybody->bottomNoMargins() + st::boxLittleSkip); if (canEditSignatures()) { - _publicLink->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _sign->bottomNoMargins() + st::newGroupDescriptionPadding.bottom() + st::newGroupPublicLinkPadding.top()); + _publicLink->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), + _sign->bottomNoMargins() + st::newGroupDescriptionPadding.bottom() + + st::newGroupPublicLinkPadding.top()); } else if (canEditInvites()) { - _publicLink->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _inviteOnlyAdmins->bottomNoMargins() + st::newGroupDescriptionPadding.bottom() + st::newGroupPublicLinkPadding.top()); + _publicLink->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), + _inviteOnlyAdmins->bottomNoMargins() + st::newGroupDescriptionPadding.bottom() + + st::newGroupPublicLinkPadding.top()); } else { - _publicLink->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _description->y() + _description->height() + st::newGroupDescriptionPadding.bottom() + st::newGroupPublicLinkPadding.top()); + _publicLink->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), + _description->y() + _description->height() + st::newGroupDescriptionPadding.bottom() + + st::newGroupPublicLinkPadding.top()); } } @@ -1254,7 +1351,8 @@ void EditChannelBox::paintEvent(QPaintEvent *e) { Painter p(this); p.setPen(st::boxTitleFg); p.setFont(st::autoDownloadTitleFont); - p.drawTextLeft(st::boxTitlePosition.x(), _description->y() + _description->height() + st::boxTitlePosition.y(), width(), lang(lng_edit_group_who_invites)); + p.drawTextLeft(st::boxTitlePosition.x(), _description->y() + _description->height() + st::boxTitlePosition.y(), + width(), lang(lng_edit_group_who_invites)); } } @@ -1262,7 +1360,8 @@ void EditChannelBox::onSave() { if (_saveTitleRequestId || _saveDescriptionRequestId || _saveSignRequestId || _saveInvitesRequestId) return; auto title = TextUtilities::PrepareForSending(_title->getLastText()); - auto description = TextUtilities::PrepareForSending(_description->getLastText(), TextUtilities::PrepareTextOption::CheckLinks); + auto description = + TextUtilities::PrepareForSending(_description->getLastText(), TextUtilities::PrepareTextOption::CheckLinks); if (title.isEmpty()) { _title->setFocus(); _title->showError(); @@ -1273,7 +1372,9 @@ void EditChannelBox::onSave() { if (_sentTitle == _channel->name) { saveDescription(); } else { - _saveTitleRequestId = MTP::send(MTPchannels_EditTitle(_channel->inputChannel, MTP_string(_sentTitle)), rpcDone(&EditChannelBox::onSaveTitleDone), rpcFail(&EditChannelBox::onSaveFail)); + _saveTitleRequestId = + MTP::send(MTPchannels_EditTitle(_channel->inputChannel, MTP_string(_sentTitle)), + rpcDone(&EditChannelBox::onSaveTitleDone), rpcFail(&EditChannelBox::onSaveFail)); } } @@ -1285,7 +1386,9 @@ void EditChannelBox::saveDescription() { if (_sentDescription == _channel->about()) { saveSign(); } else { - _saveDescriptionRequestId = MTP::send(MTPchannels_EditAbout(_channel->inputChannel, MTP_string(_sentDescription)), rpcDone(&EditChannelBox::onSaveDescriptionDone), rpcFail(&EditChannelBox::onSaveFail)); + _saveDescriptionRequestId = + MTP::send(MTPchannels_EditAbout(_channel->inputChannel, MTP_string(_sentDescription)), + rpcDone(&EditChannelBox::onSaveDescriptionDone), rpcFail(&EditChannelBox::onSaveFail)); } } @@ -1293,7 +1396,8 @@ void EditChannelBox::saveSign() { if (!canEditSignatures() || _channel->addsSignature() == _sign->checked()) { saveInvites(); } else { - _saveSignRequestId = MTP::send(MTPchannels_ToggleSignatures(_channel->inputChannel, MTP_bool(_sign->checked())), rpcDone(&EditChannelBox::onSaveSignDone), rpcFail(&EditChannelBox::onSaveFail)); + _saveSignRequestId = MTP::send(MTPchannels_ToggleSignatures(_channel->inputChannel, MTP_bool(_sign->checked())), + rpcDone(&EditChannelBox::onSaveSignDone), rpcFail(&EditChannelBox::onSaveFail)); } } @@ -1301,7 +1405,9 @@ void EditChannelBox::saveInvites() { if (!canEditInvites() || _channel->anyoneCanAddMembers() == (_inviteGroup->value() == Invites::Everybody)) { closeBox(); } else { - _saveInvitesRequestId = MTP::send(MTPchannels_ToggleInvites(_channel->inputChannel, MTP_bool(_inviteGroup->value() == Invites::Everybody)), rpcDone(&EditChannelBox::onSaveInvitesDone), rpcFail(&EditChannelBox::onSaveFail)); + _saveInvitesRequestId = MTP::send( + MTPchannels_ToggleInvites(_channel->inputChannel, MTP_bool(_inviteGroup->value() == Invites::Everybody)), + rpcDone(&EditChannelBox::onSaveInvitesDone), rpcFail(&EditChannelBox::onSaveFail)); } } @@ -1375,48 +1481,55 @@ void EditChannelBox::onSaveInvitesDone(const MTPUpdates &result) { closeBox(); } -RevokePublicLinkBox::Inner::Inner(QWidget *parent, base::lambda revokeCallback) : TWidget(parent) -, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) -, _revokeWidth(st::normalFont->width(lang(lng_channels_too_much_public_revoke))) -, _revokeCallback(std::move(revokeCallback)) { +RevokePublicLinkBox::Inner::Inner(QWidget *parent, Fn revokeCallback) + : TWidget(parent) + , _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) + , _revokeWidth(st::normalFont->width(lang(lng_channels_too_much_public_revoke))) + , _revokeCallback(std::move(revokeCallback)) { setMouseTracking(true); resize(width(), 5 * _rowHeight); - request(MTPchannels_GetAdminedPublicChannels()).done([this](const MTPmessages_Chats &result) { - if (auto chats = Api::getChatsFromMessagesChats(result)) { - for_const (auto &chat, chats->v) { - if (auto peer = App::feedChat(chat)) { - if (!peer->isChannel() || peer->userName().isEmpty()) { - continue; - } - - auto row = ChatRow(peer); - row.peer = peer; - row.name.setText(st::contactsNameStyle, peer->name, _textNameOptions); - row.status.setText(st::defaultTextStyle, Messenger::Instance().createInternalLink(textcmdLink(1, peer->userName())), _textDlgOptions); - _rows.push_back(std::move(row)); - } - } - } - resize(width(), _rows.size() * _rowHeight); - update(); - }).send(); -} - -RevokePublicLinkBox::RevokePublicLinkBox(QWidget*, base::lambda revokeCallback) -: _aboutRevoke(this, lang(lng_channels_too_much_public_about), Ui::FlatLabel::InitType::Simple, st::aboutRevokePublicLabel) -, _revokeCallback(std::move(revokeCallback)) { -} + request(MTPchannels_GetAdminedPublicChannels()) + .done([this](const MTPmessages_Chats &result) { + if (auto chats = Api::getChatsFromMessagesChats(result)) { + for_const (auto &chat, chats->v) { + if (auto peer = App::feedChat(chat)) { + if (!peer->isChannel() || peer->userName().isEmpty()) { + continue; + } + + auto row = ChatRow(peer); + row.peer = peer; + row.name.setText(st::contactsNameStyle, peer->name, _textNameOptions); + row.status.setText(st::defaultTextStyle, + Messenger::Instance().createInternalLink(textcmdLink(1, peer->userName())), + _textDlgOptions); + _rows.push_back(std::move(row)); + } + } + } + resize(width(), _rows.size() * _rowHeight); + update(); + }) + .send(); +} + +RevokePublicLinkBox::RevokePublicLinkBox(QWidget *, Fn revokeCallback) + : _aboutRevoke(this, lang(lng_channels_too_much_public_about), Ui::FlatLabel::InitType::Simple, + st::aboutRevokePublicLabel) + , _revokeCallback(std::move(revokeCallback)) {} void RevokePublicLinkBox::prepare() { _innerTop = st::boxPadding.top() + _aboutRevoke->height() + st::boxPadding.top(); - _inner = setInnerWidget(object_ptr(this, [this] { - closeBox(); - if (_revokeCallback) { - _revokeCallback(); - } - }), st::boxLayerScroll, _innerTop); + _inner = setInnerWidget(object_ptr(this, + [this] { + closeBox(); + if (_revokeCallback) { + _revokeCallback(); + } + }), + st::boxLayerScroll, _innerTop); addButton(langFactory(lng_cancel), [this] { closeBox(); }); @@ -1435,7 +1548,10 @@ void RevokePublicLinkBox::Inner::updateSelected() { PeerData *selected = nullptr; auto top = _rowsTop; for_const (auto &row, _rows) { - auto revokeLink = rtlrect(width() - st::contactsPadding.right() - st::contactsCheckPosition.x() - _revokeWidth, top + st::contactsPadding.top() + (st::contactsPhotoSize - st::normalFont->height) / 2, _revokeWidth, st::normalFont->height, width()); + auto revokeLink = + rtlrect(width() - st::contactsPadding.right() - st::contactsCheckPosition.x() - _revokeWidth, + top + st::contactsPadding.top() + (st::contactsPhotoSize - st::normalFont->height) / 2, + _revokeWidth, st::normalFont->height, width()); if (revokeLink.contains(point)) { selected = row.peer; break; @@ -1460,20 +1576,31 @@ void RevokePublicLinkBox::Inner::mouseReleaseEvent(QMouseEvent *e) { auto pressed = base::take(_pressed); setCursor((_selected || _pressed) ? style::cur_pointer : style::cur_default); if (pressed && pressed == _selected) { - auto text_method = pressed->isMegagroup() ? lng_channels_too_much_public_revoke_confirm_group : lng_channels_too_much_public_revoke_confirm_channel; - auto text = text_method(lt_link, Messenger::Instance().createInternalLink(pressed->userName()), lt_group, pressed->name); + auto text_method = pressed->isMegagroup() ? lng_channels_too_much_public_revoke_confirm_group : + lng_channels_too_much_public_revoke_confirm_channel; + auto text = text_method(lt_link, Messenger::Instance().createInternalLink(pressed->userName()), lt_group, + pressed->name); auto confirmText = lang(lng_channels_too_much_public_revoke); - _weakRevokeConfirmBox = Ui::show(Box(text, confirmText, base::lambda_guarded(this, [this, pressed]() { - if (_revokeRequestId) return; - _revokeRequestId = request(MTPchannels_UpdateUsername(pressed->asChannel()->inputChannel, MTP_string(""))).done([this](const MTPBool &result) { - if (_weakRevokeConfirmBox) { - _weakRevokeConfirmBox->closeBox(); - } - if (_revokeCallback) { - _revokeCallback(); - } - }).send(); - })), KeepOtherLayers); + _weakRevokeConfirmBox = + Ui::show(Box(text, confirmText, + base::lambda_guarded(this, + [this, pressed]() { + if (_revokeRequestId) return; + _revokeRequestId = + request(MTPchannels_UpdateUsername( + pressed->asChannel()->inputChannel, + MTP_string(""))) + .done([this](const MTPBool &result) { + if (_weakRevokeConfirmBox) { + _weakRevokeConfirmBox->closeBox(); + } + if (_revokeCallback) { + _revokeCallback(); + } + }) + .send(); + })), + KeepOtherLayers); } } @@ -1498,18 +1625,21 @@ void RevokePublicLinkBox::Inner::paintChat(Painter &p, const ChatRow &row, bool p.setPen(st::contactsNameFg); - int32 namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left(); - int32 namew = width() - namex - st::contactsPadding.right() - (_revokeWidth + st::contactsCheckPosition.x() * 2); + qint32 namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left(); + qint32 namew = width() - namex - st::contactsPadding.right() - (_revokeWidth + st::contactsCheckPosition.x() * 2); if (peer->isVerified()) { auto icon = &st::dialogsVerifiedIcon; namew -= icon->width(); - icon->paint(p, namex + qMin(row.name.maxWidth(), namew), st::contactsPadding.top() + st::contactsNameTop, width()); + icon->paint(p, namex + std::min(row.name.maxWidth(), namew), st::contactsPadding.top() + st::contactsNameTop, + width()); } row.name.drawLeftElided(p, namex, st::contactsPadding.top() + st::contactsNameTop, namew, width()); p.setFont(selected ? st::linkOverFont : st::linkFont); p.setPen(selected ? st::defaultLinkButton.overColor : st::defaultLinkButton.color); - p.drawTextRight(st::contactsPadding.right() + st::contactsCheckPosition.x(), st::contactsPadding.top() + (st::contactsPhotoSize - st::normalFont->height) / 2, width(), lang(lng_channels_too_much_public_revoke), _revokeWidth); + p.drawTextRight(st::contactsPadding.right() + st::contactsCheckPosition.x(), + st::contactsPadding.top() + (st::contactsPhotoSize - st::normalFont->height) / 2, width(), + lang(lng_channels_too_much_public_revoke), _revokeWidth); p.setPen(st::contactsStatusFg); p.setTextPalette(st::revokePublicLinkStatusPalette); diff --git a/Telegram/SourceFiles/boxes/add_contact_box.h b/Telegram/SourceFiles/boxes/add_contact_box.h index c49e8f14f..ef7a6fa1f 100644 --- a/Telegram/SourceFiles/boxes/add_contact_box.h +++ b/Telegram/SourceFiles/boxes/add_contact_box.h @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "boxes/abstract_box.h" @@ -33,10 +35,8 @@ class PhoneInput; class InputArea; class UsernameInput; class Checkbox; -template -class RadioenumGroup; -template -class Radioenum; +template class RadioenumGroup; +template class Radioenum; class LinkButton; class NewAvatarButton; } // namespace Ui @@ -52,8 +52,8 @@ class AddContactBox : public BoxContent, public RPCSender { Q_OBJECT public: - AddContactBox(QWidget*, QString fname = QString(), QString lname = QString(), QString phone = QString()); - AddContactBox(QWidget*, UserData *user); + AddContactBox(QWidget *, QString fname = QString(), QString lname = QString(), QString phone = QString()); + AddContactBox(QWidget *, UserData *user); protected: void prepare() override; @@ -84,18 +84,17 @@ private slots: bool _retrying = false; bool _invertOrder = false; - uint64 _contactId = 0; + quint64 _contactId = 0; mtpRequestId _addRequest = 0; QString _sentName; - }; class GroupInfoBox : public BoxContent, private MTP::Sender { Q_OBJECT public: - GroupInfoBox(QWidget*, CreatingGroupType creating, bool fromTypeChoose); + GroupInfoBox(QWidget *, CreatingGroupType creating, bool fromTypeChoose); protected: void prepare() override; @@ -116,7 +115,8 @@ private slots: private: void setupPhotoButton(); void createChannel(const QString &title, const QString &description); - void createGroup(not_null selectUsersBox, const QString &title, const std::vector> &users); + void createGroup(not_null selectUsersBox, const QString &title, + const std::vector> &users); void updateMaxHeight(); void updateSelected(const QPoint &cursorGlobalPosition); @@ -126,21 +126,20 @@ private slots: object_ptr _photo; object_ptr _title; - object_ptr _description = { nullptr }; + object_ptr _description = {nullptr}; QImage _photoImage; // group / channel creation mtpRequestId _creationRequestId = 0; ChannelData *_createdChannel = nullptr; - }; class SetupChannelBox : public BoxContent, public RPCSender { Q_OBJECT public: - SetupChannelBox(QWidget*, ChannelData *channel, bool existing = false); + SetupChannelBox(QWidget *, ChannelData *channel, bool existing = false); void setInnerFocus() override; @@ -185,7 +184,7 @@ private slots: std::shared_ptr> _privacyGroup; object_ptr> _public; object_ptr> _private; - int32 _aboutPublicWidth, _aboutPublicHeight; + qint32 _aboutPublicWidth, _aboutPublicHeight; Text _aboutPublic, _aboutPrivate; object_ptr _link; @@ -199,14 +198,13 @@ private slots: QString _sentUsername, _checkUsername, _errorText, _goodText; QTimer _checkTimer; - }; class EditNameTitleBox : public BoxContent, public RPCSender { Q_OBJECT public: - EditNameTitleBox(QWidget*, not_null peer); + EditNameTitleBox(QWidget *, not_null peer); protected: void setInnerFocus() override; @@ -225,7 +223,7 @@ private slots: void onSaveChatDone(const MTPUpdates &updates); bool onSaveChatFail(const RPCError &e); - not_null _peer; + not_null _peer; object_ptr _first; object_ptr _last; @@ -234,12 +232,11 @@ private slots: mtpRequestId _requestId = 0; QString _sentName; - }; class EditBioBox : public BoxContent, private MTP::Sender { public: - EditBioBox(QWidget*, not_null self); + EditBioBox(QWidget *, not_null self); protected: void setInnerFocus() override; @@ -253,21 +250,20 @@ class EditBioBox : public BoxContent, private MTP::Sender { void save(); style::InputField _dynamicFieldStyle; - not_null _self; + not_null _self; object_ptr _bio; object_ptr _countdown; object_ptr _about; mtpRequestId _requestId = 0; QString _sentBio; - }; class EditChannelBox : public BoxContent, public RPCSender { Q_OBJECT public: - EditChannelBox(QWidget*, not_null channel); + EditChannelBox(QWidget *, not_null channel); protected: void prepare() override; @@ -301,7 +297,7 @@ private slots: void saveSign(); void saveInvites(); - not_null _channel; + not_null _channel; object_ptr _title; object_ptr _description; @@ -323,12 +319,11 @@ private slots: mtpRequestId _saveInvitesRequestId = 0; QString _sentTitle, _sentDescription; - }; class RevokePublicLinkBox : public BoxContent, public RPCSender { public: - RevokePublicLinkBox(QWidget*, base::lambda revokeCallback); + RevokePublicLinkBox(QWidget *, Fn revokeCallback); protected: void prepare() override; @@ -342,6 +337,5 @@ class RevokePublicLinkBox : public BoxContent, public RPCSender { QPointer _inner; int _innerTop = 0; - base::lambda _revokeCallback; - + Fn _revokeCallback; }; diff --git a/Telegram/SourceFiles/boxes/autolock_box.cpp b/Telegram/SourceFiles/boxes/autolock_box.cpp index c0a1d1af5..cdc09b4b9 100644 --- a/Telegram/SourceFiles/boxes/autolock_box.cpp +++ b/Telegram/SourceFiles/boxes/autolock_box.cpp @@ -1,50 +1,57 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/autolock_box.h" +#include "facades.h" #include "lang/lang_keys.h" -#include "storage/localstorage.h" #include "mainwindow.h" -#include "ui/widgets/checkbox.h" +#include "storage/localstorage.h" #include "styles/style_boxes.h" - +#include "ui/widgets/checkbox.h" void AutoLockBox::prepare() { setTitle(langFactory(lng_passcode_autolock)); addButton(langFactory(lng_box_ok), [this] { closeBox(); }); - auto options = { 60, 300, 3600, 18000 }; + auto options = {60, 300, 3600, 18000}; auto group = std::make_shared(Global::AutoLock()); auto y = st::boxOptionListPadding.top() + st::langsButton.margin.top(); auto count = int(options.size()); _options.reserve(count); for (auto seconds : options) { - _options.emplace_back(this, group, seconds, (seconds % 3600) ? lng_passcode_autolock_minutes(lt_count, seconds / 60) : lng_passcode_autolock_hours(lt_count, seconds / 3600), st::langsButton); + _options.emplace_back(this, group, seconds, + (seconds % 3600) ? lng_passcode_autolock_minutes(lt_count, seconds / 60) : + lng_passcode_autolock_hours(lt_count, seconds / 3600), + st::langsButton); _options.back()->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), y); y += _options.back()->heightNoMargins() + st::boxOptionListSkip; } group->setChangedCallback([this](int value) { durationChanged(value); }); - setDimensions(st::langsWidth, st::boxOptionListPadding.top() + count * _options.back()->heightNoMargins() + (count - 1) * st::boxOptionListSkip + st::boxOptionListPadding.bottom() + st::boxPadding.bottom()); + setDimensions(st::langsWidth, st::boxOptionListPadding.top() + count * _options.back()->heightNoMargins() + + (count - 1) * st::boxOptionListSkip + st::boxOptionListPadding.bottom() + + st::boxPadding.bottom()); } void AutoLockBox::durationChanged(int seconds) { diff --git a/Telegram/SourceFiles/boxes/autolock_box.h b/Telegram/SourceFiles/boxes/autolock_box.h index 6ec547324..78ccd832e 100644 --- a/Telegram/SourceFiles/boxes/autolock_box.h +++ b/Telegram/SourceFiles/boxes/autolock_box.h @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "boxes/abstract_box.h" @@ -30,8 +32,7 @@ class AutoLockBox : public BoxContent { Q_OBJECT public: - AutoLockBox(QWidget*) { - } + AutoLockBox(QWidget*) {} protected: void prepare() override; @@ -40,5 +41,4 @@ class AutoLockBox : public BoxContent { void durationChanged(int seconds); std::vector> _options; - }; diff --git a/Telegram/SourceFiles/boxes/background_box.cpp b/Telegram/SourceFiles/boxes/background_box.cpp index 6366da106..2f59a1bbb 100644 --- a/Telegram/SourceFiles/boxes/background_box.cpp +++ b/Telegram/SourceFiles/boxes/background_box.cpp @@ -1,39 +1,41 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/background_box.h" +#include "auth_session.h" #include "lang/lang_keys.h" #include "mainwidget.h" #include "mainwindow.h" -#include "window/themes/window_theme.h" -#include "styles/style_overview.h" #include "styles/style_boxes.h" +#include "styles/style_overview.h" #include "ui/effects/round_checkbox.h" -#include "auth_session.h" +#include "window/themes/window_theme.h" class BackgroundBox::Inner : public TWidget, public RPCSender, private base::Subscriber { public: Inner(QWidget *parent); - void setBackgroundChosenCallback(base::lambda callback) { + void setBackgroundChosenCallback(Fn callback) { _backgroundChosenCallback = std::move(callback); } @@ -49,18 +51,16 @@ class BackgroundBox::Inner : public TWidget, public RPCSender, private base::Sub void gotWallpapers(const MTPVector &result); void updateWallpapers(); - base::lambda _backgroundChosenCallback; + Fn _backgroundChosenCallback; int _bgCount = 0; int _rows = 0; int _over = -1; int _overDown = -1; std::unique_ptr _check; // this is not a widget - }; -BackgroundBox::BackgroundBox(QWidget*) { -} +BackgroundBox::BackgroundBox(QWidget *) {} void BackgroundBox::prepare() { setTitle(langFactory(lng_backgrounds_header)); @@ -84,11 +84,13 @@ void BackgroundBox::backgroundChosen(int index) { closeBox(); } -BackgroundBox::Inner::Inner(QWidget *parent) : TWidget(parent) -, _check(std::make_unique(st::overviewCheck, [this] { update(); })) { +BackgroundBox::Inner::Inner(QWidget *parent) + : TWidget(parent) + , _check(std::make_unique(st::overviewCheck, [this] { update(); })) { _check->setChecked(true, Ui::RoundCheckbox::SetStyle::Fast); if (App::cServerBackgrounds().isEmpty()) { - resize(BackgroundsInRow * (st::backgroundSize.width() + st::backgroundPadding) + st::backgroundPadding, 2 * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding); + resize(BackgroundsInRow * (st::backgroundSize.width() + st::backgroundPadding) + st::backgroundPadding, + 2 * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding); MTP::send(MTPaccount_GetWallPapers(), rpcDone(&Inner::gotWallpapers)); } else { updateWallpapers(); @@ -115,10 +117,10 @@ void BackgroundBox::Inner::gotWallpapers(const MTPVector &result) auto &d = w.c_wallPaper(); auto &sizes = d.vsizes.v; const MTPPhotoSize *thumb = 0, *full = 0; - int32 thumbLevel = -1, fullLevel = -1; + qint32 thumbLevel = -1, fullLevel = -1; for (QVector::const_iterator j = sizes.cbegin(), e = sizes.cend(); j != e; ++j) { char size = 0; - int32 w = 0, h = 0; + qint32 w = 0, h = 0; switch (j->type()) { case mtpc_photoSize: { auto &s = j->c_photoSize().vtype.v; @@ -136,7 +138,8 @@ void BackgroundBox::Inner::gotWallpapers(const MTPVector &result) } if (!size || !w || !h) continue; - int32 newThumbLevel = qAbs((st::backgroundSize.width() * cIntRetinaFactor()) - w), newFullLevel = qAbs(2560 - w); + qint32 newThumbLevel = qAbs((st::backgroundSize.width() * cIntRetinaFactor()) - w), + newFullLevel = qAbs(2560 - w); if (thumbLevel < 0 || newThumbLevel < thumbLevel) { thumbLevel = newThumbLevel; thumb = &(*j); @@ -147,7 +150,8 @@ void BackgroundBox::Inner::gotWallpapers(const MTPVector &result) } } if (thumb && full && full->type() != mtpc_photoSizeEmpty) { - wallpapers.push_back(App::WallPaper(d.vid.v ? d.vid.v : INT_MAX, App::image(*thumb), App::image(*full))); + wallpapers.push_back( + App::WallPaper(d.vid.v ? d.vid.v : INT_MAX, App::image(*thumb), App::image(*full))); } } break; @@ -166,7 +170,8 @@ void BackgroundBox::Inner::updateWallpapers() { _rows = _bgCount / BackgroundsInRow; if (_bgCount % BackgroundsInRow) ++_rows; - resize(BackgroundsInRow * (st::backgroundSize.width() + st::backgroundPadding) + st::backgroundPadding, _rows * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding); + resize(BackgroundsInRow * (st::backgroundSize.width() + st::backgroundPadding) + st::backgroundPadding, + _rows * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding); for (int i = 0; i < BackgroundsInRow * 3; ++i) { if (i >= _bgCount) break; @@ -211,10 +216,14 @@ void BackgroundBox::Inner::paintEvent(QPaintEvent *e) { void BackgroundBox::Inner::mouseMoveEvent(QMouseEvent *e) { int x = e->pos().x(), y = e->pos().y(); int row = int((y - st::backgroundPadding) / (st::backgroundSize.height() + st::backgroundPadding)); - if (y - row * (st::backgroundSize.height() + st::backgroundPadding) > st::backgroundPadding + st::backgroundSize.height()) row = _rows + 1; + if (y - row * (st::backgroundSize.height() + st::backgroundPadding) > + st::backgroundPadding + st::backgroundSize.height()) + row = _rows + 1; int col = int((x - st::backgroundPadding) / (st::backgroundSize.width() + st::backgroundPadding)); - if (x - col * (st::backgroundSize.width() + st::backgroundPadding) > st::backgroundPadding + st::backgroundSize.width()) row = _rows + 1; + if (x - col * (st::backgroundSize.width() + st::backgroundPadding) > + st::backgroundPadding + st::backgroundSize.width()) + row = _rows + 1; int newOver = row * BackgroundsInRow + col; if (newOver >= _bgCount) newOver = -1; diff --git a/Telegram/SourceFiles/boxes/background_box.h b/Telegram/SourceFiles/boxes/background_box.h index f24331dd8..ed2ab273e 100644 --- a/Telegram/SourceFiles/boxes/background_box.h +++ b/Telegram/SourceFiles/boxes/background_box.h @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "boxes/abstract_box.h" @@ -38,5 +40,4 @@ class BackgroundBox : public BoxContent { class Inner; QPointer _inner; - }; diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style index 81f5fabae..2afae013e 100644 --- a/Telegram/SourceFiles/boxes/boxes.style +++ b/Telegram/SourceFiles/boxes/boxes.style @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// using "basic.style"; using "ui/widgets/widgets.style"; diff --git a/Telegram/SourceFiles/boxes/calendar_box.cpp b/Telegram/SourceFiles/boxes/calendar_box.cpp index 8d4af760e..92a6dc4d4 100644 --- a/Telegram/SourceFiles/boxes/calendar_box.cpp +++ b/Telegram/SourceFiles/boxes/calendar_box.cpp @@ -1,30 +1,32 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/calendar_box.h" -#include "ui/widgets/buttons.h" +#include "lang/lang_keys.h" #include "styles/style_boxes.h" #include "styles/style_dialogs.h" -#include "lang/lang_keys.h" #include "ui/effects/ripple_animation.h" +#include "ui/widgets/buttons.h" namespace { @@ -92,10 +94,10 @@ class CalendarBox::Context { int _daysCount = 0; int _daysShift = 0; int _rowsCount = 0; - }; -CalendarBox::Context::Context(QDate month, QDate highlighted) : _highlighted(highlighted) { +CalendarBox::Context::Context(QDate month, QDate highlighted) + : _highlighted(highlighted) { showMonth(month); } @@ -125,8 +127,6 @@ void CalendarBox::Context::applyMonth(const QDate &month, bool forced) { _daysCount = month.daysInMonth(); _daysShift = daysShiftForMonth(month); _rowsCount = rowsCountForMonth(month); - auto yearIndex = month.year(); - auto monthIndex = month.month(); _highlightedIndex = month.daysTo(_highlighted); _minDayIndex = _min.isNull() ? INT_MIN : month.daysTo(_min); _maxDayIndex = _max.isNull() ? INT_MAX : month.daysTo(_max); @@ -176,7 +176,8 @@ QDate CalendarBox::Context::dateFromIndex(int index) const { } index += QDate(year, month, 1).daysInMonth(); } - for (auto maxIndex = QDate(year, month, 1).daysInMonth(); index >= maxIndex; maxIndex = QDate(year, month, 1).daysInMonth()) { + for (auto maxIndex = QDate(year, month, 1).daysInMonth(); index >= maxIndex; + maxIndex = QDate(year, month, 1).daysInMonth()) { index -= maxIndex; if (month++ == kMonthsCount) { month -= kMonthsCount; @@ -205,7 +206,7 @@ class CalendarBox::Inner : public TWidget, public RPCSender, private base::Subsc return st::calendarPadding.top() + innerHeight + st::calendarPadding.bottom(); } - void setDateChosenCallback(base::lambda callback) { + void setDateChosenCallback(Fn callback) { _dateChosenCallback = std::move(callback); } @@ -231,16 +232,16 @@ class CalendarBox::Inner : public TWidget, public RPCSender, private base::Subsc std::map> _ripples; - base::lambda _dateChosenCallback; + Fn _dateChosenCallback; static constexpr auto kEmptySelection = -kDaysInWeek; int _selected = kEmptySelection; int _pressed = kEmptySelection; - }; -CalendarBox::Inner::Inner(QWidget *parent, Context *context) : TWidget(parent) -, _context(context) { +CalendarBox::Inner::Inner(QWidget *parent, Context *context) + : TWidget(parent) + , _context(context) { setMouseTracking(true); subscribe(context->month(), [this](QDate month) { monthChanged(month); }); } @@ -295,11 +296,11 @@ void CalendarBox::Inner::paintRows(Painter &p, QRect clip) { auto y = rowsTop(); auto index = -_context->daysShift(); auto highlightedIndex = _context->highlightedIndex(); - for (auto row = 0, rowsCount = _context->rowsCount(), daysCount = _context->daysCount() - ; row != rowsCount - ; ++row, y += st::calendarCellSize.height()) { + for (auto row = 0, rowsCount = _context->rowsCount(), daysCount = _context->daysCount(); row != rowsCount; + ++row, y += st::calendarCellSize.height()) { auto x = rowsLeft(); - if (!myrtlrect(x, y, st::calendarCellSize.width() * kDaysInWeek, st::calendarCellSize.height()).intersects(clip)) { + if (!myrtlrect(x, y, st::calendarCellSize.width() * kDaysInWeek, st::calendarCellSize.height()) + .intersects(clip)) { index += kDaysInWeek; continue; } @@ -364,14 +365,20 @@ void CalendarBox::Inner::mousePressEvent(QMouseEvent *e) { auto row = index / kDaysInWeek; auto col = index % kDaysInWeek; - auto cell = QRect(rowsLeft() + col * st::calendarCellSize.width(), rowsTop() + row * st::calendarCellSize.height(), st::calendarCellSize.width(), st::calendarCellSize.height()); + auto cell = + QRect(rowsLeft() + col * st::calendarCellSize.width(), rowsTop() + row * st::calendarCellSize.height(), + st::calendarCellSize.width(), st::calendarCellSize.height()); auto it = _ripples.find(_selected); if (it == _ripples.cend()) { auto mask = Ui::RippleAnimation::ellipseMask(QSize(st::calendarCellInner, st::calendarCellInner)); auto update = [this, cell] { rtlupdate(cell); }; - it = _ripples.emplace(_selected, std::make_unique(st::defaultRippleAnimation, std::move(mask), std::move(update))).first; + it = _ripples + .emplace(_selected, std::make_unique(st::defaultRippleAnimation, + std::move(mask), std::move(update))) + .first; } - auto ripplePosition = QPoint(cell.x() + (st::calendarCellSize.width() - st::calendarCellInner) / 2, cell.y() + (st::calendarCellSize.height() - st::calendarCellInner) / 2); + auto ripplePosition = QPoint(cell.x() + (st::calendarCellSize.width() - st::calendarCellInner) / 2, + cell.y() + (st::calendarCellSize.height() - st::calendarCellInner) / 2); it->second->add(e->pos() - ripplePosition); } } @@ -400,7 +407,9 @@ CalendarBox::Inner::~Inner() = default; class CalendarBox::Title : public TWidget, private base::Subscriber { public: - Title(QWidget *parent, Context *context) : TWidget(parent), _context(context) { + Title(QWidget *parent, Context *context) + : TWidget(parent) + , _context(context) { subscribe(_context->month(), [this](QDate date) { monthChanged(date); }); } @@ -414,7 +423,6 @@ class CalendarBox::Title : public TWidget, private base::Subscriber { QString _text; int _textWidth = 0; - }; void CalendarBox::Title::monthChanged(QDate month) { @@ -428,17 +436,17 @@ void CalendarBox::Title::paintEvent(QPaintEvent *e) { p.setFont(st::calendarTitleFont); p.setPen(st::boxTitleFg); - p.drawTextLeft((width() - _textWidth) / 2, (height() - st::calendarTitleFont->height) / 2, width(), _text, _textWidth); + p.drawTextLeft((width() - _textWidth) / 2, (height() - st::calendarTitleFont->height) / 2, width(), _text, + _textWidth); } -CalendarBox::CalendarBox(QWidget*, QDate month, QDate highlighted, base::lambda callback) -: _context(std::make_unique(month, highlighted)) -, _inner(this, _context.get()) -, _title(this, _context.get()) -, _previous(this, st::calendarPrevious) -, _next(this, st::calendarNext) -, _callback(std::move(callback)) { -} +CalendarBox::CalendarBox(QWidget *, QDate month, QDate highlighted, Fn callback) + : _context(std::make_unique(month, highlighted)) + , _inner(this, _context.get()) + , _title(this, _context.get()) + , _previous(this, st::calendarPrevious) + , _next(this, st::calendarNext) + , _callback(std::move(callback)) {} void CalendarBox::setMinDate(QDate date) { _context->setMinDate(date); @@ -460,7 +468,7 @@ void CalendarBox::prepare() { } }); -// _inner = setInnerWidget(object_ptr(this, _context.get()), st::calendarScroll, st::calendarTitleHeight); + // _inner = setInnerWidget(object_ptr(this, _context.get()), st::calendarScroll, st::calendarTitleHeight); _inner->setDateChosenCallback(std::move(_callback)); addButton(langFactory(lng_close), [this] { closeBox(); }); @@ -493,7 +501,8 @@ void CalendarBox::monthChanged(QDate month) { void CalendarBox::resizeEvent(QResizeEvent *e) { _previous->moveToLeft(0, 0); _next->moveToRight(0, 0); - _title->setGeometryToLeft(_previous->width(), 0, width() - _previous->width() - _next->width(), st::calendarTitleHeight); + _title->setGeometryToLeft(_previous->width(), 0, width() - _previous->width() - _next->width(), + st::calendarTitleHeight); _inner->setGeometryToLeft(0, st::calendarTitleHeight, width(), height() - st::calendarTitleHeight); BoxContent::resizeEvent(e); } diff --git a/Telegram/SourceFiles/boxes/calendar_box.h b/Telegram/SourceFiles/boxes/calendar_box.h index 1cb326024..bcd0db27b 100644 --- a/Telegram/SourceFiles/boxes/calendar_box.h +++ b/Telegram/SourceFiles/boxes/calendar_box.h @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "abstract_box.h" @@ -28,7 +30,7 @@ class IconButton; class CalendarBox : public BoxContent { public: - CalendarBox(QWidget*, QDate month, QDate highlighted, base::lambda callback); + CalendarBox(QWidget *, QDate month, QDate highlighted, Fn callback); void setMinDate(QDate date); void setMaxDate(QDate date); @@ -57,6 +59,5 @@ class CalendarBox : public BoxContent { object_ptr _previous; object_ptr _next; - base::lambda _callback; - + Fn _callback; }; diff --git a/Telegram/SourceFiles/boxes/change_phone_box.cpp b/Telegram/SourceFiles/boxes/change_phone_box.cpp index 8a2659f7c..9e9d772ad 100644 --- a/Telegram/SourceFiles/boxes/change_phone_box.cpp +++ b/Telegram/SourceFiles/boxes/change_phone_box.cpp @@ -1,37 +1,42 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/change_phone_box.h" - +#include "app.h" // For formatPhone +#include "base/lambda_guard.h" +#include "boxes/confirm_box.h" +#include "boxes/confirm_phone_box.h" +#include "facades.h" #include "lang/lang_keys.h" #include "styles/style_boxes.h" -#include "ui/widgets/labels.h" -#include "ui/widgets/input_fields.h" #include "ui/effects/widget_fade_wrap.h" -#include "boxes/confirm_phone_box.h" #include "ui/toast/toast.h" -#include "boxes/confirm_box.h" +#include "ui/widgets/input_fields.h" +#include "ui/widgets/labels.h" namespace { -void createErrorLabel(QWidget *parent, object_ptr> &label, const QString &text, int x, int y) { +void createErrorLabel(QWidget *parent, object_ptr> &label, const QString &text, int x, + int y) { if (label) { auto errorFadeOut = std::move(label); errorFadeOut->setUpdateCallback([label = errorFadeOut.data()] { @@ -42,7 +47,8 @@ void createErrorLabel(QWidget *parent, object_ptrhideAnimated(); } if (!text.isEmpty()) { - label.create(parent, object_ptr(parent, text, Ui::FlatLabel::InitType::Simple, st::changePhoneError)); + label.create(parent, + object_ptr(parent, text, Ui::FlatLabel::InitType::Simple, st::changePhoneError)); label->hideFast(); label->moveToLeft(x, y); label->showAnimated(); @@ -53,8 +59,7 @@ void createErrorLabel(QWidget *parent, object_ptrsetFocusFast(); @@ -72,15 +77,14 @@ class ChangePhoneBox::EnterPhone : public BoxContent { showError(QString()); } - object_ptr _phone = { nullptr }; - object_ptr> _error = { nullptr }; + object_ptr _phone = {nullptr}; + object_ptr> _error = {nullptr}; mtpRequestId _requestId = 0; - }; class ChangePhoneBox::EnterCode : public BoxContent { public: - EnterCode(QWidget*, const QString &phone, const QString &hash, int codeLength, int callTimeout); + EnterCode(QWidget *, const QString &phone, const QString &hash, int codeLength, int callTimeout); void setInnerFocus() override { _code->setFocusFast(); @@ -104,12 +108,11 @@ class ChangePhoneBox::EnterCode : public BoxContent { QString _hash; int _codeLength = 0; int _callTimeout = 0; - object_ptr _code = { nullptr }; - object_ptr> _error = { nullptr }; - object_ptr _callLabel = { nullptr }; + object_ptr _code = {nullptr}; + object_ptr> _error = {nullptr}; + object_ptr _callLabel = {nullptr}; mtpRequestId _requestId = 0; SentCodeCall _call; - }; void ChangePhoneBox::EnterPhone::prepare() { @@ -122,7 +125,8 @@ void ChangePhoneBox::EnterPhone::prepare() { _phone->moveToLeft(st::boxPadding.left(), st::boxLittleSkip); connect(_phone, &Ui::PhoneInput::submitted, this, [this] { submit(); }); - auto description = object_ptr(this, lang(lng_change_phone_new_description), Ui::FlatLabel::InitType::Simple, st::changePhoneLabel); + auto description = object_ptr(this, lang(lng_change_phone_new_description), + Ui::FlatLabel::InitType::Simple, st::changePhoneLabel); auto errorSkip = st::boxLittleSkip + st::changePhoneError.style.font->height; description->moveToLeft(st::boxPadding.left(), _phone->y() + _phone->height() + errorSkip + st::boxLittleSkip); @@ -139,11 +143,12 @@ void ChangePhoneBox::EnterPhone::submit() { hideError(); auto phoneNumber = _phone->getLastText().trimmed(); - _requestId = MTP::send(MTPaccount_SendChangePhoneCode(MTP_flags(0), MTP_string(phoneNumber), MTP_bool(false)), rpcDone(base::lambda_guarded(this, [this, phoneNumber](const MTPauth_SentCode &result) { - return sendPhoneDone(phoneNumber, result); - })), rpcFail(base::lambda_guarded(this, [this, phoneNumber](const RPCError &error) { - return sendPhoneFail(phoneNumber, error); - }))); + _requestId = MTP::send( + MTPaccount_SendChangePhoneCode(MTP_flags(0), MTP_string(phoneNumber), MTP_bool(false)), + rpcDone(base::lambda_guarded( + this, [this, phoneNumber](const MTPauth_SentCode &result) { return sendPhoneDone(phoneNumber, result); })), + rpcFail(base::lambda_guarded( + this, [this, phoneNumber](const RPCError &error) { return sendPhoneFail(phoneNumber, error); }))); } void ChangePhoneBox::EnterPhone::sendPhoneDone(const QString &phoneNumber, const MTPauth_SentCode &result) { @@ -197,19 +202,21 @@ void ChangePhoneBox::EnterPhone::showError(const QString &text) { } } -ChangePhoneBox::EnterCode::EnterCode(QWidget*, const QString &phone, const QString &hash, int codeLength, int callTimeout) -: _phone(phone) -, _hash(hash) -, _codeLength(codeLength) -, _callTimeout(callTimeout) -, _call(this, [this] { sendCall(); }, [this] { updateCall(); }) { -} +ChangePhoneBox::EnterCode::EnterCode(QWidget *, const QString &phone, const QString &hash, int codeLength, + int callTimeout) + : _phone(phone) + , _hash(hash) + , _codeLength(codeLength) + , _callTimeout(callTimeout) + , _call(this, [this] { sendCall(); }, [this] { updateCall(); }) {} void ChangePhoneBox::EnterCode::prepare() { setTitle(langFactory(lng_change_phone_title)); - auto descriptionText = lng_change_phone_code_description(lt_phone, textcmdStartSemibold() + App::formatPhone(_phone) + textcmdStopSemibold()); - auto description = object_ptr(this, descriptionText, Ui::FlatLabel::InitType::Rich, st::changePhoneLabel); + auto descriptionText = lng_change_phone_code_description( + lt_phone, textcmdStartSemibold() + App::formatPhone(_phone) + textcmdStopSemibold()); + auto description = + object_ptr(this, descriptionText, Ui::FlatLabel::InitType::Rich, st::changePhoneLabel); description->moveToLeft(st::boxPadding.left(), 0); auto phoneValue = QString(); @@ -224,7 +231,7 @@ void ChangePhoneBox::EnterCode::prepare() { setDimensions(st::boxWidth, countHeight()); if (_callTimeout > 0) { - _call.setStatus({ SentCodeCall::State::Waiting, _callTimeout }); + _call.setStatus({SentCodeCall::State::Waiting, _callTimeout}); updateCall(); } @@ -244,21 +251,21 @@ void ChangePhoneBox::EnterCode::submit() { hideError(); auto code = _code->getLastText().trimmed(); - _requestId = MTP::send(MTPaccount_ChangePhone(MTP_string(_phone), MTP_string(_hash), MTP_string(code)), rpcDone([weak = weak(this)](const MTPUser &result) { - App::feedUser(result); - if (weak) { - Ui::hideLayer(); - } - Ui::Toast::Show(lang(lng_change_phone_success)); - }), rpcFail(base::lambda_guarded(this, [this](const RPCError &error) { - return sendCodeFail(error); - }))); + _requestId = + MTP::send(MTPaccount_ChangePhone(MTP_string(_phone), MTP_string(_hash), MTP_string(code)), + rpcDone([weak = weak(this)](const MTPUser &result) { + App::feedUser(result); + if (weak) { + Ui::hideLayer(); + } + Ui::Toast::Show(lang(lng_change_phone_success)); + }), + rpcFail(base::lambda_guarded(this, [this](const RPCError &error) { return sendCodeFail(error); }))); } void ChangePhoneBox::EnterCode::sendCall() { - MTP::send(MTPauth_ResendCode(MTP_string(_phone), MTP_string(_hash)), rpcDone(base::lambda_guarded(this, [this] { - _call.callDone(); - }))); + MTP::send(MTPauth_ResendCode(MTP_string(_phone), MTP_string(_hash)), + rpcDone(base::lambda_guarded(this, [this] { _call.callDone(); }))); } void ChangePhoneBox::EnterCode::updateCall() { @@ -303,16 +310,12 @@ bool ChangePhoneBox::EnterCode::sendCodeFail(const RPCError &error) { void ChangePhoneBox::prepare() { setTitle(langFactory(lng_change_phone_title)); - addButton(langFactory(lng_change_phone_button), [] { - Ui::show(Box(lang(lng_change_phone_warning), [] { - Ui::show(Box()); - })); - }); - addButton(langFactory(lng_cancel), [this] { - closeBox(); - }); - - auto label = object_ptr(this, lang(lng_change_phone_description), Ui::FlatLabel::InitType::Rich, st::changePhoneDescription); + addButton(langFactory(lng_change_phone_button), + [] { Ui::show(Box(lang(lng_change_phone_warning), [] { Ui::show(Box()); })); }); + addButton(langFactory(lng_cancel), [this] { closeBox(); }); + + auto label = object_ptr(this, lang(lng_change_phone_description), Ui::FlatLabel::InitType::Rich, + st::changePhoneDescription); label->moveToLeft((st::boxWideWidth - label->width()) / 2, st::changePhoneDescriptionTop); setDimensions(st::boxWideWidth, label->bottomNoMargins() + st::boxLittleSkip); diff --git a/Telegram/SourceFiles/boxes/change_phone_box.h b/Telegram/SourceFiles/boxes/change_phone_box.h index 0c64f7e7c..c3ae9b9ae 100644 --- a/Telegram/SourceFiles/boxes/change_phone_box.h +++ b/Telegram/SourceFiles/boxes/change_phone_box.h @@ -1,31 +1,32 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "boxes/abstract_box.h" class ChangePhoneBox : public BoxContent { public: - ChangePhoneBox(QWidget*) { - } + ChangePhoneBox(QWidget *) {} protected: void prepare() override; @@ -35,6 +36,4 @@ class ChangePhoneBox : public BoxContent { private: class EnterPhone; class EnterCode; - }; - diff --git a/Telegram/SourceFiles/boxes/confirm_box.cpp b/Telegram/SourceFiles/boxes/confirm_box.cpp index 681a0a7e4..86ede373f 100644 --- a/Telegram/SourceFiles/boxes/confirm_box.cpp +++ b/Telegram/SourceFiles/boxes/confirm_box.cpp @@ -1,108 +1,116 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/confirm_box.h" -#include "styles/style_boxes.h" +#include "apiwrap.h" +#include "application.h" +#include "auth_session.h" +#include "core/click_handler_types.h" #include "lang/lang_keys.h" #include "mainwidget.h" #include "mainwindow.h" -#include "apiwrap.h" -#include "application.h" -#include "ui/widgets/checkbox.h" +#include "observer_peer.h" +#include "storage/localstorage.h" +#include "styles/style_boxes.h" +#include "ui/toast/toast.h" #include "ui/widgets/buttons.h" +#include "ui/widgets/checkbox.h" #include "ui/widgets/labels.h" -#include "ui/toast/toast.h" -#include "core/click_handler_types.h" -#include "storage/localstorage.h" -#include "auth_session.h" -#include "observer_peer.h" TextParseOptions _confirmBoxTextOptions = { - TextParseLinks | TextParseMultiline | TextParseRichText, // flags - 0, // maxw - 0, // maxh - Qt::LayoutDirectionAuto, // dir + TextParseLinks | TextParseMultiline | TextParseRichText, // flags + 0, // maxw + 0, // maxh + Qt::LayoutDirectionAuto, // dir }; -ConfirmBox::ConfirmBox(QWidget*, const QString &text, base::lambda_once confirmedCallback, base::lambda_once cancelledCallback) -: _confirmText(lang(lng_box_ok)) -, _cancelText(lang(lng_cancel)) -, _confirmStyle(st::defaultBoxButton) -, _text(st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right()) -, _confirmedCallback(std::move(confirmedCallback)) -, _cancelledCallback(std::move(cancelledCallback)) { +ConfirmBox::ConfirmBox(QWidget *, const QString &text, FnMut confirmedCallback, FnMut cancelledCallback) + : _confirmText(lang(lng_box_ok)) + , _cancelText(lang(lng_cancel)) + , _confirmStyle(st::defaultBoxButton) + , _text(st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right()) + , _confirmedCallback(std::move(confirmedCallback)) + , _cancelledCallback(std::move(cancelledCallback)) { init(text); } -ConfirmBox::ConfirmBox(QWidget*, const QString &text, const QString &confirmText, base::lambda_once confirmedCallback, base::lambda_once cancelledCallback) -: _confirmText(confirmText) -, _cancelText(lang(lng_cancel)) -, _confirmStyle(st::defaultBoxButton) -, _text(st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right()) -, _confirmedCallback(std::move(confirmedCallback)) -, _cancelledCallback(std::move(cancelledCallback)) { +ConfirmBox::ConfirmBox(QWidget *, const QString &text, const QString &confirmText, FnMut confirmedCallback, + FnMut cancelledCallback) + : _confirmText(confirmText) + , _cancelText(lang(lng_cancel)) + , _confirmStyle(st::defaultBoxButton) + , _text(st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right()) + , _confirmedCallback(std::move(confirmedCallback)) + , _cancelledCallback(std::move(cancelledCallback)) { init(text); } -ConfirmBox::ConfirmBox(QWidget*, const QString &text, const QString &confirmText, const style::RoundButton &confirmStyle, base::lambda_once confirmedCallback, base::lambda_once cancelledCallback) -: _confirmText(confirmText) -, _cancelText(lang(lng_cancel)) -, _confirmStyle(confirmStyle) -, _text(st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right()) -, _confirmedCallback(std::move(confirmedCallback)) -, _cancelledCallback(std::move(cancelledCallback)) { +ConfirmBox::ConfirmBox(QWidget *, const QString &text, const QString &confirmText, + const style::RoundButton &confirmStyle, FnMut confirmedCallback, + FnMut cancelledCallback) + : _confirmText(confirmText) + , _cancelText(lang(lng_cancel)) + , _confirmStyle(confirmStyle) + , _text(st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right()) + , _confirmedCallback(std::move(confirmedCallback)) + , _cancelledCallback(std::move(cancelledCallback)) { init(text); } -ConfirmBox::ConfirmBox(QWidget*, const QString &text, const QString &confirmText, const QString &cancelText, base::lambda_once confirmedCallback, base::lambda_once cancelledCallback) -: _confirmText(confirmText) -, _cancelText(cancelText) -, _confirmStyle(st::defaultBoxButton) -, _text(st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right()) -, _confirmedCallback(std::move(confirmedCallback)) -, _cancelledCallback(std::move(cancelledCallback)) { +ConfirmBox::ConfirmBox(QWidget *, const QString &text, const QString &confirmText, const QString &cancelText, + FnMut confirmedCallback, FnMut cancelledCallback) + : _confirmText(confirmText) + , _cancelText(cancelText) + , _confirmStyle(st::defaultBoxButton) + , _text(st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right()) + , _confirmedCallback(std::move(confirmedCallback)) + , _cancelledCallback(std::move(cancelledCallback)) { init(text); } -ConfirmBox::ConfirmBox(QWidget*, const QString &text, const QString &confirmText, const style::RoundButton &confirmStyle, const QString &cancelText, base::lambda_once confirmedCallback, base::lambda_once cancelledCallback) -: _confirmText(confirmText) -, _cancelText(cancelText) -, _confirmStyle(st::defaultBoxButton) -, _text(st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right()) -, _confirmedCallback(std::move(confirmedCallback)) -, _cancelledCallback(std::move(cancelledCallback)) { +ConfirmBox::ConfirmBox(QWidget *, const QString &text, const QString &confirmText, + const style::RoundButton &confirmStyle, const QString &cancelText, + FnMut confirmedCallback, FnMut cancelledCallback) + : _confirmText(confirmText) + , _cancelText(cancelText) + , _confirmStyle(st::defaultBoxButton) + , _text(st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right()) + , _confirmedCallback(std::move(confirmedCallback)) + , _cancelledCallback(std::move(cancelledCallback)) { init(text); } -ConfirmBox::ConfirmBox(const InformBoxTag &, const QString &text, const QString &doneText, base::lambda closedCallback) -: _confirmText(doneText) -, _confirmStyle(st::defaultBoxButton) -, _informative(true) -, _text(st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right()) -, _confirmedCallback(generateInformCallback(closedCallback)) -, _cancelledCallback(generateInformCallback(closedCallback)) { +ConfirmBox::ConfirmBox(const InformBoxTag &, const QString &text, const QString &doneText, Fn closedCallback) + : _confirmText(doneText) + , _confirmStyle(st::defaultBoxButton) + , _informative(true) + , _text(st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right()) + , _confirmedCallback(generateInformCallback(closedCallback)) + , _cancelledCallback(generateInformCallback(closedCallback)) { init(text); } -base::lambda_once ConfirmBox::generateInformCallback(base::lambda closedCallback) { +FnMut ConfirmBox::generateInformCallback(Fn closedCallback) { return base::lambda_guarded(this, [this, closedCallback] { closeBox(); if (closedCallback) { @@ -118,7 +126,11 @@ void ConfirmBox::init(const QString &text) { void ConfirmBox::prepare() { addButton([this] { return _confirmText; }, [this] { confirmed(); }, _confirmStyle); if (!_informative) { - addButton([this] { return _cancelText; }, [this] { _cancelled = true; closeBox(); }); + addButton([this] { return _cancelText; }, + [this] { + _cancelled = true; + closeBox(); + }); } subscribe(boxClosing, [this] { if (!_confirmed && (!_strictCancel || _cancelled) && _cancelledCallback) { @@ -130,7 +142,7 @@ void ConfirmBox::prepare() { void ConfirmBox::textUpdated() { _textWidth = st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right(); - _textHeight = qMin(_text.countHeight(_textWidth), 16 * st::boxLabelStyle.lineHeight); + _textHeight = std::min(_text.countHeight(_textWidth), 16 * st::boxLabelStyle.lineHeight); setDimensions(st::boxWidth, st::boxPadding.top() + _textHeight + st::boxPadding.bottom()); setMouseTracking(_text.hasLinks()); @@ -210,16 +222,17 @@ void ConfirmBox::paintEvent(QPaintEvent *e) { _text.drawLeftElided(p, st::boxPadding.left(), st::boxPadding.top(), _textWidth, width(), 16, style::al_left); } -InformBox::InformBox(QWidget*, const QString &text, base::lambda closedCallback) : ConfirmBox(ConfirmBox::InformBoxTag(), text, lang(lng_box_ok), std::move(closedCallback)) { -} +InformBox::InformBox(QWidget *, const QString &text, Fn closedCallback) + : ConfirmBox(ConfirmBox::InformBoxTag(), text, lang(lng_box_ok), std::move(closedCallback)) {} -InformBox::InformBox(QWidget*, const QString &text, const QString &doneText, base::lambda closedCallback) : ConfirmBox(ConfirmBox::InformBoxTag(), text, doneText, std::move(closedCallback)) { -} +InformBox::InformBox(QWidget *, const QString &text, const QString &doneText, Fn closedCallback) + : ConfirmBox(ConfirmBox::InformBoxTag(), text, doneText, std::move(closedCallback)) {} -MaxInviteBox::MaxInviteBox(QWidget*, not_null channel) : BoxContent() -, _channel(channel) -, _text(st::boxLabelStyle, lng_participant_invite_sorry(lt_count, Global::ChatSizeMax()), _confirmBoxTextOptions, st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right()) { -} +MaxInviteBox::MaxInviteBox(QWidget *, not_null channel) + : BoxContent() + , _channel(channel) + , _text(st::boxLabelStyle, lng_participant_invite_sorry(lt_count, Global::ChatSizeMax()), _confirmBoxTextOptions, + st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right()) {} void MaxInviteBox::prepare() { setMouseTracking(true); @@ -227,14 +240,16 @@ void MaxInviteBox::prepare() { addButton(langFactory(lng_box_ok), [this] { closeBox(); }); _textWidth = st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right(); - _textHeight = qMin(_text.countHeight(_textWidth), 16 * st::boxLabelStyle.lineHeight); - setDimensions(st::boxWidth, st::boxPadding.top() + _textHeight + st::boxTextFont->height + st::boxTextFont->height * 2 + st::newGroupLinkPadding.bottom()); + _textHeight = std::min(_text.countHeight(_textWidth), 16 * st::boxLabelStyle.lineHeight); + setDimensions(st::boxWidth, st::boxPadding.top() + _textHeight + st::boxTextFont->height + + st::boxTextFont->height * 2 + st::newGroupLinkPadding.bottom()); - subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(Notify::PeerUpdate::Flag::InviteLinkChanged, [this](const Notify::PeerUpdate &update) { - if (update.peer == _channel) { - rtlupdate(_invitationLink); - } - })); + subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(Notify::PeerUpdate::Flag::InviteLinkChanged, + [this](const Notify::PeerUpdate &update) { + if (update.peer == _channel) { + rtlupdate(_invitationLink); + } + })); } void MaxInviteBox::mouseMoveEvent(QMouseEvent *e) { @@ -287,14 +302,14 @@ void MaxInviteBox::paintEvent(QPaintEvent *e) { void MaxInviteBox::resizeEvent(QResizeEvent *e) { BoxContent::resizeEvent(e); - _invitationLink = myrtlrect(st::boxPadding.left(), st::boxPadding.top() + _textHeight + st::boxTextFont->height, width() - st::boxPadding.left() - st::boxPadding.right(), 2 * st::boxTextFont->height); + _invitationLink = myrtlrect(st::boxPadding.left(), st::boxPadding.top() + _textHeight + st::boxTextFont->height, + width() - st::boxPadding.left() - st::boxPadding.right(), 2 * st::boxTextFont->height); } -ConvertToSupergroupBox::ConvertToSupergroupBox(QWidget*, ChatData *chat) -: _chat(chat) -, _text(100) -, _note(100) { -} +ConvertToSupergroupBox::ConvertToSupergroupBox(QWidget *, ChatData *chat) + : _chat(chat) + , _text(100) + , _note(100) {} void ConvertToSupergroupBox::prepare() { QStringList text; @@ -309,14 +324,18 @@ void ConvertToSupergroupBox::prepare() { addButton(langFactory(lng_cancel), [this] { closeBox(); }); _text.setText(st::boxLabelStyle, text.join('\n'), _confirmBoxTextOptions); - _note.setText(st::boxLabelStyle, lng_profile_convert_warning(lt_bold_start, textcmdStartSemibold(), lt_bold_end, textcmdStopSemibold()), _confirmBoxTextOptions); + _note.setText( + st::boxLabelStyle, + lng_profile_convert_warning(lt_bold_start, textcmdStartSemibold(), lt_bold_end, textcmdStopSemibold()), + _confirmBoxTextOptions); _textWidth = st::boxWideWidth - st::boxPadding.left() - st::boxButtonPadding.right(); _textHeight = _text.countHeight(_textWidth); setDimensions(st::boxWideWidth, _textHeight + st::boxPadding.bottom() + _note.countHeight(_textWidth)); } void ConvertToSupergroupBox::convertToSupergroup() { - MTP::send(MTPmessages_MigrateChat(_chat->inputChat), rpcDone(&ConvertToSupergroupBox::convertDone), rpcFail(&ConvertToSupergroupBox::convertFail)); + MTP::send(MTPmessages_MigrateChat(_chat->inputChat), rpcDone(&ConvertToSupergroupBox::convertDone), + rpcFail(&ConvertToSupergroupBox::convertFail)); } void ConvertToSupergroupBox::convertDone(const MTPUpdates &updates) { @@ -336,7 +355,9 @@ void ConvertToSupergroupBox::convertDone(const MTPUpdates &updates) { switch (updates.type()) { case mtpc_updates: handleChats(updates.c_updates().vchats); break; case mtpc_updatesCombined: handleChats(updates.c_updatesCombined().vchats); break; - default: LOG(("API Error: unexpected update cons %1 (ConvertToSupergroupBox::convertDone)").arg(updates.type())); break; + default: + LOG(("API Error: unexpected update cons %1 (ConvertToSupergroupBox::convertDone)").arg(updates.type())); + break; } } @@ -365,24 +386,33 @@ void ConvertToSupergroupBox::paintEvent(QPaintEvent *e) { _note.drawLeft(p, st::boxPadding.left(), _textHeight + st::boxPadding.bottom(), _textWidth, width()); } -PinMessageBox::PinMessageBox(QWidget*, ChannelData *channel, MsgId msgId) -: _channel(channel) -, _msgId(msgId) -, _text(this, lang(lng_pinned_pin_sure), Ui::FlatLabel::InitType::Simple, st::boxLabel) -, _notify(this, lang(lng_pinned_notify), true, st::defaultBoxCheckbox) { -} +PinMessageBox::PinMessageBox(QWidget *, ChannelData *channel, MsgId msgId) + : _channel(channel) + , _msgId(msgId) + , _text(this, lang(lng_pinned_pin_sure), Ui::FlatLabel::InitType::Simple, st::boxLabel) {} void PinMessageBox::prepare() { + if (_channel->isMegagroup()) { + _notify.create(this, lang(lng_pinned_notify), true, st::defaultBoxCheckbox); + } + + auto height = st::boxPadding.top() + _text->height() + st::boxPadding.bottom(); + if (_notify) { + height += st::boxMediumSkip + _notify->heightNoMargins(); + } + addButton(langFactory(lng_pinned_pin), [this] { pinMessage(); }); addButton(langFactory(lng_cancel), [this] { closeBox(); }); - setDimensions(st::boxWidth, st::boxPadding.top() + _text->height() + st::boxMediumSkip + _notify->heightNoMargins() + st::boxPadding.bottom()); + setDimensions(st::boxWidth, height); } void PinMessageBox::resizeEvent(QResizeEvent *e) { BoxContent::resizeEvent(e); _text->moveToLeft(st::boxPadding.left(), st::boxPadding.top()); - _notify->moveToLeft(st::boxPadding.left(), _text->y() + _text->height() + st::boxMediumSkip); + if (_notify) { + _notify->moveToLeft(st::boxPadding.left(), _text->y() + _text->height() + st::boxMediumSkip); + } } void PinMessageBox::keyPressEvent(QKeyEvent *e) { @@ -397,10 +427,11 @@ void PinMessageBox::pinMessage() { if (_requestId) return; auto flags = MTPchannels_UpdatePinnedMessage::Flags(0); - if (!_notify->checked()) { + if (_notify && !_notify->checked()) { flags |= MTPchannels_UpdatePinnedMessage::Flag::f_silent; } - _requestId = MTP::send(MTPchannels_UpdatePinnedMessage(MTP_flags(flags), _channel->inputChannel, MTP_int(_msgId)), rpcDone(&PinMessageBox::pinDone), rpcFail(&PinMessageBox::pinFail)); + _requestId = MTP::send(MTPchannels_UpdatePinnedMessage(MTP_flags(flags), _channel->inputChannel, MTP_int(_msgId)), + rpcDone(&PinMessageBox::pinDone), rpcFail(&PinMessageBox::pinFail)); } void PinMessageBox::pinDone(const MTPUpdates &updates) { @@ -416,7 +447,8 @@ bool PinMessageBox::pinFail(const RPCError &error) { return true; } -DeleteMessagesBox::DeleteMessagesBox(QWidget*, HistoryItem *item, bool suggestModerateActions) : _singleItem(true) { +DeleteMessagesBox::DeleteMessagesBox(QWidget *, HistoryItem *item, bool suggestModerateActions) + : _singleItem(true) { _ids.push_back(item->fullId()); if (suggestModerateActions) { _moderateBan = item->suggestBanReport(); @@ -428,13 +460,11 @@ DeleteMessagesBox::DeleteMessagesBox(QWidget*, HistoryItem *item, bool suggestMo } } -DeleteMessagesBox::DeleteMessagesBox(QWidget*, const SelectedItemSet &selected) { +DeleteMessagesBox::DeleteMessagesBox(QWidget *, const SelectedItemSet &selected) { auto count = selected.size(); Assert(count > 0); _ids.reserve(count); - for_const (auto item, selected) { - _ids.push_back(item->fullId()); - } + for_const (auto item, selected) { _ids.push_back(item->fullId()); } } void DeleteMessagesBox::prepare() { @@ -453,8 +483,8 @@ void DeleteMessagesBox::prepare() { text = _singleItem ? lang(lng_selected_delete_sure_this) : lng_selected_delete_sure(lt_count, _ids.size()); auto canDeleteAllForEveryone = true; auto now = ::date(unixtime()); - auto deleteForUser = (UserData*)nullptr; - auto peer = (PeerData*)nullptr; + auto deleteForUser = (UserData *)nullptr; + auto peer = (PeerData *)nullptr; auto forEveryoneText = lang(lng_delete_for_everyone_check); for_const (auto fullId, _ids) { if (auto item = App::histItemById(fullId)) { @@ -474,7 +504,7 @@ void DeleteMessagesBox::prepare() { canDeleteAllForEveryone = false; } } - auto count = qMax(1, _ids.size()); + auto count = std::max(1, _ids.size()); if (canDeleteAllForEveryone) { _forEveryone.create(this, forEveryoneText, false, st::defaultBoxCheckbox); } else if (peer && peer->isChannel()) { @@ -542,10 +572,12 @@ void DeleteMessagesBox::deleteAndClear() { if (_moderateFrom) { if (_banUser && _banUser->checked()) { - Auth().api().kickParticipant(_moderateInChannel, _moderateFrom, MTP_channelBannedRights(MTP_flags(0), MTP_int(0))); + Auth().api().kickParticipant(_moderateInChannel, _moderateFrom, + MTP_channelBannedRights(MTP_flags(0), MTP_int(0))); } if (_reportSpam->checked()) { - MTP::send(MTPchannels_ReportSpam(_moderateInChannel->inputChannel, _moderateFrom->inputUser, MTP_vector(1, MTP_int(_ids[0].msg)))); + MTP::send(MTPchannels_ReportSpam(_moderateInChannel->inputChannel, _moderateFrom->inputUser, + MTP_vector(1, MTP_int(_ids[0].msg)))); } if (_deleteAll && _deleteAll->checked()) { App::main()->deleteAllFromUser(_moderateInChannel, _moderateFrom); @@ -556,7 +588,7 @@ void DeleteMessagesBox::deleteAndClear() { App::main()->clearSelectedItems(); } - QMap> idsByPeer; + QMap> idsByPeer; for_const (auto fullId, _ids) { if (auto item = App::histItemById(fullId)) { auto history = item->history(); @@ -579,10 +611,11 @@ void DeleteMessagesBox::deleteAndClear() { Ui::hideLayer(); } -ConfirmInviteBox::ConfirmInviteBox(QWidget*, const QString &title, bool isChannel, const MTPChatPhoto &photo, int count, const QVector &participants) -: _title(this, st::confirmInviteTitle) -, _status(this, st::confirmInviteStatus) -, _participants(participants) { +ConfirmInviteBox::ConfirmInviteBox(QWidget *, const QString &title, bool isChannel, const MTPChatPhoto &photo, + int count, const QVector &participants) + : _title(this, st::confirmInviteTitle) + , _status(this, st::confirmInviteStatus) + , _participants(participants) { _title->setText(title); QString status; if (_participants.isEmpty() || _participants.size() >= count) { @@ -612,7 +645,7 @@ ConfirmInviteBox::ConfirmInviteBox(QWidget*, const QString &title, bool isChanne } void ConfirmInviteBox::prepare() { - addButton(langFactory(lng_group_invite_join), [this] { + addButton(langFactory(lng_group_invite_join), [] { if (auto main = App::main()) { main->onInviteImport(); } @@ -655,15 +688,18 @@ void ConfirmInviteBox::paintEvent(QPaintEvent *e) { Painter p(this); if (_photo) { - p.drawPixmap((width() - st::confirmInvitePhotoSize) / 2, st::confirmInvitePhotoTop, _photo->pixCircled(st::confirmInvitePhotoSize, st::confirmInvitePhotoSize)); + p.drawPixmap((width() - st::confirmInvitePhotoSize) / 2, st::confirmInvitePhotoTop, + _photo->pixCircled(st::confirmInvitePhotoSize, st::confirmInvitePhotoSize)); } else { - _photoEmpty.paint(p, (width() - st::confirmInvitePhotoSize) / 2, st::confirmInvitePhotoTop, width(), st::confirmInvitePhotoSize); + _photoEmpty.paint(p, (width() - st::confirmInvitePhotoSize) / 2, st::confirmInvitePhotoTop, width(), + st::confirmInvitePhotoSize); } int sumWidth = _participants.size() * _userWidth; int left = (width() - sumWidth) / 2; for_const (auto user, _participants) { - user->paintUserpicLeft(p, left + (_userWidth - st::confirmInviteUserPhotoSize) / 2, st::confirmInviteUserPhotoTop, width(), st::confirmInviteUserPhotoSize); + user->paintUserpicLeft(p, left + (_userWidth - st::confirmInviteUserPhotoSize) / 2, + st::confirmInviteUserPhotoTop, width(), st::confirmInviteUserPhotoSize); left += _userWidth; } } diff --git a/Telegram/SourceFiles/boxes/confirm_box.h b/Telegram/SourceFiles/boxes/confirm_box.h index 9ea2e457a..6f52a00bf 100644 --- a/Telegram/SourceFiles/boxes/confirm_box.h +++ b/Telegram/SourceFiles/boxes/confirm_box.h @@ -1,26 +1,29 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "boxes/abstract_box.h" +#include "history/history.h" namespace Ui { class Checkbox; @@ -30,11 +33,17 @@ class FlatLabel; class InformBox; class ConfirmBox : public BoxContent, public ClickHandlerHost { public: - ConfirmBox(QWidget*, const QString &text, base::lambda_once confirmedCallback = base::lambda_once(), base::lambda_once cancelledCallback = base::lambda_once()); - ConfirmBox(QWidget*, const QString &text, const QString &confirmText, base::lambda_once confirmedCallback = base::lambda_once(), base::lambda_once cancelledCallback = base::lambda_once()); - ConfirmBox(QWidget*, const QString &text, const QString &confirmText, const style::RoundButton &confirmStyle, base::lambda_once confirmedCallback = base::lambda_once(), base::lambda_once cancelledCallback = base::lambda_once()); - ConfirmBox(QWidget*, const QString &text, const QString &confirmText, const QString &cancelText, base::lambda_once confirmedCallback = base::lambda_once(), base::lambda_once cancelledCallback = base::lambda_once()); - ConfirmBox(QWidget*, const QString &text, const QString &confirmText, const style::RoundButton &confirmStyle, const QString &cancelText, base::lambda_once confirmedCallback = base::lambda_once(), base::lambda_once cancelledCallback = base::lambda_once()); + ConfirmBox(QWidget *, const QString &text, FnMut confirmedCallback = FnMut(), + FnMut cancelledCallback = FnMut()); + ConfirmBox(QWidget *, const QString &text, const QString &confirmText, + FnMut confirmedCallback = FnMut(), FnMut cancelledCallback = FnMut()); + ConfirmBox(QWidget *, const QString &text, const QString &confirmText, const style::RoundButton &confirmStyle, + FnMut confirmedCallback = FnMut(), FnMut cancelledCallback = FnMut()); + ConfirmBox(QWidget *, const QString &text, const QString &confirmText, const QString &cancelText, + FnMut confirmedCallback = FnMut(), FnMut cancelledCallback = FnMut()); + ConfirmBox(QWidget *, const QString &text, const QString &confirmText, const style::RoundButton &confirmStyle, + const QString &cancelText, FnMut confirmedCallback = FnMut(), + FnMut cancelledCallback = FnMut()); void updateLink(); @@ -58,10 +67,9 @@ class ConfirmBox : public BoxContent, public ClickHandlerHost { void leaveEventHook(QEvent *e) override; private: - struct InformBoxTag { - }; - ConfirmBox(const InformBoxTag &, const QString &text, const QString &doneText, base::lambda closedCallback); - base::lambda_once generateInformCallback(base::lambda closedCallback); + struct InformBoxTag {}; + ConfirmBox(const InformBoxTag &, const QString &text, const QString &doneText, Fn closedCallback); + FnMut generateInformCallback(Fn closedCallback); friend class InformBox; void confirmed(); @@ -84,21 +92,19 @@ class ConfirmBox : public BoxContent, public ClickHandlerHost { bool _confirmed = false; bool _cancelled = false; bool _strictCancel = false; - base::lambda_once _confirmedCallback; - base::lambda_once _cancelledCallback; - + FnMut _confirmedCallback; + FnMut _cancelledCallback; }; class InformBox : public ConfirmBox { public: - InformBox(QWidget*, const QString &text, base::lambda closedCallback = base::lambda()); - InformBox(QWidget*, const QString &text, const QString &doneText, base::lambda closedCallback = base::lambda()); - + InformBox(QWidget *, const QString &text, Fn closedCallback = Fn()); + InformBox(QWidget *, const QString &text, const QString &doneText, Fn closedCallback = Fn()); }; class MaxInviteBox : public BoxContent { public: - MaxInviteBox(QWidget*, not_null channel); + MaxInviteBox(QWidget *, not_null channel); protected: void prepare() override; @@ -112,21 +118,20 @@ class MaxInviteBox : public BoxContent { private: void updateSelected(const QPoint &cursorGlobalPosition); - not_null _channel; + not_null _channel; Text _text; - int32 _textWidth, _textHeight; + qint32 _textWidth, _textHeight; QRect _invitationLink; bool _linkOver = false; QPoint _lastMousePos; - }; class ConvertToSupergroupBox : public BoxContent, public RPCSender { public: - ConvertToSupergroupBox(QWidget*, ChatData *chat); + ConvertToSupergroupBox(QWidget *, ChatData *chat); protected: void prepare() override; @@ -141,13 +146,12 @@ class ConvertToSupergroupBox : public BoxContent, public RPCSender { ChatData *_chat; Text _text, _note; - int32 _textWidth, _textHeight; - + qint32 _textWidth, _textHeight; }; class PinMessageBox : public BoxContent, public RPCSender { public: - PinMessageBox(QWidget*, ChannelData *channel, MsgId msgId); + PinMessageBox(QWidget *, ChannelData *channel, MsgId msgId); protected: void prepare() override; @@ -164,16 +168,15 @@ class PinMessageBox : public BoxContent, public RPCSender { MsgId _msgId; object_ptr _text; - object_ptr _notify; + object_ptr _notify = {nullptr}; mtpRequestId _requestId = 0; - }; class DeleteMessagesBox : public BoxContent, public RPCSender { public: - DeleteMessagesBox(QWidget*, HistoryItem *item, bool suggestModerateActions); - DeleteMessagesBox(QWidget*, const SelectedItemSet &selected); + DeleteMessagesBox(QWidget *, HistoryItem *item, bool suggestModerateActions); + DeleteMessagesBox(QWidget *, const SelectedItemSet &selected); protected: void prepare() override; @@ -191,17 +194,17 @@ class DeleteMessagesBox : public BoxContent, public RPCSender { bool _moderateBan = false; bool _moderateDeleteAll = false; - object_ptr _text = { nullptr }; - object_ptr _forEveryone = { nullptr }; - object_ptr _banUser = { nullptr }; - object_ptr _reportSpam = { nullptr }; - object_ptr _deleteAll = { nullptr }; - + object_ptr _text = {nullptr}; + object_ptr _forEveryone = {nullptr}; + object_ptr _banUser = {nullptr}; + object_ptr _reportSpam = {nullptr}; + object_ptr _deleteAll = {nullptr}; }; class ConfirmInviteBox : public BoxContent, public RPCSender { public: - ConfirmInviteBox(QWidget*, const QString &title, bool isChannel, const MTPChatPhoto &photo, int count, const QVector &participants); + ConfirmInviteBox(QWidget *, const QString &title, bool isChannel, const MTPChatPhoto &photo, int count, + const QVector &participants); protected: void prepare() override; @@ -214,8 +217,7 @@ class ConfirmInviteBox : public BoxContent, public RPCSender { object_ptr _status; ImagePtr _photo; EmptyUserpic _photoEmpty; - QVector _participants; + QVector _participants; int _userWidth = 0; - }; diff --git a/Telegram/SourceFiles/boxes/confirm_phone_box.cpp b/Telegram/SourceFiles/boxes/confirm_phone_box.cpp index 1b2724198..4d8cd8a99 100644 --- a/Telegram/SourceFiles/boxes/confirm_phone_box.cpp +++ b/Telegram/SourceFiles/boxes/confirm_phone_box.cpp @@ -1,36 +1,38 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/confirm_phone_box.h" -#include "styles/style_boxes.h" #include "boxes/confirm_box.h" +#include "lang/lang_keys.h" +#include "mainwidget.h" +#include "styles/style_boxes.h" #include "ui/widgets/buttons.h" #include "ui/widgets/input_fields.h" #include "ui/widgets/labels.h" -#include "mainwidget.h" -#include "lang/lang_keys.h" namespace { -object_ptr CurrentConfirmPhoneBox = { nullptr }; +object_ptr CurrentConfirmPhoneBox = {nullptr}; } // namespace @@ -89,10 +91,10 @@ void SentCodeField::fix() { } } -SentCodeCall::SentCodeCall(QObject *parent, base::lambda_once callCallback, base::lambda updateCallback) -: _timer(parent) -, _call(std::move(callCallback)) -, _update(std::move(updateCallback)) { +SentCodeCall::SentCodeCall(QObject *parent, FnMut callCallback, Fn updateCallback) + : _timer(parent) + , _call(std::move(callCallback)) + , _update(std::move(updateCallback)) { _timer->connect(_timer, &QTimer::timeout, [this] { if (_status.state == State::Waiting) { if (--_status.timeout <= 0) { @@ -120,9 +122,13 @@ QString SentCodeCall::getText() const { switch (_status.state) { case State::Waiting: { if (_status.timeout >= 3600) { - return lng_code_call(lt_minutes, qsl("%1:%2").arg(_status.timeout / 3600).arg((_status.timeout / 60) % 60, 2, 10, QChar('0')), lt_seconds, qsl("%1").arg(_status.timeout % 60, 2, 10, QChar('0'))); + return lng_code_call( + lt_minutes, + qsl("%1:%2").arg(_status.timeout / 3600).arg((_status.timeout / 60) % 60, 2, 10, QChar('0')), + lt_seconds, qsl("%1").arg(_status.timeout % 60, 2, 10, QChar('0'))); } - return lng_code_call(lt_minutes, QString::number(_status.timeout / 60), lt_seconds, qsl("%1").arg(_status.timeout % 60, 2, 10, QChar('0'))); + return lng_code_call(lt_minutes, QString::number(_status.timeout / 60), lt_seconds, + qsl("%1").arg(_status.timeout % 60, 2, 10, QChar('0'))); } break; case State::Calling: return lang(lng_code_calling); case State::Called: return lang(lng_code_called); @@ -140,11 +146,10 @@ void ConfirmPhoneBox::start(const QString &phone, const QString &hash) { CurrentConfirmPhoneBox->checkPhoneAndHash(); } -ConfirmPhoneBox::ConfirmPhoneBox(QWidget*, const QString &phone, const QString &hash) -: _phone(phone) -, _hash(hash) -, _call(this, [this] { sendCall(); }, [this] { update(); }) { -} +ConfirmPhoneBox::ConfirmPhoneBox(QWidget *, const QString &phone, const QString &hash) + : _phone(phone) + , _hash(hash) + , _call(this, [this] { sendCall(); }, [this] { update(); }) {} void ConfirmPhoneBox::sendCall() { MTP::send(MTPauth_ResendCode(MTP_string(_phone), MTP_string(_phoneHash)), rpcDone(&ConfirmPhoneBox::callDone)); @@ -154,7 +159,8 @@ void ConfirmPhoneBox::checkPhoneAndHash() { if (_sendCodeRequestId) { return; } - _sendCodeRequestId = MTP::send(MTPaccount_SendConfirmPhoneCode(MTP_flags(0), MTP_string(_hash), MTPBool()), rpcDone(&ConfirmPhoneBox::sendCodeDone), rpcFail(&ConfirmPhoneBox::sendCodeFail)); + _sendCodeRequestId = MTP::send(MTPaccount_SendConfirmPhoneCode(MTP_flags(0), MTP_string(_hash), MTPBool()), + rpcDone(&ConfirmPhoneBox::sendCodeDone), rpcFail(&ConfirmPhoneBox::sendCodeFail)); } void ConfirmPhoneBox::sendCodeDone(const MTPauth_SentCode &result) { @@ -170,7 +176,7 @@ void ConfirmPhoneBox::sendCodeDone(const MTPauth_SentCode &result) { } _phoneHash = qs(resultInner.vphone_code_hash); if (resultInner.has_next_type() && resultInner.vnext_type.type() == mtpc_auth_codeTypeCall) { - _call.setStatus({ SentCodeCall::State::Waiting, resultInner.has_timeout() ? resultInner.vtimeout.v : 60 }); + _call.setStatus({SentCodeCall::State::Waiting, resultInner.has_timeout() ? resultInner.vtimeout.v : 60}); } launch(); } @@ -219,7 +225,8 @@ void ConfirmPhoneBox::prepare() { addButton(langFactory(lng_confirm_phone_send), [this] { onSendCode(); }); addButton(langFactory(lng_cancel), [this] { closeBox(); }); - setDimensions(st::boxWidth, st::usernamePadding.top() + _code->height() + st::usernameSkip + _about->height() + st::usernameSkip); + setDimensions(st::boxWidth, + st::usernamePadding.top() + _code->height() + st::usernameSkip + _about->height() + st::usernameSkip); connect(_code, SIGNAL(submitted(bool)), this, SLOT(onSendCode())); @@ -245,7 +252,8 @@ void ConfirmPhoneBox::onSendCode() { showError(QString()); - _sendCodeRequestId = MTP::send(MTPaccount_ConfirmPhone(MTP_string(_phoneHash), MTP_string(_code->getLastText())), rpcDone(&ConfirmPhoneBox::confirmDone), rpcFail(&ConfirmPhoneBox::confirmFail)); + _sendCodeRequestId = MTP::send(MTPaccount_ConfirmPhone(MTP_string(_phoneHash), MTP_string(_code->getLastText())), + rpcDone(&ConfirmPhoneBox::confirmDone), rpcFail(&ConfirmPhoneBox::confirmFail)); } void ConfirmPhoneBox::confirmDone(const MTPBool &result) { diff --git a/Telegram/SourceFiles/boxes/confirm_phone_box.h b/Telegram/SourceFiles/boxes/confirm_phone_box.h index 88554f4de..b7d9141a8 100644 --- a/Telegram/SourceFiles/boxes/confirm_phone_box.h +++ b/Telegram/SourceFiles/boxes/confirm_phone_box.h @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "boxes/abstract_box.h" @@ -30,15 +32,17 @@ class FlatLabel; class SentCodeField : public Ui::InputField { public: - SentCodeField(QWidget *parent, const style::InputField &st, base::lambda placeholderFactory = base::lambda(), const QString &val = QString()) : Ui::InputField(parent, st, std::move(placeholderFactory), val) { + SentCodeField(QWidget *parent, const style::InputField &st, Fn placeholderFactory = Fn(), + const QString &val = QString()) + : Ui::InputField(parent, st, std::move(placeholderFactory), val) { connect(this, &Ui::InputField::changed, [this] { fix(); }); } - void setAutoSubmit(int length, base::lambda submitCallback) { + void setAutoSubmit(int length, Fn submitCallback) { _autoSubmitLength = length; _submitCallback = std::move(submitCallback); } - void setChangedCallback(base::lambda changedCallback) { + void setChangedCallback(Fn changedCallback) { _changedCallback = std::move(changedCallback); } @@ -49,14 +53,13 @@ class SentCodeField : public Ui::InputField { bool _fixing = false; int _autoSubmitLength = 0; - base::lambda _submitCallback; - base::lambda _changedCallback; - + Fn _submitCallback; + Fn _changedCallback; }; class SentCodeCall { public: - SentCodeCall(QObject *parent, base::lambda_once callCallback, base::lambda updateCallback); + SentCodeCall(QObject *parent, FnMut callCallback, Fn updateCallback); enum class State { Waiting, @@ -65,10 +68,10 @@ class SentCodeCall { Disabled, }; struct Status { - Status() { - } - Status(State state, int timeout) : state(state), timeout(timeout) { - } + Status() {} + Status(State state, int timeout) + : state(state) + , timeout(timeout) {} State state = State::Disabled; int timeout = 0; @@ -89,9 +92,8 @@ class SentCodeCall { private: Status _status; object_ptr _timer; - base::lambda_once _call; - base::lambda _update; - + FnMut _call; + Fn _update; }; class ConfirmPhoneBox : public BoxContent, public RPCSender { @@ -113,7 +115,7 @@ private slots: void resizeEvent(QResizeEvent *e) override; private: - ConfirmPhoneBox(QWidget*, const QString &phone, const QString &hash); + ConfirmPhoneBox(QWidget *, const QString &phone, const QString &hash); friend class object_ptr; void sendCall(); @@ -146,10 +148,9 @@ private slots: mtpRequestId _checkCodeRequestId = 0; - object_ptr _about = { nullptr }; - object_ptr _code = { nullptr }; + object_ptr _about = {nullptr}; + object_ptr _code = {nullptr}; QString _error; SentCodeCall _call; - }; diff --git a/Telegram/SourceFiles/boxes/connection_box.cpp b/Telegram/SourceFiles/boxes/connection_box.cpp index cf75dae50..8bce2d767 100644 --- a/Telegram/SourceFiles/boxes/connection_box.cpp +++ b/Telegram/SourceFiles/boxes/connection_box.cpp @@ -1,72 +1,80 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/connection_box.h" #include "boxes/confirm_box.h" +#include "history/history_location_manager.h" #include "lang/lang_keys.h" -#include "storage/localstorage.h" #include "mainwidget.h" #include "mainwindow.h" -#include "ui/widgets/checkbox.h" +#include "storage/localstorage.h" +#include "styles/style_boxes.h" #include "ui/widgets/buttons.h" +#include "ui/widgets/checkbox.h" #include "ui/widgets/input_fields.h" -#include "history/history_location_manager.h" -#include "styles/style_boxes.h" void ConnectionBox::ShowApplyProxyConfirmation(const QMap &fields) { auto server = fields.value(qsl("server")); auto port = fields.value(qsl("port")).toInt(); if (!server.isEmpty() && port != 0) { auto weakBox = std::make_shared>(nullptr); - auto box = Ui::show(Box(lng_sure_enable_socks(lt_server, server, lt_port, QString::number(port)), lang(lng_sure_enable), [fields, weakBox] { - auto p = ProxyData(); - p.host = fields.value(qsl("server")); - p.user = fields.value(qsl("user")); - p.password = fields.value(qsl("pass")); - p.port = fields.value(qsl("port")).toInt(); - Global::SetConnectionType(dbictTcpProxy); - Global::SetLastProxyType(dbictTcpProxy); - Global::SetConnectionProxy(p); - Local::writeSettings(); - Global::RefConnectionTypeChanged().notify(); - MTP::restart(); - reinitLocationManager(); - reinitWebLoadManager(); - if (*weakBox) (*weakBox)->closeBox(); - }), KeepOtherLayers); + auto box = Ui::show(Box(lng_sure_enable_socks(lt_server, server, lt_port, QString::number(port)), + lang(lng_sure_enable), + [fields, weakBox] { + auto p = ProxyData(); + p.host = fields.value(qsl("server")); + p.user = fields.value(qsl("user")); + p.password = fields.value(qsl("pass")); + p.port = fields.value(qsl("port")).toInt(); + Global::SetConnectionType(dbictTcpProxy); + Global::SetLastProxyType(dbictTcpProxy); + Global::SetConnectionProxy(p); + Local::writeSettings(); + Global::RefConnectionTypeChanged().notify(); + MTP::restart(); + reinitLocationManager(); + reinitWebLoadManager(); + if (*weakBox) (*weakBox)->closeBox(); + }), + KeepOtherLayers); *weakBox = box; } } ConnectionBox::ConnectionBox(QWidget *parent) -: _hostInput(this, st::connectionHostInputField, langFactory(lng_connection_host_ph), Global::ConnectionProxy().host) -, _portInput(this, st::connectionPortInputField, langFactory(lng_connection_port_ph), QString::number(Global::ConnectionProxy().port)) -, _userInput(this, st::connectionUserInputField, langFactory(lng_connection_user_ph), Global::ConnectionProxy().user) -, _passwordInput(this, st::connectionPasswordInputField, langFactory(lng_connection_password_ph), Global::ConnectionProxy().password) -, _typeGroup(std::make_shared>(Global::ConnectionType())) -, _autoRadio(this, _typeGroup, dbictAuto, lang(lng_connection_auto_rb), st::defaultBoxCheckbox) -, _httpProxyRadio(this, _typeGroup, dbictHttpProxy, lang(lng_connection_http_proxy_rb), st::defaultBoxCheckbox) -, _tcpProxyRadio(this, _typeGroup, dbictTcpProxy, lang(lng_connection_tcp_proxy_rb), st::defaultBoxCheckbox) -, _tryIPv6(this, lang(lng_connection_try_ipv6), Global::TryIPv6(), st::defaultBoxCheckbox) { -} + : _hostInput(this, st::connectionHostInputField, langFactory(lng_connection_host_ph), + Global::ConnectionProxy().host) + , _portInput(this, st::connectionPortInputField, langFactory(lng_connection_port_ph), + QString::number(Global::ConnectionProxy().port)) + , _userInput(this, st::connectionUserInputField, langFactory(lng_connection_user_ph), + Global::ConnectionProxy().user) + , _passwordInput(this, st::connectionPasswordInputField, langFactory(lng_connection_password_ph), + Global::ConnectionProxy().password) + , _typeGroup(std::make_shared>(Global::ConnectionType())) + , _autoRadio(this, _typeGroup, dbictAuto, lang(lng_connection_auto_rb), st::defaultBoxCheckbox) + , _httpProxyRadio(this, _typeGroup, dbictHttpProxy, lang(lng_connection_http_proxy_rb), st::defaultBoxCheckbox) + , _tcpProxyRadio(this, _typeGroup, dbictTcpProxy, lang(lng_connection_tcp_proxy_rb), st::defaultBoxCheckbox) + , _tryIPv6(this, lang(lng_connection_try_ipv6), Global::TryIPv6(), st::defaultBoxCheckbox) {} void ConnectionBox::prepare() { setTitle(langFactory(lng_connection_header)); @@ -93,7 +101,10 @@ bool ConnectionBox::badProxyValue() const { } void ConnectionBox::updateControlsVisibility() { - auto newHeight = st::boxOptionListPadding.top() + _autoRadio->heightNoMargins() + st::boxOptionListSkip + _httpProxyRadio->heightNoMargins() + st::boxOptionListSkip + _tcpProxyRadio->heightNoMargins() + st::boxOptionListSkip + st::connectionIPv6Skip + _tryIPv6->heightNoMargins() + st::defaultCheckbox.margin.bottom() + st::boxOptionListPadding.bottom() + st::boxPadding.bottom(); + auto newHeight = st::boxOptionListPadding.top() + _autoRadio->heightNoMargins() + st::boxOptionListSkip + + _httpProxyRadio->heightNoMargins() + st::boxOptionListSkip + _tcpProxyRadio->heightNoMargins() + + st::boxOptionListSkip + st::connectionIPv6Skip + _tryIPv6->heightNoMargins() + + st::defaultCheckbox.margin.bottom() + st::boxOptionListPadding.bottom() + st::boxPadding.bottom(); if (_typeGroup->value() == dbictAuto && badProxyValue()) { _hostInput->hide(); _portInput->hide(); @@ -127,31 +138,42 @@ void ConnectionBox::resizeEvent(QResizeEvent *e) { void ConnectionBox::updateControlsPosition() { auto type = _typeGroup->value(); - _autoRadio->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), _autoRadio->getMargins().top() + st::boxOptionListPadding.top()); - _httpProxyRadio->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), _autoRadio->bottomNoMargins() + st::boxOptionListSkip); + _autoRadio->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), + _autoRadio->getMargins().top() + st::boxOptionListPadding.top()); + _httpProxyRadio->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), + _autoRadio->bottomNoMargins() + st::boxOptionListSkip); auto inputy = 0; auto fieldsVisible = (type != dbictAuto) || (!badProxyValue() && Global::LastProxyType() != dbictAuto); - auto fieldsBelowHttp = fieldsVisible && (type == dbictHttpProxy || (type == dbictAuto && Global::LastProxyType() == dbictHttpProxy)); - auto fieldsBelowTcp = fieldsVisible && (type == dbictTcpProxy || (type == dbictAuto && Global::LastProxyType() == dbictTcpProxy)); + auto fieldsBelowHttp = + fieldsVisible && (type == dbictHttpProxy || (type == dbictAuto && Global::LastProxyType() == dbictHttpProxy)); + auto fieldsBelowTcp = + fieldsVisible && (type == dbictTcpProxy || (type == dbictAuto && Global::LastProxyType() == dbictTcpProxy)); if (fieldsBelowHttp) { inputy = _httpProxyRadio->bottomNoMargins() + st::boxOptionInputSkip; - _tcpProxyRadio->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), inputy + st::boxOptionInputSkip + 2 * _hostInput->height() + st::boxOptionListSkip); + _tcpProxyRadio->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), + inputy + st::boxOptionInputSkip + 2 * _hostInput->height() + st::boxOptionListSkip); } else { - _tcpProxyRadio->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), _httpProxyRadio->bottomNoMargins() + st::boxOptionListSkip); + _tcpProxyRadio->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), + _httpProxyRadio->bottomNoMargins() + st::boxOptionListSkip); if (fieldsBelowTcp) { inputy = _tcpProxyRadio->bottomNoMargins() + st::boxOptionInputSkip; } } if (inputy) { - _hostInput->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left() + st::defaultCheck.diameter + st::defaultBoxCheckbox.textPosition.x() - st::defaultInputField.textMargins.left(), inputy); + _hostInput->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left() + st::defaultCheck.diameter + + st::defaultBoxCheckbox.textPosition.x() - st::defaultInputField.textMargins.left(), + inputy); _portInput->moveToRight(st::boxPadding.right(), inputy); - _userInput->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left() + st::defaultCheck.diameter + st::defaultBoxCheckbox.textPosition.x() - st::defaultInputField.textMargins.left(), _hostInput->y() + _hostInput->height() + st::boxOptionInputSkip); + _userInput->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left() + st::defaultCheck.diameter + + st::defaultBoxCheckbox.textPosition.x() - st::defaultInputField.textMargins.left(), + _hostInput->y() + _hostInput->height() + st::boxOptionInputSkip); _passwordInput->moveToRight(st::boxPadding.right(), _userInput->y()); } - auto tryipv6y = (fieldsBelowTcp ? _userInput->bottomNoMargins() : _tcpProxyRadio->bottomNoMargins()) + st::boxOptionListSkip + st::connectionIPv6Skip; + auto tryipv6y = (fieldsBelowTcp ? _userInput->bottomNoMargins() : _tcpProxyRadio->bottomNoMargins()) + + st::boxOptionListSkip + st::connectionIPv6Skip; _tryIPv6->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), tryipv6y); } @@ -162,7 +184,8 @@ void ConnectionBox::typeChanged(DBIConnectionType type) { updateControlsVisibility(); if (type != dbictAuto) { Global::SetLastProxyType(type); - if (!_hostInput->hasFocus() && !_portInput->hasFocus() && !_userInput->hasFocus() && !_passwordInput->hasFocus()) { + if (!_hostInput->hasFocus() && !_portInput->hasFocus() && !_userInput->hasFocus() && + !_passwordInput->hasFocus()) { _hostInput->setFocusFast(); } if ((type == dbictHttpProxy) && !_portInput->getLastText().toInt()) { @@ -257,21 +280,24 @@ void ConnectionBox::onSave() { } AutoDownloadBox::AutoDownloadBox(QWidget *parent) -: _photoPrivate(this, lang(lng_media_auto_private_chats), !(cAutoDownloadPhoto() & dbiadNoPrivate), st::defaultBoxCheckbox) -, _photoGroups(this, lang(lng_media_auto_groups), !(cAutoDownloadPhoto() & dbiadNoGroups), st::defaultBoxCheckbox) -, _audioPrivate(this, lang(lng_media_auto_private_chats), !(cAutoDownloadAudio() & dbiadNoPrivate), st::defaultBoxCheckbox) -, _audioGroups(this, lang(lng_media_auto_groups), !(cAutoDownloadAudio() & dbiadNoGroups), st::defaultBoxCheckbox) -, _gifPrivate(this, lang(lng_media_auto_private_chats), !(cAutoDownloadGif() & dbiadNoPrivate), st::defaultBoxCheckbox) -, _gifGroups(this, lang(lng_media_auto_groups), !(cAutoDownloadGif() & dbiadNoGroups), st::defaultBoxCheckbox) -, _gifPlay(this, lang(lng_media_auto_play), cAutoPlayGif(), st::defaultBoxCheckbox) -, _sectionHeight(st::boxTitleHeight + 2 * (st::defaultCheck.diameter + st::setLittleSkip)) { -} + : _photoPrivate(this, lang(lng_media_auto_private_chats), !(cAutoDownloadPhoto() & dbiadNoPrivate), + st::defaultBoxCheckbox) + , _photoGroups(this, lang(lng_media_auto_groups), !(cAutoDownloadPhoto() & dbiadNoGroups), st::defaultBoxCheckbox) + , _audioPrivate(this, lang(lng_media_auto_private_chats), !(cAutoDownloadAudio() & dbiadNoPrivate), + st::defaultBoxCheckbox) + , _audioGroups(this, lang(lng_media_auto_groups), !(cAutoDownloadAudio() & dbiadNoGroups), st::defaultBoxCheckbox) + , _gifPrivate(this, lang(lng_media_auto_private_chats), !(cAutoDownloadGif() & dbiadNoPrivate), + st::defaultBoxCheckbox) + , _gifGroups(this, lang(lng_media_auto_groups), !(cAutoDownloadGif() & dbiadNoGroups), st::defaultBoxCheckbox) + , _gifPlay(this, lang(lng_media_auto_play), cAutoPlayGif(), st::defaultBoxCheckbox) + , _sectionHeight(st::boxTitleHeight + 2 * (st::defaultCheck.diameter + st::setLittleSkip)) {} void AutoDownloadBox::prepare() { addButton(langFactory(lng_connection_save), [this] { onSave(); }); addButton(langFactory(lng_cancel), [this] { closeBox(); }); - setDimensions(st::boxWidth, 3 * _sectionHeight - st::autoDownloadTopDelta + st::setLittleSkip + _gifPlay->heightNoMargins() + st::setLittleSkip); + setDimensions(st::boxWidth, 3 * _sectionHeight - st::autoDownloadTopDelta + st::setLittleSkip + + _gifPlay->heightNoMargins() + st::setLittleSkip); } void AutoDownloadBox::paintEvent(QPaintEvent *e) { @@ -281,9 +307,12 @@ void AutoDownloadBox::paintEvent(QPaintEvent *e) { p.setPen(st::boxTitleFg); p.setFont(st::autoDownloadTitleFont); - p.drawTextLeft(st::autoDownloadTitlePosition.x(), st::autoDownloadTitlePosition.y(), width(), lang(lng_media_auto_photo)); - p.drawTextLeft(st::autoDownloadTitlePosition.x(), _sectionHeight + st::autoDownloadTitlePosition.y(), width(), lang(lng_media_auto_audio)); - p.drawTextLeft(st::autoDownloadTitlePosition.x(), 2 * _sectionHeight + st::autoDownloadTitlePosition.y(), width(), lang(lng_media_auto_gif)); + p.drawTextLeft(st::autoDownloadTitlePosition.x(), st::autoDownloadTitlePosition.y(), width(), + lang(lng_media_auto_photo)); + p.drawTextLeft(st::autoDownloadTitlePosition.x(), _sectionHeight + st::autoDownloadTitlePosition.y(), width(), + lang(lng_media_auto_audio)); + p.drawTextLeft(st::autoDownloadTitlePosition.x(), 2 * _sectionHeight + st::autoDownloadTitlePosition.y(), width(), + lang(lng_media_auto_gif)); } void AutoDownloadBox::resizeEvent(QResizeEvent *e) { @@ -303,7 +332,8 @@ void AutoDownloadBox::resizeEvent(QResizeEvent *e) { void AutoDownloadBox::onSave() { bool changed = false; - int32 autoDownloadPhoto = (_photoPrivate->checked() ? 0 : dbiadNoPrivate) | (_photoGroups->checked() ? 0 : dbiadNoGroups); + qint32 autoDownloadPhoto = + (_photoPrivate->checked() ? 0 : dbiadNoPrivate) | (_photoGroups->checked() ? 0 : dbiadNoGroups); if (cAutoDownloadPhoto() != autoDownloadPhoto) { bool enabledPrivate = ((cAutoDownloadPhoto() & dbiadNoPrivate) && !(autoDownloadPhoto & dbiadNoPrivate)); bool enabledGroups = ((cAutoDownloadPhoto() & dbiadNoGroups) && !(autoDownloadPhoto & dbiadNoGroups)); @@ -316,7 +346,8 @@ void AutoDownloadBox::onSave() { } changed = true; } - int32 autoDownloadAudio = (_audioPrivate->checked() ? 0 : dbiadNoPrivate) | (_audioGroups->checked() ? 0 : dbiadNoGroups); + qint32 autoDownloadAudio = + (_audioPrivate->checked() ? 0 : dbiadNoPrivate) | (_audioGroups->checked() ? 0 : dbiadNoGroups); if (cAutoDownloadAudio() != autoDownloadAudio) { bool enabledPrivate = ((cAutoDownloadAudio() & dbiadNoPrivate) && !(autoDownloadAudio & dbiadNoPrivate)); bool enabledGroups = ((cAutoDownloadAudio() & dbiadNoGroups) && !(autoDownloadAudio & dbiadNoGroups)); @@ -330,7 +361,8 @@ void AutoDownloadBox::onSave() { } changed = true; } - int32 autoDownloadGif = (_gifPrivate->checked() ? 0 : dbiadNoPrivate) | (_gifGroups->checked() ? 0 : dbiadNoGroups); + qint32 autoDownloadGif = + (_gifPrivate->checked() ? 0 : dbiadNoPrivate) | (_gifGroups->checked() ? 0 : dbiadNoGroups); if (cAutoDownloadGif() != autoDownloadGif) { bool enabledPrivate = ((cAutoDownloadGif() & dbiadNoPrivate) && !(autoDownloadGif & dbiadNoPrivate)); bool enabledGroups = ((cAutoDownloadGif() & dbiadNoGroups) && !(autoDownloadGif & dbiadNoGroups)); diff --git a/Telegram/SourceFiles/boxes/connection_box.h b/Telegram/SourceFiles/boxes/connection_box.h index 2256db6fa..72bf204f8 100644 --- a/Telegram/SourceFiles/boxes/connection_box.h +++ b/Telegram/SourceFiles/boxes/connection_box.h @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "boxes/abstract_box.h" @@ -27,10 +29,8 @@ class InputField; class PortInput; class PasswordInput; class Checkbox; -template -class RadioenumGroup; -template -class Radioenum; +template class RadioenumGroup; +template class Radioenum; } // namespace Ui class ConnectionBox : public BoxContent { @@ -67,7 +67,6 @@ private slots: object_ptr> _httpProxyRadio; object_ptr> _tcpProxyRadio; object_ptr _tryIPv6; - }; class AutoDownloadBox : public BoxContent { @@ -95,5 +94,4 @@ private slots: object_ptr _gifPlay; int _sectionHeight = 0; - }; diff --git a/Telegram/SourceFiles/boxes/download_path_box.cpp b/Telegram/SourceFiles/boxes/download_path_box.cpp index b2dfa61a4..42ca88e28 100644 --- a/Telegram/SourceFiles/boxes/download_path_box.cpp +++ b/Telegram/SourceFiles/boxes/download_path_box.cpp @@ -1,42 +1,44 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/download_path_box.h" -#include "lang/lang_keys.h" -#include "storage/localstorage.h" #include "core/file_utilities.h" -#include "ui/widgets/checkbox.h" -#include "ui/widgets/buttons.h" +#include "facades.h" +#include "lang/lang_keys.h" #include "platform/platform_specific.h" +#include "storage/localstorage.h" #include "styles/style_boxes.h" +#include "ui/widgets/buttons.h" +#include "ui/widgets/checkbox.h" DownloadPathBox::DownloadPathBox(QWidget *parent) -: _path(Global::DownloadPath()) -, _pathBookmark(Global::DownloadPathBookmark()) -, _group(std::make_shared>(typeFromPath(_path))) -, _default(this, _group, Directory::Downloads, lang(lng_download_path_default_radio), st::defaultBoxCheckbox) -, _temp(this, _group, Directory::Temp, lang(lng_download_path_temp_radio), st::defaultBoxCheckbox) -, _dir(this, _group, Directory::Custom, lang(lng_download_path_dir_radio), st::defaultBoxCheckbox) -, _pathLink(this, QString(), st::boxLinkButton) { -} + : _path(Global::DownloadPath()) + , _pathBookmark(Global::DownloadPathBookmark()) + , _group(std::make_shared>(typeFromPath(_path))) + , _default(this, _group, Directory::Downloads, lang(lng_download_path_default_radio), st::defaultBoxCheckbox) + , _temp(this, _group, Directory::Temp, lang(lng_download_path_temp_radio), st::defaultBoxCheckbox) + , _dir(this, _group, Directory::Custom, lang(lng_download_path_dir_radio), st::defaultBoxCheckbox) + , _pathLink(this, QString(), st::boxLinkButton) {} void DownloadPathBox::prepare() { addButton(langFactory(lng_connection_save), [this] { save(); }); @@ -57,7 +59,8 @@ void DownloadPathBox::updateControlsVisibility() { auto custom = (_group->value() == Directory::Custom); _pathLink->setVisible(custom); - auto newHeight = st::boxOptionListPadding.top() + _default->getMargins().top() + _default->heightNoMargins() + st::boxOptionListSkip + _temp->heightNoMargins() + st::boxOptionListSkip + _dir->heightNoMargins(); + auto newHeight = st::boxOptionListPadding.top() + _default->getMargins().top() + _default->heightNoMargins() + + st::boxOptionListSkip + _temp->heightNoMargins() + st::boxOptionListSkip + _dir->heightNoMargins(); if (custom) { newHeight += st::downloadPathSkip + _pathLink->height(); } @@ -69,10 +72,14 @@ void DownloadPathBox::updateControlsVisibility() { void DownloadPathBox::resizeEvent(QResizeEvent *e) { BoxContent::resizeEvent(e); - _default->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), st::boxOptionListPadding.top() + _default->getMargins().top()); - _temp->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), _default->bottomNoMargins() + st::boxOptionListSkip); - _dir->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), _temp->bottomNoMargins() + st::boxOptionListSkip); - auto inputx = st::boxPadding.left() + st::boxOptionListPadding.left() + st::defaultCheck.diameter + st::defaultBoxCheckbox.textPosition.x(); + _default->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), + st::boxOptionListPadding.top() + _default->getMargins().top()); + _temp->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), + _default->bottomNoMargins() + st::boxOptionListSkip); + _dir->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), + _temp->bottomNoMargins() + st::boxOptionListSkip); + auto inputx = st::boxPadding.left() + st::boxOptionListPadding.left() + st::defaultCheck.diameter + + st::defaultBoxCheckbox.textPosition.x(); auto inputy = _dir->bottomNoMargins() + st::downloadPathSkip; _pathLink->moveToLeft(inputx, inputy); @@ -98,18 +105,20 @@ void DownloadPathBox::radioChanged(Directory value) { void DownloadPathBox::onEditPath() { auto initialPath = [] { if (!Global::DownloadPath().isEmpty() && Global::DownloadPath() != qstr("tmp")) { - return Global::DownloadPath().left(Global::DownloadPath().size() - (Global::DownloadPath().endsWith('/') ? 1 : 0)); + return Global::DownloadPath().left(Global::DownloadPath().size() - + (Global::DownloadPath().endsWith('/') ? 1 : 0)); } return QString(); }; - FileDialog::GetFolder(lang(lng_download_path_choose), initialPath(), base::lambda_guarded(this, [this](const QString &result) { - if (!result.isEmpty()) { - _path = result + '/'; - _pathBookmark = psDownloadPathBookmark(_path); - setPathText(QDir::toNativeSeparators(_path)); - _group->setValue(Directory::Custom); - } - })); + FileDialog::GetFolder(lang(lng_download_path_choose), initialPath(), + base::lambda_guarded(this, [this](const QString &result) { + if (!result.isEmpty()) { + _path = result + '/'; + _pathBookmark = psDownloadPathBookmark(_path); + setPathText(QDir::toNativeSeparators(_path)); + _group->setValue(Directory::Custom); + } + })); } void DownloadPathBox::save() { @@ -132,6 +141,7 @@ void DownloadPathBox::save() { } void DownloadPathBox::setPathText(const QString &text) { - auto availw = st::boxWideWidth - st::boxPadding.left() - st::defaultCheck.diameter - st::defaultBoxCheckbox.textPosition.x() - st::boxPadding.right(); + auto availw = st::boxWideWidth - st::boxPadding.left() - st::defaultCheck.diameter - + st::defaultBoxCheckbox.textPosition.x() - st::boxPadding.right(); _pathLink->setText(st::boxTextFont->elided(text, availw)); } diff --git a/Telegram/SourceFiles/boxes/download_path_box.h b/Telegram/SourceFiles/boxes/download_path_box.h index d2a52ae10..977ce6ead 100644 --- a/Telegram/SourceFiles/boxes/download_path_box.h +++ b/Telegram/SourceFiles/boxes/download_path_box.h @@ -1,33 +1,33 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once -#include "boxes/abstract_box.h" #include "base/observer.h" +#include "boxes/abstract_box.h" namespace Ui { -template -class RadioenumGroup; -template -class Radioenum; +template class RadioenumGroup; +template class Radioenum; class LinkButton; } // namespace Ui @@ -73,5 +73,4 @@ private slots: object_ptr> _temp; object_ptr> _dir; object_ptr _pathLink; - }; diff --git a/Telegram/SourceFiles/boxes/edit_color_box.cpp b/Telegram/SourceFiles/boxes/edit_color_box.cpp index 897da15fb..e01b6c5c0 100644 --- a/Telegram/SourceFiles/boxes/edit_color_box.cpp +++ b/Telegram/SourceFiles/boxes/edit_color_box.cpp @@ -1,39 +1,42 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/edit_color_box.h" +#include "app.h" #include "lang/lang_keys.h" #include "styles/style_boxes.h" -#include "ui/widgets/shadow.h" #include "styles/style_mediaview.h" #include "ui/widgets/input_fields.h" +#include "ui/widgets/shadow.h" class EditColorBox::Picker : public TWidget { public: Picker(QWidget *parent, QColor color); - float64 valueX() const { + double valueX() const { return _x; } - float64 valueY() const { + double valueY() const { return _y; } @@ -64,12 +67,11 @@ class EditColorBox::Picker : public TWidget { QImage _palette; bool _paletteInvalidated = false; - float64 _x = 0.; - float64 _y = 0.; + double _x = 0.; + double _y = 0.; bool _choosing = false; base::Observable _changed; - }; QCursor EditColorBox::Picker::generateCursor() { @@ -96,7 +98,8 @@ QCursor EditColorBox::Picker::generateCursor() { return QCursor(QPixmap::fromImage(cursor)); } -EditColorBox::Picker::Picker(QWidget *parent, QColor color) : TWidget(parent) { +EditColorBox::Picker::Picker(QWidget *parent, QColor color) + : TWidget(parent) { setCursor(generateCursor()); auto size = QSize(st::colorPickerSize, st::colorPickerSize); @@ -127,7 +130,8 @@ void EditColorBox::Picker::paintEvent(QPaintEvent *e) { auto y = anim::interpolate(0, height() - 1, _y); PainterHighQualityEnabler hq(p); - p.drawEllipse(QRect(x - st::colorPickerMarkRadius, y - st::colorPickerMarkRadius, 2 * st::colorPickerMarkRadius, 2 * st::colorPickerMarkRadius)); + p.drawEllipse(QRect(x - st::colorPickerMarkRadius, y - st::colorPickerMarkRadius, 2 * st::colorPickerMarkRadius, + 2 * st::colorPickerMarkRadius)); } void EditColorBox::Picker::mousePressEvent(QMouseEvent *e) { @@ -150,8 +154,8 @@ void EditColorBox::Picker::preparePalette() { _paletteInvalidated = false; auto size = _palette.width(); - auto ints = reinterpret_cast(_palette.bits()); - auto intsAddPerLine = (_palette.bytesPerLine() - size * sizeof(uint32)) / sizeof(uint32); + auto ints = reinterpret_cast(_palette.bits()); + auto intsAddPerLine = (_palette.bytesPerLine() - size * sizeof(quint32)) / sizeof(quint32); constexpr auto Large = 1024 * 1024; constexpr auto LargeBit = 20; // n / Large == (n >> LargeBit) @@ -190,8 +194,8 @@ void EditColorBox::Picker::preparePalette() { } void EditColorBox::Picker::updateCurrentPoint(QPoint localPosition) { - auto x = snap(localPosition.x(), 0, width()) / float64(width()); - auto y = snap(localPosition.y(), 0, height()) / float64(height()); + auto x = snap(localPosition.x(), 0, width()) / double(width()); + auto y = snap(localPosition.y(), 0, height()) / double(height()); if (_x != x || _y != y) { _x = x; _y = y; @@ -202,7 +206,7 @@ void EditColorBox::Picker::updateCurrentPoint(QPoint localPosition) { void EditColorBox::Picker::setHSV(int hue, int saturation, int brightness) { _topleft = QColor(255, 255, 255); - _topright.setHsv(qMax(0, hue), 255, 255); + _topright.setHsv(std::max(0, hue), 255, 255); _topright = _topright.toRgb(); _bottomleft = _bottomright = QColor(0, 0, 0); @@ -236,10 +240,10 @@ class EditColorBox::Slider : public TWidget { base::Observable &changed() { return _changed; } - float64 value() const { + double value() const { return _value; } - void setValue(float64 value) { + void setValue(double value) { _value = snap(value, 0., 1.); update(); } @@ -256,8 +260,8 @@ class EditColorBox::Slider : public TWidget { void mouseReleaseEvent(QMouseEvent *e) override; private: - float64 valueFromColor(QColor color) const; - float64 valueFromHue(int hue) const; + double valueFromColor(QColor color) const; + double valueFromHue(int hue) const; bool isHorizontal() const { return (_direction == Direction::Horizontal); } @@ -271,7 +275,7 @@ class EditColorBox::Slider : public TWidget { Type _type = Type::Hue; QColor _color; - float64 _value = 0; + double _value = 0; QImage _mask; QPixmap _pixmap; @@ -279,15 +283,15 @@ class EditColorBox::Slider : public TWidget { bool _choosing = false; base::Observable _changed; - }; -EditColorBox::Slider::Slider(QWidget *parent, Direction direction, Type type, QColor color) : TWidget(parent) -, _direction(direction) -, _type(type) -, _color(color.red(), color.green(), color.blue()) -, _value(valueFromColor(color)) -, _transparent((_type == Type::Hue) ? QBrush() : style::transparentPlaceholderBrush()) { +EditColorBox::Slider::Slider(QWidget *parent, Direction direction, Type type, QColor color) + : TWidget(parent) + , _direction(direction) + , _type(type) + , _color(color.red(), color.green(), color.blue()) + , _value(valueFromColor(color)) + , _transparent((_type == Type::Hue) ? QBrush() : style::transparentPlaceholderBrush()) { prepareMinSize(); } @@ -298,20 +302,23 @@ void EditColorBox::Slider::prepareMinSize() { void EditColorBox::Slider::paintEvent(QPaintEvent *e) { Painter p(this); - auto to = rect().marginsRemoved(QMargins(st::colorSliderSkip, st::colorSliderSkip, st::colorSliderSkip, st::colorSliderSkip)); + auto to = rect().marginsRemoved( + QMargins(st::colorSliderSkip, st::colorSliderSkip, st::colorSliderSkip, st::colorSliderSkip)); Ui::Shadow::paint(p, to, width(), st::defaultRoundShadow); if (_type == Type::Opacity) { p.fillRect(to, _transparent); } p.drawPixmap(to, _pixmap, _pixmap.rect()); if (isHorizontal()) { - auto x = st::colorSliderSkip + qRound(_value * to.width()); + auto x = st::colorSliderSkip + std::round(_value * to.width()); st::colorSliderArrowTop.paint(p, x - st::colorSliderArrowTop.width() / 2, 0, width()); - st::colorSliderArrowBottom.paint(p, x - st::colorSliderArrowBottom.width() / 2, height() - st::colorSliderArrowBottom.height(), width()); + st::colorSliderArrowBottom.paint(p, x - st::colorSliderArrowBottom.width() / 2, + height() - st::colorSliderArrowBottom.height(), width()); } else { - auto y = st::colorSliderSkip + qRound(_value * to.height()); + auto y = st::colorSliderSkip + std::round(_value * to.height()); st::colorSliderArrowLeft.paint(p, 0, y - st::colorSliderArrowLeft.height() / 2, width()); - st::colorSliderArrowRight.paint(p, width() - st::colorSliderArrowRight.width(), y - st::colorSliderArrowRight.height() / 2, width()); + st::colorSliderArrowRight.paint(p, width() - st::colorSliderArrowRight.width(), + y - st::colorSliderArrowRight.height() / 2, width()); } } @@ -339,8 +346,8 @@ void EditColorBox::Slider::generatePixmap() { auto size = (isHorizontal() ? width() : height()) * cIntRetinaFactor(); auto image = QImage(size, cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied); image.setDevicePixelRatio(cRetinaFactor()); - auto ints = reinterpret_cast(image.bits()); - auto intsPerLine = image.bytesPerLine() / sizeof(uint32); + auto ints = reinterpret_cast(image.bits()); + auto intsPerLine = image.bytesPerLine() / sizeof(quint32); auto intsPerLineAdded = intsPerLine - size; constexpr auto Large = 1024 * 1024; @@ -408,11 +415,11 @@ void EditColorBox::Slider::colorUpdated() { update(); } -float64 EditColorBox::Slider::valueFromColor(QColor color) const { +double EditColorBox::Slider::valueFromColor(QColor color) const { return (_type == Type::Hue) ? valueFromHue(color.hsvHue()) : color.alphaF(); } -float64 EditColorBox::Slider::valueFromHue(int hue) const { +double EditColorBox::Slider::valueFromHue(int hue) const { return (1. - snap(hue, 0, 360) / 360.); } @@ -430,7 +437,7 @@ void EditColorBox::Slider::updatePixmapFromMask() { void EditColorBox::Slider::updateCurrentPoint(QPoint localPosition) { auto coord = (isHorizontal() ? localPosition.x() : localPosition.y()) - st::colorSliderSkip; auto maximum = (isHorizontal() ? width() : height()) - 2 * st::colorSliderSkip; - auto value = snap(coord, 0, maximum) / float64(maximum); + auto value = snap(coord, 0, maximum) / double(maximum); if (_value != value) { _value = value; update(); @@ -440,7 +447,8 @@ void EditColorBox::Slider::updateCurrentPoint(QPoint localPosition) { class EditColorBox::Field : public Ui::MaskedInputField { public: - Field(QWidget *parent, const style::InputField &st, const QString &placeholder, int limit, const QString &units = QString()); + Field(QWidget *parent, const style::InputField &st, const QString &placeholder, int limit, + const QString &units = QString()); int value() const { return getLastText().toInt(); @@ -467,15 +475,15 @@ class EditColorBox::Field : public Ui::MaskedInputField { int _limit = 0; int _digitLimit = 1; int _wheelDelta = 0; - }; -EditColorBox::Field::Field(QWidget *parent, const style::InputField &st, const QString &placeholder, int limit, const QString &units) : Ui::MaskedInputField(parent, st) -, _placeholder(placeholder) -, _units(units) -, _limit(limit) -, _digitLimit(QString::number(_limit).size()) { -} +EditColorBox::Field::Field(QWidget *parent, const style::InputField &st, const QString &placeholder, int limit, + const QString &units) + : Ui::MaskedInputField(parent, st) + , _placeholder(placeholder) + , _units(units) + , _limit(limit) + , _digitLimit(QString::number(_limit).size()) {} void EditColorBox::Field::correctValue(const QString &was, int wasCursor, QString &now, int &nowCursor) { QString newText; @@ -517,7 +525,8 @@ void EditColorBox::Field::correctValue(const QString &was, int wasCursor, QStrin void EditColorBox::Field::paintAdditionalPlaceholder(Painter &p, TimeMs ms) { p.setFont(_st.font); p.setPen(_st.placeholderFg); - auto inner = QRect(_st.textMargins.right(), _st.textMargins.top(), width() - 2 * _st.textMargins.right(), height() - _st.textMargins.top() - _st.textMargins.bottom()); + auto inner = QRect(_st.textMargins.right(), _st.textMargins.top(), width() - 2 * _st.textMargins.right(), + height() - _st.textMargins.top() - _st.textMargins.bottom()); p.drawText(inner, _placeholder, style::al_topleft); if (!_units.isEmpty()) { p.drawText(inner, _units, style::al_topright); @@ -579,11 +588,10 @@ class EditColorBox::ResultField : public Ui::MaskedInputField { protected: void correctValue(const QString &was, int wasCursor, QString &now, int &nowCursor) override; void paintAdditionalPlaceholder(Painter &p, TimeMs ms) override; - }; -EditColorBox::ResultField::ResultField(QWidget *parent, const style::InputField &st) : Ui::MaskedInputField(parent, st) { -} +EditColorBox::ResultField::ResultField(QWidget *parent, const style::InputField &st) + : Ui::MaskedInputField(parent, st) {} void EditColorBox::ResultField::correctValue(const QString &was, int wasCursor, QString &now, int &nowCursor) { QString newText; @@ -622,25 +630,27 @@ void EditColorBox::ResultField::correctValue(const QString &was, int wasCursor, void EditColorBox::ResultField::paintAdditionalPlaceholder(Painter &p, TimeMs ms) { p.setFont(_st.font); p.setPen(_st.placeholderFg); - p.drawText(QRect(_st.textMargins.right(), _st.textMargins.top(), width(), height() - _st.textMargins.top() - _st.textMargins.bottom()), "#", style::al_topleft); -} - -EditColorBox::EditColorBox(QWidget*, const QString &title, QColor current) : BoxContent() -, _title(title) -, _picker(this, current) -, _hueSlider(this, Slider::Direction::Vertical, Slider::Type::Hue, current) -, _opacitySlider(this, Slider::Direction::Horizontal, Slider::Type::Opacity, current) -, _hueField(this, st::colorValueInput, "H", 360, QString() + QChar(176)) // degree character -, _saturationField(this, st::colorValueInput, "S", 100, "%") -, _brightnessField(this, st::colorValueInput, "B", 100, "%") -, _redField(this, st::colorValueInput, "R", 255) -, _greenField(this, st::colorValueInput, "G", 255) -, _blueField(this, st::colorValueInput, "B", 255) -, _result(this, st::colorResultInput) -, _transparent(style::transparentPlaceholderBrush()) -, _current(current) -, _new(current) { -} + p.drawText(QRect(_st.textMargins.right(), _st.textMargins.top(), width(), + height() - _st.textMargins.top() - _st.textMargins.bottom()), + "#", style::al_topleft); +} + +EditColorBox::EditColorBox(QWidget *, const QString &title, QColor current) + : BoxContent() + , _title(title) + , _picker(this, current) + , _hueSlider(this, Slider::Direction::Vertical, Slider::Type::Hue, current) + , _opacitySlider(this, Slider::Direction::Horizontal, Slider::Type::Opacity, current) + , _hueField(this, st::colorValueInput, "H", 360, QString() + QChar(176)) // degree character + , _saturationField(this, st::colorValueInput, "S", 100, "%") + , _brightnessField(this, st::colorValueInput, "B", 100, "%") + , _redField(this, st::colorValueInput, "R", 255) + , _greenField(this, st::colorValueInput, "G", 255) + , _blueField(this, st::colorValueInput, "B", 255) + , _result(this, st::colorResultInput) + , _transparent(style::transparentPlaceholderBrush()) + , _current(current) + , _new(current) {} void EditColorBox::prepare() { setTitle([this] { return _title; }); @@ -664,7 +674,8 @@ void EditColorBox::prepare() { addButton(langFactory(lng_settings_save), [this] { saveColor(); }); addButton(langFactory(lng_cancel), [this] { closeBox(); }); - auto height = st::colorEditSkip + st::colorPickerSize + st::colorEditSkip + st::colorSliderWidth + st::colorEditSkip; + auto height = + st::colorEditSkip + st::colorPickerSize + st::colorEditSkip + st::colorSliderWidth + st::colorEditSkip; setDimensions(st::colorEditWidth, height); subscribe(_picker->changed(), [this] { updateFromControls(); }); @@ -707,15 +718,8 @@ void EditColorBox::onFieldChanged() { } void EditColorBox::onFieldSubmitted() { - Ui::MaskedInputField *fields[] = { - _hueField, - _saturationField, - _brightnessField, - _redField, - _greenField, - _blueField, - _result - }; + Ui::MaskedInputField *fields[] = {_hueField, _saturationField, _brightnessField, _redField, + _greenField, _blueField, _result}; for (auto i = 0, count = int(base::array_size(fields)); i + 1 != count; ++i) { if (fields[i]->hasFocus()) { fields[i + 1]->setFocus(); @@ -729,7 +733,7 @@ void EditColorBox::onFieldSubmitted() { } void EditColorBox::saveColor() { - _cancelCallback = base::lambda(); + _cancelCallback = Fn(); if (_saveCallback) { _saveCallback(_new.toRgb()); } @@ -737,10 +741,9 @@ void EditColorBox::saveColor() { } void EditColorBox::updateHSVFields() { - auto hue = qRound((1. - _hueSlider->value()) * 360); - auto saturation = qRound(_picker->valueX() * 255); - auto brightness = qRound((1. - _picker->valueY()) * 255); - auto alpha = qRound(_opacitySlider->value() * 255); + auto hue = std::round((1. - _hueSlider->value()) * 360); + auto saturation = std::round(_picker->valueX() * 255); + auto brightness = std::round((1. - _picker->valueY()) * 255); _hueField->setTextWithFocus(QString::number(hue)); _saturationField->setTextWithFocus(QString::number(percentFromByte(saturation))); _brightnessField->setTextWithFocus(QString::number(percentFromByte(brightness))); @@ -775,23 +778,33 @@ void EditColorBox::updateResultField() { } void EditColorBox::resizeEvent(QResizeEvent *e) { - auto fullwidth = _picker->width() + 2 * (st::colorEditSkip - st::colorSliderSkip) + _hueSlider->width() + st::colorSampleSize.width(); + auto fullwidth = _picker->width() + 2 * (st::colorEditSkip - st::colorSliderSkip) + _hueSlider->width() + + st::colorSampleSize.width(); auto left = (width() - fullwidth) / 2; _picker->moveToLeft(left, st::colorEditSkip); - _hueSlider->setGeometryToLeft(_picker->x() + _picker->width() + st::colorEditSkip - st::colorSliderSkip, st::colorEditSkip - st::colorSliderSkip, _hueSlider->width(), st::colorPickerSize + 2 * st::colorSliderSkip); - _opacitySlider->setGeometryToLeft(_picker->x() - st::colorSliderSkip, _picker->y() + _picker->height() + st::colorEditSkip - st::colorSliderSkip, _picker->width() + 2 * st::colorSliderSkip, _opacitySlider->height()); + _hueSlider->setGeometryToLeft(_picker->x() + _picker->width() + st::colorEditSkip - st::colorSliderSkip, + st::colorEditSkip - st::colorSliderSkip, _hueSlider->width(), + st::colorPickerSize + 2 * st::colorSliderSkip); + _opacitySlider->setGeometryToLeft(_picker->x() - st::colorSliderSkip, + _picker->y() + _picker->height() + st::colorEditSkip - st::colorSliderSkip, + _picker->width() + 2 * st::colorSliderSkip, _opacitySlider->height()); auto fieldLeft = _hueSlider->x() + _hueSlider->width() - st::colorSliderSkip + st::colorEditSkip; auto fieldWidth = st::colorSampleSize.width(); auto fieldHeight = _hueField->height(); _newRect = QRect(fieldLeft, st::colorEditSkip, fieldWidth, st::colorSampleSize.height()); _currentRect = _newRect.translated(0, st::colorSampleSize.height()); - _hueField->setGeometryToLeft(fieldLeft, _currentRect.y() + _currentRect.height() + st::colorFieldSkip, fieldWidth, fieldHeight); + _hueField->setGeometryToLeft(fieldLeft, _currentRect.y() + _currentRect.height() + st::colorFieldSkip, fieldWidth, + fieldHeight); _saturationField->setGeometryToLeft(fieldLeft, _hueField->y() + _hueField->height(), fieldWidth, fieldHeight); - _brightnessField->setGeometryToLeft(fieldLeft, _saturationField->y() + _saturationField->height(), fieldWidth, fieldHeight); - _redField->setGeometryToLeft(fieldLeft, _brightnessField->y() + _brightnessField->height() + st::colorFieldSkip, fieldWidth, fieldHeight); + _brightnessField->setGeometryToLeft(fieldLeft, _saturationField->y() + _saturationField->height(), fieldWidth, + fieldHeight); + _redField->setGeometryToLeft(fieldLeft, _brightnessField->y() + _brightnessField->height() + st::colorFieldSkip, + fieldWidth, fieldHeight); _greenField->setGeometryToLeft(fieldLeft, _redField->y() + _redField->height(), fieldWidth, fieldHeight); _blueField->setGeometryToLeft(fieldLeft, _greenField->y() + _greenField->height(), fieldWidth, fieldHeight); - _result->setGeometryToLeft(fieldLeft - (st::colorEditSkip + st::colorSliderWidth), _opacitySlider->y() + _opacitySlider->height() - st::colorSliderSkip - _result->height(), fieldWidth + (st::colorEditSkip + st::colorSliderWidth), fieldHeight); + _result->setGeometryToLeft(fieldLeft - (st::colorEditSkip + st::colorSliderWidth), + _opacitySlider->y() + _opacitySlider->height() - st::colorSliderSkip - _result->height(), + fieldWidth + (st::colorEditSkip + st::colorSliderWidth), fieldHeight); } void EditColorBox::paintEvent(QPaintEvent *e) { @@ -800,7 +813,8 @@ void EditColorBox::paintEvent(QPaintEvent *e) { Painter p(this); Ui::Shadow::paint(p, _picker->geometry(), width(), st::defaultRoundShadow); - Ui::Shadow::paint(p, QRect(_newRect.x(), _newRect.y(), _newRect.width(), _newRect.height() + _currentRect.height()), width(), st::defaultRoundShadow); + Ui::Shadow::paint(p, QRect(_newRect.x(), _newRect.y(), _newRect.width(), _newRect.height() + _currentRect.height()), + width(), st::defaultRoundShadow); if (_new.alphaF() < 1.) { p.fillRect(myrtlrect(_newRect), _transparent); } @@ -827,10 +841,10 @@ void EditColorBox::updateFromColor(QColor color) { } void EditColorBox::updateFromControls() { - auto hue = qRound((1. - _hueSlider->value()) * 360); - auto saturation = qRound(_picker->valueX() * 255); - auto brightness = qRound((1. - _picker->valueY()) * 255); - auto alpha = qRound(_opacitySlider->value() * 255); + auto hue = std::round((1. - _hueSlider->value()) * 360); + auto saturation = std::round(_picker->valueX() * 255); + auto brightness = std::round((1. - _picker->valueY()) * 255); + auto alpha = std::round(_opacitySlider->value() * 255); setHSV(hue, saturation, brightness, alpha); updateHSVFields(); updateControlsFromHSV(hue, saturation, brightness); @@ -840,7 +854,7 @@ void EditColorBox::updateFromHSVFields() { auto hue = _hueField->value(); auto saturation = percentToByte(_saturationField->value()); auto brightness = percentToByte(_brightnessField->value()); - auto alpha = qRound(_opacitySlider->value() * 255); + auto alpha = std::round(_opacitySlider->value() * 255); setHSV(hue, saturation, brightness, alpha); updateControlsFromHSV(hue, saturation, brightness); } @@ -849,7 +863,7 @@ void EditColorBox::updateFromRGBFields() { auto red = _redField->value(); auto blue = _blueField->value(); auto green = _greenField->value(); - auto alpha = qRound(_opacitySlider->value() * 255); + auto alpha = std::round(_opacitySlider->value() * 255); setRGB(red, green, blue, alpha); updateResultField(); } @@ -869,9 +883,7 @@ void EditColorBox::updateFromResultField() { } return code - '0'; }; - auto fromChars = [fromHex](QChar a, QChar b) { - return fromHex(a) * 0x10 + fromHex(b); - }; + auto fromChars = [fromHex](QChar a, QChar b) { return fromHex(a) * 0x10 + fromHex(b); }; auto red = fromChars(text[0], text[1]); auto green = fromChars(text[2], text[3]); auto blue = fromChars(text[4], text[5]); @@ -909,4 +921,4 @@ void EditColorBox::setRGB(int red, int green, int blue, int alpha) { updateControlsFromColor(); updateHSVFields(); update(); -} \ No newline at end of file +} diff --git a/Telegram/SourceFiles/boxes/edit_color_box.h b/Telegram/SourceFiles/boxes/edit_color_box.h index b4aa2a64d..0dc90c5a9 100644 --- a/Telegram/SourceFiles/boxes/edit_color_box.h +++ b/Telegram/SourceFiles/boxes/edit_color_box.h @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "boxes/abstract_box.h" @@ -26,13 +28,13 @@ class EditColorBox : public BoxContent { Q_OBJECT public: - EditColorBox(QWidget*, const QString &title, QColor current = QColor(255, 255, 255)); + EditColorBox(QWidget *, const QString &title, QColor current = QColor(255, 255, 255)); - void setSaveCallback(base::lambda callback) { + void setSaveCallback(Fn callback) { _saveCallback = std::move(callback); } - void setCancelCallback(base::lambda callback) { + void setCancelCallback(Fn callback) { _cancelCallback = std::move(callback); } @@ -103,7 +105,6 @@ private slots: QRect _currentRect; QRect _newRect; - base::lambda _saveCallback; - base::lambda _cancelCallback; - + Fn _saveCallback; + Fn _cancelCallback; }; diff --git a/Telegram/SourceFiles/boxes/edit_participant_box.cpp b/Telegram/SourceFiles/boxes/edit_participant_box.cpp index b4098ddd0..a617d9a89 100644 --- a/Telegram/SourceFiles/boxes/edit_participant_box.cpp +++ b/Telegram/SourceFiles/boxes/edit_participant_box.cpp @@ -1,32 +1,36 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/edit_participant_box.h" +#include "app.h" // For App::peerName +#include "boxes/calendar_box.h" +#include "facades.h" #include "lang/lang_keys.h" -#include "ui/widgets/checkbox.h" -#include "ui/widgets/labels.h" -#include "ui/widgets/buttons.h" #include "styles/style_boxes.h" #include "ui/special_buttons.h" -#include "boxes/calendar_box.h" +#include "ui/widgets/buttons.h" +#include "ui/widgets/checkbox.h" +#include "ui/widgets/labels.h" namespace { @@ -75,12 +79,11 @@ void ApplyDependencies(CheckboxesMap &checkboxes, DependenciesMap &dependencies, class EditParticipantBox::Inner : public TWidget { public: - Inner(QWidget *parent, not_null channel, not_null user, bool hasAdminRights); + Inner(QWidget *parent, not_null channel, not_null user, bool hasAdminRights); - template - QPointer addControl(object_ptr widget, QMargins margin) { + template QPointer addControl(object_ptr widget, QMargins margin) { doAddControl(std::move(widget), margin); - return static_cast(_rows.back().widget.data()); + return static_cast(_rows.back().widget.data()); } void removeControl(QPointer widget); @@ -92,8 +95,8 @@ class EditParticipantBox::Inner : public TWidget { private: void doAddControl(object_ptr widget, QMargins margin); - not_null _channel; - not_null _user; + not_null _channel; + not_null _user; object_ptr _userPhoto; Text _userName; bool _hasAdminRights = false; @@ -102,22 +105,21 @@ class EditParticipantBox::Inner : public TWidget { QMargins margin; }; std::vector _rows; - }; -EditParticipantBox::Inner::Inner(QWidget *parent, not_null channel, not_null user, bool hasAdminRights) : TWidget(parent) -, _channel(channel) -, _user(user) -, _userPhoto(this, _user, st::rightsPhotoButton) -, _hasAdminRights(hasAdminRights) { +EditParticipantBox::Inner::Inner(QWidget *parent, not_null channel, not_null user, + bool hasAdminRights) + : TWidget(parent) + , _channel(channel) + , _user(user) + , _userPhoto(this, _user, st::rightsPhotoButton) + , _hasAdminRights(hasAdminRights) { _userName.setText(st::rightsNameStyle, App::peerName(_user), _textNameOptions); _userPhoto->setClickedCallback([this] { Ui::showPeerProfile(_user); }); } void EditParticipantBox::Inner::removeControl(QPointer widget) { - auto row = std::find_if(_rows.begin(), _rows.end(), [widget](auto &&row) { - return (row.widget == widget); - }); + auto row = std::find_if(_rows.begin(), _rows.end(), [widget](auto &&row) { return (row.widget == widget); }); Assert(row != _rows.end()); row->widget.destroy(); _rows.erase(row); @@ -125,7 +127,7 @@ void EditParticipantBox::Inner::removeControl(QPointer widget) { void EditParticipantBox::Inner::doAddControl(object_ptr widget, QMargins margin) { widget->setParent(this); - _rows.push_back({ std::move(widget), margin }); + _rows.push_back({std::move(widget), margin}); _rows.back().widget->show(); } @@ -163,18 +165,18 @@ void EditParticipantBox::Inner::paintEvent(QPaintEvent *e) { p.drawTextLeft(namex, st::rightsPhotoMargin.top() + st::rightsStatusTop, width(), statusText()); } -EditParticipantBox::EditParticipantBox(QWidget*, not_null channel, not_null user, bool hasAdminRights) : BoxContent() -, _channel(channel) -, _user(user) -, _hasAdminRights(hasAdminRights) { -} +EditParticipantBox::EditParticipantBox(QWidget *, not_null channel, not_null user, + bool hasAdminRights) + : BoxContent() + , _channel(channel) + , _user(user) + , _hasAdminRights(hasAdminRights) {} void EditParticipantBox::prepare() { _inner = setInnerWidget(object_ptr(this, _channel, _user, hasAdminRights())); } -template -QPointer EditParticipantBox::addControl(object_ptr widget, QMargins margin) { +template QPointer EditParticipantBox::addControl(object_ptr widget, QMargins margin) { Expects(_inner != nullptr); return _inner->addControl(std::move(widget), margin); } @@ -186,11 +188,13 @@ void EditParticipantBox::removeControl(QPointer widget) { void EditParticipantBox::resizeToContent() { _inner->resizeToWidth(st::boxWideWidth); - setDimensions(_inner->width(), qMin(_inner->height(), st::boxMaxListHeight)); + setDimensions(_inner->width(), std::min(_inner->height(), st::boxMaxListHeight)); } -EditAdminBox::EditAdminBox(QWidget*, not_null channel, not_null user, const MTPChannelAdminRights &rights) : EditParticipantBox(nullptr, channel, user, (rights.c_channelAdminRights().vflags.v != 0)) -, _oldRights(rights) { +EditAdminBox::EditAdminBox(QWidget *, not_null channel, not_null user, + const MTPChannelAdminRights &rights) + : EditParticipantBox(nullptr, channel, user, (rights.c_channelAdminRights().vflags.v != 0)) + , _oldRights(rights) { auto dependency = [this](Flag dependent, Flag dependency) { _dependencies.push_back(std::make_pair(dependent, dependency)); }; @@ -198,10 +202,12 @@ EditAdminBox::EditAdminBox(QWidget*, not_null channel, not_null channel) { - auto defaultRights = channel->isMegagroup() - ? (Flag::f_change_info | Flag::f_delete_messages | Flag::f_ban_users | Flag::f_invite_users | Flag::f_invite_link | Flag::f_pin_messages) - : (Flag::f_change_info | Flag::f_post_messages | Flag::f_edit_messages | Flag::f_delete_messages | Flag::f_invite_users | Flag::f_invite_link); +MTPChannelAdminRights EditAdminBox::DefaultRights(not_null channel) { + auto defaultRights = channel->isMegagroup() ? + (Flag::f_change_info | Flag::f_delete_messages | Flag::f_ban_users | Flag::f_invite_users | + Flag::f_invite_link | Flag::f_pin_messages) : + (Flag::f_change_info | Flag::f_post_messages | Flag::f_edit_messages | + Flag::f_delete_messages | Flag::f_invite_users | Flag::f_invite_link); return MTP_channelAdminRights(MTP_flags(defaultRights)); } @@ -212,12 +218,15 @@ void EditAdminBox::prepare() { setTitle(langFactory(hadRights ? lng_rights_edit_admin : lng_channel_add_admin)); addControl(object_ptr(this), QMargins()); - addControl(object_ptr(this, lang(lng_rights_edit_admin_header), Ui::FlatLabel::InitType::Simple, st::rightsHeaderLabel), st::rightsHeaderMargin); + addControl(object_ptr(this, lang(lng_rights_edit_admin_header), Ui::FlatLabel::InitType::Simple, + st::rightsHeaderLabel), + st::rightsHeaderMargin); auto prepareRights = (hadRights ? _oldRights : DefaultRights(channel())); auto addCheckbox = [this, &prepareRights](Flags flags, const QString &text) { auto checked = (prepareRights.c_channelAdminRights().vflags.v & flags) != 0; - auto control = addControl(object_ptr(this, text, checked, st::rightsCheckbox, st::rightsToggle), st::rightsToggleMargin); + auto control = addControl(object_ptr(this, text, checked, st::rightsCheckbox, st::rightsToggle), + st::rightsToggleMargin); subscribe(control->checkedChanged, [this, control](bool checked) { InvokeQueued(this, [this, control] { applyDependencies(control); }); }); @@ -235,7 +244,8 @@ void EditAdminBox::prepare() { addCheckbox(Flag::f_change_info, lang(lng_rights_group_info)); addCheckbox(Flag::f_delete_messages, lang(lng_rights_group_delete)); addCheckbox(Flag::f_ban_users, lang(lng_rights_group_ban)); - addCheckbox(Flag::f_invite_users | Flag::f_invite_link, lang(channel()->anyoneCanAddMembers() ? lng_rights_group_invite_link : lng_rights_group_invite)); + addCheckbox(Flag::f_invite_users | Flag::f_invite_link, + lang(channel()->anyoneCanAddMembers() ? lng_rights_group_invite_link : lng_rights_group_invite)); addCheckbox(Flag::f_pin_messages, lang(lng_rights_group_pin)); addCheckbox(Flag::f_add_admins, lang(lng_rights_add_admins)); } else { @@ -251,9 +261,7 @@ void EditAdminBox::prepare() { if (addAdmins != _checkboxes.end()) { _aboutAddAdmins = addControl(object_ptr(this, st::boxLabel), st::rightsAboutMargin); Assert(addAdmins != _checkboxes.end()); - subscribe(addAdmins->second->checkedChanged, [this](bool checked) { - refreshAboutAddAdminsText(); - }); + subscribe(addAdmins->second->checkedChanged, [this](bool checked) { refreshAboutAddAdminsText(); }); refreshAboutAddAdminsText(); } @@ -308,8 +316,10 @@ void EditAdminBox::refreshAboutAddAdminsText() { resizeToContent(); } -EditRestrictedBox::EditRestrictedBox(QWidget*, not_null channel, not_null user, bool hasAdminRights, const MTPChannelBannedRights &rights) : EditParticipantBox(nullptr, channel, user, hasAdminRights) -, _oldRights(rights) { +EditRestrictedBox::EditRestrictedBox(QWidget *, not_null channel, not_null user, + bool hasAdminRights, const MTPChannelBannedRights &rights) + : EditParticipantBox(nullptr, channel, user, hasAdminRights) + , _oldRights(rights) { auto dependency = [this](Flag dependent, Flag dependency) { _dependencies.push_back(std::make_pair(dependent, dependency)); }; @@ -331,14 +341,17 @@ void EditRestrictedBox::prepare() { setTitle(langFactory(lng_rights_user_restrictions)); addControl(object_ptr(this), QMargins()); - addControl(object_ptr(this, lang(lng_rights_user_restrictions_header), Ui::FlatLabel::InitType::Simple, st::rightsHeaderLabel), st::rightsHeaderMargin); + addControl(object_ptr(this, lang(lng_rights_user_restrictions_header), + Ui::FlatLabel::InitType::Simple, st::rightsHeaderLabel), + st::rightsHeaderMargin); auto prepareRights = (_oldRights.c_channelBannedRights().vflags.v ? _oldRights : DefaultRights(channel())); _until = prepareRights.c_channelBannedRights().vuntil_date.v; auto addCheckbox = [this, &prepareRights](Flags flags, const QString &text) { auto checked = (prepareRights.c_channelBannedRights().vflags.v & flags) == 0; - auto control = addControl(object_ptr(this, text, checked, st::rightsCheckbox, st::rightsToggle), st::rightsToggleMargin); + auto control = addControl(object_ptr(this, text, checked, st::rightsCheckbox, st::rightsToggle), + st::rightsToggleMargin); subscribe(control->checkedChanged, [this, control](bool checked) { InvokeQueued(this, [this, control] { applyDependencies(control); }); }); @@ -350,14 +363,17 @@ void EditRestrictedBox::prepare() { addCheckbox(Flag::f_view_messages, lang(lng_rights_chat_read)); addCheckbox(Flag::f_send_messages, lang(lng_rights_chat_send_text)); addCheckbox(Flag::f_send_media, lang(lng_rights_chat_send_media)); - addCheckbox(Flag::f_send_stickers | Flag::f_send_gifs | Flag::f_send_games | Flag::f_send_inline, lang(lng_rights_chat_send_stickers)); + addCheckbox(Flag::f_send_stickers | Flag::f_send_gifs | Flag::f_send_games | Flag::f_send_inline, + lang(lng_rights_chat_send_stickers)); addCheckbox(Flag::f_embed_links, lang(lng_rights_chat_send_links)); addControl(object_ptr(this), st::rightsUntilMargin); - addControl(object_ptr(this, lang(lng_rights_chat_banned_until_header), Ui::FlatLabel::InitType::Simple, st::rightsHeaderLabel), st::rightsHeaderMargin); + addControl(object_ptr(this, lang(lng_rights_chat_banned_until_header), + Ui::FlatLabel::InitType::Simple, st::rightsHeaderLabel), + st::rightsHeaderMargin); setRestrictUntil(_until); - //addControl(object_ptr(this, lang(lng_rights_chat_banned_block), st::boxLinkButton)); + // addControl(object_ptr(this, lang(lng_rights_chat_banned_block), st::boxLinkButton)); if (canSave()) { addButton(langFactory(lng_settings_save), [this] { @@ -391,8 +407,9 @@ void EditRestrictedBox::applyDependencies(QPointer changed) { ApplyDependencies(_checkboxes, _dependencies, changed); } -MTPChannelBannedRights EditRestrictedBox::DefaultRights(not_null channel) { - auto defaultRights = Flag::f_send_messages | Flag::f_send_media | Flag::f_embed_links | Flag::f_send_stickers | Flag::f_send_gifs | Flag::f_send_games | Flag::f_send_inline; +MTPChannelBannedRights EditRestrictedBox::DefaultRights(not_null channel) { + auto defaultRights = Flag::f_send_messages | Flag::f_send_media | Flag::f_embed_links | Flag::f_send_stickers | + Flag::f_send_gifs | Flag::f_send_games | Flag::f_send_inline; return MTP_channelBannedRights(MTP_flags(defaultRights), MTP_int(0)); } @@ -400,7 +417,10 @@ void EditRestrictedBox::showRestrictUntil() { auto tomorrow = QDate::currentDate().addDays(1); auto highlighted = isUntilForever() ? tomorrow : date(getRealUntilValue()).date(); auto month = highlighted; - _restrictUntilBox = Ui::show(Box(month, highlighted, [this](const QDate &date) { setRestrictUntil(static_cast(QDateTime(date).toTime_t())); }), KeepOtherLayers); + _restrictUntilBox = Ui::show( + Box(month, highlighted, + [this](const QDate &date) { setRestrictUntil(static_cast(QDateTime(date).toTime_t())); }), + KeepOtherLayers); _restrictUntilBox->setMaxDate(QDate::currentDate().addDays(kMaxRestrictDelayDays)); _restrictUntilBox->setMinDate(tomorrow); _restrictUntilBox->addLeftButton(langFactory(lng_rights_chat_banned_forever), [this] { setRestrictUntil(0); }); @@ -440,12 +460,14 @@ void EditRestrictedBox::createUntilVariants() { if (!canSave() && _untilGroup->value() != value) { return; } - _untilVariants.push_back(addControl(object_ptr(this, _untilGroup, value, text, st::defaultBoxCheckbox), st::rightsToggleMargin)); + _untilVariants.push_back( + addControl(object_ptr(this, _untilGroup, value, text, st::defaultBoxCheckbox), + st::rightsToggleMargin)); if (!canSave()) { _untilVariants.back()->setDisabled(true); } }; - auto addCustomVariant = [this, addVariant](TimeId until, TimeId from, TimeId to) { + auto addCustomVariant = [addVariant](TimeId until, TimeId from, TimeId to) { if (!ChannelData::IsRestrictedForever(until) && until > from && until <= to) { addVariant(until, lng_rights_chat_banned_custom_date(lt_date, langDayOfMonthFull(date(until).date()))); } diff --git a/Telegram/SourceFiles/boxes/edit_participant_box.h b/Telegram/SourceFiles/boxes/edit_participant_box.h index d4496b19b..be352861a 100644 --- a/Telegram/SourceFiles/boxes/edit_participant_box.h +++ b/Telegram/SourceFiles/boxes/edit_participant_box.h @@ -1,26 +1,32 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "boxes/abstract_box.h" +#include "core/basic_types.h" +#include "data/data_types.h" +#include "data/data_peer.h" + namespace Ui { class FlatLabel; @@ -34,22 +40,21 @@ class CalendarBox; class EditParticipantBox : public BoxContent { public: - EditParticipantBox(QWidget*, not_null channel, not_null user, bool hasAdminRights); + EditParticipantBox(QWidget *, not_null channel, not_null user, bool hasAdminRights); protected: void prepare() override; void resizeToContent(); - not_null user() const { + not_null user() const { return _user; } - not_null channel() const { + not_null channel() const { return _channel; } - template - QPointer addControl(object_ptr widget, QMargins margin); + template QPointer addControl(object_ptr widget, QMargins margin); void removeControl(QPointer widget); @@ -58,20 +63,20 @@ class EditParticipantBox : public BoxContent { } private: - not_null _channel; - not_null _user; + not_null _channel; + not_null _user; bool _hasAdminRights = false; class Inner; QPointer _inner; - }; class EditAdminBox : public EditParticipantBox { public: - EditAdminBox(QWidget*, not_null channel, not_null user, const MTPChannelAdminRights &rights); + EditAdminBox(QWidget *, not_null channel, not_null user, + const MTPChannelAdminRights &rights); - void setSaveCallback(base::lambda callback) { + void setSaveCallback(Fn callback) { _saveCallback = std::move(callback); } @@ -82,7 +87,7 @@ class EditAdminBox : public EditParticipantBox { using Flag = MTPDchannelAdminRights::Flag; using Flags = MTPDchannelAdminRights::Flags; - static MTPChannelAdminRights DefaultRights(not_null channel); + static MTPChannelAdminRights DefaultRights(not_null channel); bool canSave() const { return !!_saveCallback; @@ -92,11 +97,10 @@ class EditAdminBox : public EditParticipantBox { const MTPChannelAdminRights _oldRights; std::vector> _dependencies; - base::lambda _saveCallback; + Fn _saveCallback; std::map> _checkboxes; QPointer _aboutAddAdmins; - }; // Restricted box works with flags in the opposite way. @@ -104,9 +108,10 @@ class EditAdminBox : public EditParticipantBox { class EditRestrictedBox : public EditParticipantBox { public: - EditRestrictedBox(QWidget*, not_null channel, not_null user, bool hasAdminRights, const MTPChannelBannedRights &rights); + EditRestrictedBox(QWidget *, not_null channel, not_null user, bool hasAdminRights, + const MTPChannelBannedRights &rights); - void setSaveCallback(base::lambda callback) { + void setSaveCallback(Fn callback) { _saveCallback = std::move(callback); } @@ -117,7 +122,7 @@ class EditRestrictedBox : public EditParticipantBox { using Flag = MTPDchannelBannedRights::Flag; using Flags = MTPDchannelBannedRights::Flags; - static MTPChannelBannedRights DefaultRights(not_null channel); + static MTPChannelBannedRights DefaultRights(not_null channel); bool canSave() const { return !!_saveCallback; @@ -136,7 +141,7 @@ class EditRestrictedBox : public EditParticipantBox { const MTPChannelBannedRights _oldRights; TimeId _until = 0; std::vector> _dependencies; - base::lambda _saveCallback; + Fn _saveCallback; std::map> _checkboxes; @@ -147,5 +152,4 @@ class EditRestrictedBox : public EditParticipantBox { static constexpr auto kUntilOneDay = -1; static constexpr auto kUntilOneWeek = -2; static constexpr auto kUntilCustom = -3; - }; diff --git a/Telegram/SourceFiles/boxes/edit_privacy_box.cpp b/Telegram/SourceFiles/boxes/edit_privacy_box.cpp index 16f40322b..d431e0783 100644 --- a/Telegram/SourceFiles/boxes/edit_privacy_box.cpp +++ b/Telegram/SourceFiles/boxes/edit_privacy_box.cpp @@ -1,67 +1,70 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/edit_privacy_box.h" +#include "base/lambda_guard.h" -#include "styles/style_boxes.h" -#include "ui/widgets/checkbox.h" -#include "ui/widgets/labels.h" -#include "ui/widgets/buttons.h" -#include "ui/effects/widget_slide_wrap.h" -#include "boxes/peer_list_controllers.h" #include "apiwrap.h" +#include "app.h" // For App::user, App::feedUsers #include "auth_session.h" +#include "boxes/peer_list_controllers.h" #include "lang/lang_keys.h" +#include "styles/style_boxes.h" +#include "ui/effects/widget_slide_wrap.h" +#include "ui/widgets/buttons.h" +#include "ui/widgets/checkbox.h" +#include "ui/widgets/labels.h" namespace { class PrivacyExceptionsBoxController : public ChatsListBoxController { public: - PrivacyExceptionsBoxController(base::lambda titleFactory, const std::vector> &selected); - void rowClicked(not_null row) override; + PrivacyExceptionsBoxController(Fn titleFactory, const std::vector> &selected); + void rowClicked(not_null row) override; - std::vector> getResult() const; + std::vector> getResult() const; protected: void prepareViewHook() override; - std::unique_ptr createRow(not_null history) override; + std::unique_ptr createRow(not_null history) override; private: - base::lambda _titleFactory; - std::vector> _selected; - + Fn _titleFactory; + std::vector> _selected; }; -PrivacyExceptionsBoxController::PrivacyExceptionsBoxController(base::lambda titleFactory, const std::vector> &selected) -: _titleFactory(std::move(titleFactory)) -, _selected(selected) { -} +PrivacyExceptionsBoxController::PrivacyExceptionsBoxController(Fn titleFactory, + const std::vector> &selected) + : _titleFactory(std::move(titleFactory)) + , _selected(selected) {} void PrivacyExceptionsBoxController::prepareViewHook() { delegate()->peerListSetTitle(_titleFactory); delegate()->peerListAddSelectedRows(_selected); } -std::vector> PrivacyExceptionsBoxController::getResult() const { +std::vector> PrivacyExceptionsBoxController::getResult() const { auto peers = delegate()->peerListCollectSelectedRows(); - auto users = std::vector>(); + auto users = std::vector>(); if (!peers.empty()) { users.reserve(peers.size()); for_const (auto peer, peers) { @@ -73,11 +76,12 @@ std::vector> PrivacyExceptionsBoxController::getResult() con return users; } -void PrivacyExceptionsBoxController::rowClicked(not_null row) { +void PrivacyExceptionsBoxController::rowClicked(not_null row) { delegate()->peerListSetRowChecked(row, !row->checked()); } -std::unique_ptr PrivacyExceptionsBoxController::createRow(not_null history) { +std::unique_ptr +PrivacyExceptionsBoxController::createRow(not_null history) { if (history->peer->isSelf()) { return nullptr; } @@ -89,10 +93,10 @@ std::unique_ptr PrivacyExceptionsBoxControl } // namespace -EditPrivacyBox::EditPrivacyBox(QWidget*, std::unique_ptr controller) : BoxContent() -, _controller(std::move(controller)) -, _loading(this, lang(lng_contacts_loading), Ui::FlatLabel::InitType::Simple, st::membersAbout) { -} +EditPrivacyBox::EditPrivacyBox(QWidget *, std::unique_ptr controller) + : BoxContent() + , _controller(std::move(controller)) + , _loading(this, lang(lng_contacts_loading), Ui::FlatLabel::InitType::Simple, st::membersAbout) {} void EditPrivacyBox::prepare() { _controller->setView(this); @@ -107,7 +111,7 @@ void EditPrivacyBox::prepare() { int EditPrivacyBox::resizeGetHeight(int newWidth) { auto top = 0; - auto layoutRow = [this, newWidth, &top](auto &widget, style::margins padding) { + auto layoutRow = [newWidth, &top](auto &widget, style::margins padding) { if (!widget) return; widget->resizeToNaturalWidth(newWidth - padding.left() - padding.right()); widget->moveToLeft(padding.left(), top + padding.top()); @@ -149,7 +153,7 @@ int EditPrivacyBox::countDefaultHeight(int newWidth) { } return st::editPrivacyOptionMargin.top() + st::defaultCheck.diameter + st::editPrivacyOptionMargin.bottom(); }; - auto labelHeight = [this, newWidth](const QString &text, const style::FlatLabel &st, style::margins padding) { + auto labelHeight = [newWidth](const QString &text, const style::FlatLabel &st, style::margins padding) { if (text.isEmpty()) { return 0; } @@ -175,34 +179,34 @@ int EditPrivacyBox::countDefaultHeight(int newWidth) { } void EditPrivacyBox::editExceptionUsers(Exception exception) { - auto controller = std::make_unique(base::lambda_guarded(this, [this, exception] { - return _controller->exceptionBoxTitle(exception); - }), exceptionUsers(exception)); - auto initBox = [this, exception, controller = controller.get()](not_null box) { + auto controller = std::make_unique( + base::lambda_guarded(this, [this, exception] { return _controller->exceptionBoxTitle(exception); }), + exceptionUsers(exception)); + auto initBox = [this, exception, controller = controller.get()](not_null box) { box->addButton(langFactory(lng_settings_save), base::lambda_guarded(this, [this, box, exception, controller] { - exceptionUsers(exception) = controller->getResult(); - exceptionLink(exception)->entity()->setText(exceptionLinkText(exception)); - auto removeFrom = ([exception] { - switch (exception) { - case Exception::Always: return Exception::Never; - case Exception::Never: return Exception::Always; - } - Unexpected("Invalid exception value."); - })(); - auto &removeFromUsers = exceptionUsers(removeFrom); - auto removedSome = false; - for (auto user : exceptionUsers(exception)) { - auto removedStart = std::remove(removeFromUsers.begin(), removeFromUsers.end(), user); - if (removedStart != removeFromUsers.end()) { - removeFromUsers.erase(removedStart, removeFromUsers.end()); - removedSome = true; - } - } - if (removedSome) { - exceptionLink(removeFrom)->entity()->setText(exceptionLinkText(removeFrom)); - } - box->closeBox(); - })); + exceptionUsers(exception) = controller->getResult(); + exceptionLink(exception)->entity()->setText(exceptionLinkText(exception)); + auto removeFrom = ([exception] { + switch (exception) { + case Exception::Always: return Exception::Never; + case Exception::Never: return Exception::Always; + } + Unexpected("Invalid exception value."); + })(); + auto &removeFromUsers = exceptionUsers(removeFrom); + auto removedSome = false; + for (auto user : exceptionUsers(exception)) { + auto removedStart = std::remove(removeFromUsers.begin(), removeFromUsers.end(), user); + if (removedStart != removeFromUsers.end()) { + removeFromUsers.erase(removedStart, removeFromUsers.end()); + removedSome = true; + } + } + if (removedSome) { + exceptionLink(removeFrom)->entity()->setText(exceptionLinkText(removeFrom)); + } + box->closeBox(); + })); box->addButton(langFactory(lng_cancel), [box] { box->closeBox(); }); }; Ui::show(Box(std::move(controller), std::move(initBox)), KeepOtherLayers); @@ -244,7 +248,7 @@ style::margins EditPrivacyBox::exceptionLinkMargins() const { return st::editPrivacyLinkMargin; } -std::vector> &EditPrivacyBox::exceptionUsers(Exception exception) { +std::vector> &EditPrivacyBox::exceptionUsers(Exception exception) { switch (exception) { case Exception::Always: return _alwaysUsers; case Exception::Never: return _neverUsers; @@ -284,9 +288,8 @@ void EditPrivacyBox::createWidgets() { widget.create(this, text, Ui::FlatLabel::InitType::Simple, st); }; auto createExceptionLink = [this](Exception exception) { - exceptionLink(exception).create(this, object_ptr(this, exceptionLinkText(exception)), exceptionLinkMargins(), [this] { - resizeGetHeight(width()); - }); + exceptionLink(exception).create(this, object_ptr(this, exceptionLinkText(exception)), + exceptionLinkMargins(), [this] { resizeGetHeight(width()); }); exceptionLink(exception)->entity()->setClickedCallback([this, exception] { editExceptionUsers(exception); }); }; @@ -304,9 +307,9 @@ void EditPrivacyBox::createWidgets() { addButton(langFactory(lng_settings_save), [this] { auto someAreDisallowed = (_option != Option::Everyone) || !_neverUsers.empty(); _controller->confirmSave(someAreDisallowed, base::lambda_guarded(this, [this] { - Auth().api().savePrivacy(_controller->key(), collectResult()); - closeBox(); - })); + Auth().api().savePrivacy(_controller->key(), collectResult()); + closeBox(); + })); }); addButton(langFactory(lng_cancel), [this] { closeBox(); }); @@ -324,53 +327,54 @@ void EditPrivacyBox::createWidgets() { } void EditPrivacyBox::loadData() { - request(MTPaccount_GetPrivacy(_controller->key())).done([this](const MTPaccount_PrivacyRules &result) { - Expects(result.type() == mtpc_account_privacyRules); - auto &rules = result.c_account_privacyRules(); - App::feedUsers(rules.vusers); - - // This is simplified version of privacy rules interpretation. - // But it should be fine for all the apps that use the same subset of features. - auto optionSet = false; - auto setOption = [this, &optionSet](Option option) { - if (optionSet) return; - optionSet = true; - _option = option; - }; - auto feedRule = [this, &setOption](const MTPPrivacyRule &rule) { - switch (rule.type()) { - case mtpc_privacyValueAllowAll: setOption(Option::Everyone); break; - case mtpc_privacyValueAllowContacts: setOption(Option::Contacts); break; - case mtpc_privacyValueAllowUsers: { - auto &users = rule.c_privacyValueAllowUsers().vusers.v; - _alwaysUsers.reserve(_alwaysUsers.size() + users.size()); - for (auto &userId : users) { - auto user = App::user(UserId(userId.v)); - if (!base::contains(_neverUsers, user) && !base::contains(_alwaysUsers, user)) { - _alwaysUsers.push_back(user); - } - } - } break; - case mtpc_privacyValueDisallowContacts: // not supported, fall through - case mtpc_privacyValueDisallowAll: setOption(Option::Nobody); break; - case mtpc_privacyValueDisallowUsers: { - auto &users = rule.c_privacyValueDisallowUsers().vusers.v; - _neverUsers.reserve(_neverUsers.size() + users.size()); - for (auto &userId : users) { - auto user = App::user(UserId(userId.v)); - if (!base::contains(_alwaysUsers, user) && !base::contains(_neverUsers, user)) { - _neverUsers.push_back(user); - } - } - } break; - } - }; - for (auto &rule : rules.vrules.v) { - feedRule(rule); - } - feedRule(MTP_privacyValueDisallowAll()); // disallow by default. - - createWidgets(); - }).send(); + request(MTPaccount_GetPrivacy(_controller->key())) + .done([this](const MTPaccount_PrivacyRules &result) { + Expects(result.type() == mtpc_account_privacyRules); + auto &rules = result.c_account_privacyRules(); + App::feedUsers(rules.vusers); + + // This is simplified version of privacy rules interpretation. + // But it should be fine for all the apps that use the same subset of features. + auto optionSet = false; + auto setOption = [this, &optionSet](Option option) { + if (optionSet) return; + optionSet = true; + _option = option; + }; + auto feedRule = [this, &setOption](const MTPPrivacyRule &rule) { + switch (rule.type()) { + case mtpc_privacyValueAllowAll: setOption(Option::Everyone); break; + case mtpc_privacyValueAllowContacts: setOption(Option::Contacts); break; + case mtpc_privacyValueAllowUsers: { + auto &users = rule.c_privacyValueAllowUsers().vusers.v; + _alwaysUsers.reserve(_alwaysUsers.size() + users.size()); + for (auto &userId : users) { + auto user = App::user(UserId(userId.v)); + if (!base::contains(_neverUsers, user) && !base::contains(_alwaysUsers, user)) { + _alwaysUsers.push_back(user); + } + } + } break; + case mtpc_privacyValueDisallowContacts: // not supported, fall through + case mtpc_privacyValueDisallowAll: setOption(Option::Nobody); break; + case mtpc_privacyValueDisallowUsers: { + auto &users = rule.c_privacyValueDisallowUsers().vusers.v; + _neverUsers.reserve(_neverUsers.size() + users.size()); + for (auto &userId : users) { + auto user = App::user(UserId(userId.v)); + if (!base::contains(_alwaysUsers, user) && !base::contains(_neverUsers, user)) { + _neverUsers.push_back(user); + } + } + } break; + } + }; + for (auto &rule : rules.vrules.v) { + feedRule(rule); + } + feedRule(MTP_privacyValueDisallowAll()); // disallow by default. + + createWidgets(); + }) + .send(); } - diff --git a/Telegram/SourceFiles/boxes/edit_privacy_box.h b/Telegram/SourceFiles/boxes/edit_privacy_box.h index 46eaae29f..8a7685f1c 100644 --- a/Telegram/SourceFiles/boxes/edit_privacy_box.h +++ b/Telegram/SourceFiles/boxes/edit_privacy_box.h @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "boxes/abstract_box.h" @@ -26,12 +28,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org namespace Ui { class FlatLabel; class LinkButton; -template -class RadioenumGroup; -template -class Radioenum; -template -class WidgetSlideWrap; +template class RadioenumGroup; +template class Radioenum; +template class WidgetSlideWrap; } // namespace Ui class EditPrivacyBox : public BoxContent, private MTP::Sender { @@ -62,7 +61,7 @@ class EditPrivacyBox : public BoxContent, private MTP::Sender { virtual QString exceptionBoxTitle(Exception exception) = 0; virtual QString exceptionsDescription() = 0; - virtual void confirmSave(bool someAreDisallowed, base::lambda_once saveCallback) { + virtual void confirmSave(bool someAreDisallowed, FnMut saveCallback) { saveCallback(); } @@ -81,10 +80,9 @@ class EditPrivacyBox : public BoxContent, private MTP::Sender { EditPrivacyBox *_view = nullptr; friend class EditPrivacyBox; - }; - EditPrivacyBox(QWidget*, std::unique_ptr controller); + EditPrivacyBox(QWidget *, std::unique_ptr controller); protected: void prepare() override; @@ -102,7 +100,7 @@ class EditPrivacyBox : public BoxContent, private MTP::Sender { void editExceptionUsers(Exception exception); QString exceptionLinkText(Exception exception); - std::vector> &exceptionUsers(Exception exception); + std::vector> &exceptionUsers(Exception exception); object_ptr> &exceptionLink(Exception exception); std::unique_ptr _controller; @@ -110,17 +108,16 @@ class EditPrivacyBox : public BoxContent, private MTP::Sender { std::shared_ptr> _optionGroup; object_ptr _loading; - object_ptr _description = { nullptr }; - object_ptr> _everyone = { nullptr }; - object_ptr> _contacts = { nullptr }; - object_ptr> _nobody = { nullptr }; - object_ptr _warning = { nullptr }; - object_ptr _exceptionsTitle = { nullptr }; - object_ptr> _alwaysLink = { nullptr }; - object_ptr> _neverLink = { nullptr }; - object_ptr _exceptionsDescription = { nullptr }; - - std::vector> _alwaysUsers; - std::vector> _neverUsers; - + object_ptr _description = {nullptr}; + object_ptr> _everyone = {nullptr}; + object_ptr> _contacts = {nullptr}; + object_ptr> _nobody = {nullptr}; + object_ptr _warning = {nullptr}; + object_ptr _exceptionsTitle = {nullptr}; + object_ptr> _alwaysLink = {nullptr}; + object_ptr> _neverLink = {nullptr}; + object_ptr _exceptionsDescription = {nullptr}; + + std::vector> _alwaysUsers; + std::vector> _neverUsers; }; diff --git a/Telegram/SourceFiles/boxes/language_box.cpp b/Telegram/SourceFiles/boxes/language_box.cpp index 42c2f789f..2d940aa77 100644 --- a/Telegram/SourceFiles/boxes/language_box.cpp +++ b/Telegram/SourceFiles/boxes/language_box.cpp @@ -1,39 +1,40 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/language_box.h" - -#include "lang/lang_keys.h" -#include "ui/widgets/checkbox.h" -#include "ui/widgets/buttons.h" -#include "storage/localstorage.h" #include "boxes/confirm_box.h" +#include "lang/lang_cloud_manager.h" +#include "lang/lang_instance.h" +#include "lang/lang_keys.h" #include "mainwidget.h" #include "mainwindow.h" -#include "lang/lang_instance.h" -#include "lang/lang_cloud_manager.h" +#include "storage/localstorage.h" #include "styles/style_boxes.h" +#include "ui/widgets/buttons.h" +#include "ui/widgets/checkbox.h" class LanguageBox::Inner : public TWidget, private base::Subscriber { public: - Inner(QWidget *parent, not_null languages); + Inner(QWidget *parent, not_null languages); void setSelected(int index); void refresh(); @@ -42,14 +43,14 @@ class LanguageBox::Inner : public TWidget, private base::Subscriber { void activateCurrent(); void languageChanged(int languageIndex); - not_null _languages; + not_null _languages; std::shared_ptr _group; std::vector> _buttons; - }; -LanguageBox::Inner::Inner(QWidget *parent, not_null languages) : TWidget(parent) -, _languages(languages) { +LanguageBox::Inner::Inner(QWidget *parent, not_null languages) + : TWidget(parent) + , _languages(languages) { _group = std::make_shared(0); _group->setChangedCallback([this](int value) { languageChanged(value); }); subscribe(Lang::Current().updated(), [this] { @@ -108,16 +109,12 @@ void LanguageBox::Inner::activateCurrent() { void LanguageBox::prepare() { refreshLang(); - subscribe(Lang::Current().updated(), [this] { - refreshLang(); - }); + subscribe(Lang::Current().updated(), [this] { refreshLang(); }); _inner = setInnerWidget(object_ptr(this, &_languages), st::boxLayerScroll); refresh(); - subscribe(Lang::CurrentCloudManager().languageListChanged(), [this] { - refresh(); - }); + subscribe(Lang::CurrentCloudManager().languageListChanged(), [this] { refresh(); }); } void LanguageBox::refreshLang() { @@ -133,7 +130,7 @@ void LanguageBox::refresh() { refreshLanguages(); _inner->refresh(); - setDimensions(st::langsWidth, qMin(_inner->height(), st::boxMaxListHeight)); + setDimensions(st::langsWidth, std::min(_inner->height(), st::boxMaxListHeight)); } void LanguageBox::refreshLanguages() { @@ -142,9 +139,10 @@ void LanguageBox::refreshLanguages() { _languages.reserve(list.size() + 1); auto currentId = Lang::Current().id(); auto currentIndex = -1; - _languages.push_back({ qsl("en"), qsl("English"), qsl("English") }); + _languages.push_back({qsl("en"), qsl("English"), qsl("English")}); for (auto &language : list) { - auto isCurrent = (language.id == currentId) || (language.id == Lang::DefaultLanguageId() && currentId.isEmpty()); + auto isCurrent = + (language.id == currentId) || (language.id == Lang::DefaultLanguageId() && currentId.isEmpty()); if (language.id != qstr("en")) { if (isCurrent) { currentIndex = _languages.size(); @@ -155,11 +153,11 @@ void LanguageBox::refreshLanguages() { } } if (currentId == qstr("custom")) { - _languages.insert(_languages.begin(), { currentId, qsl("Custom LangPack"), qsl("Custom LangPack") }); + _languages.insert(_languages.begin(), {currentId, qsl("Custom LangPack"), qsl("Custom LangPack")}); currentIndex = 0; } else if (currentIndex < 0) { currentIndex = _languages.size(); - _languages.push_back({ currentId, lang(lng_language_name), lang(lng_language_name) }); + _languages.push_back({currentId, lang(lng_language_name), lang(lng_language_name)}); } _inner->setSelected(currentIndex); } diff --git a/Telegram/SourceFiles/boxes/language_box.h b/Telegram/SourceFiles/boxes/language_box.h index a34505ebd..00ce3ceaf 100644 --- a/Telegram/SourceFiles/boxes/language_box.h +++ b/Telegram/SourceFiles/boxes/language_box.h @@ -1,27 +1,29 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once -#include "lang/lang_cloud_manager.h" #include "boxes/abstract_box.h" +#include "lang/lang_cloud_manager.h" #include "mtproto/sender.h" namespace Ui { @@ -29,10 +31,9 @@ class RadiobuttonGroup; class Radiobutton; } // namespace Ui -class LanguageBox : public BoxContent, private MTP::Sender { +class LanguageBox : public BoxContent, private MTP::Sender { public: - LanguageBox(QWidget*) { - } + LanguageBox(QWidget*) {} protected: void prepare() override; @@ -48,5 +49,4 @@ class LanguageBox : public BoxContent, private MTP::Sender { class Inner; QPointer _inner; - }; diff --git a/Telegram/SourceFiles/boxes/local_storage_box.cpp b/Telegram/SourceFiles/boxes/local_storage_box.cpp index c6462715b..2a123668c 100644 --- a/Telegram/SourceFiles/boxes/local_storage_box.cpp +++ b/Telegram/SourceFiles/boxes/local_storage_box.cpp @@ -1,35 +1,39 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/local_storage_box.h" -#include "styles/style_boxes.h" -#include "ui/widgets/buttons.h" -#include "storage/localstorage.h" +#include "app.h" // For App::wnd +#include "auth_session.h" +#include "facades.h" #include "lang/lang_keys.h" +#include "layout.h" // For formatSizeText #include "mainwindow.h" -#include "auth_session.h" +#include "storage/localstorage.h" +#include "styles/style_boxes.h" +#include "ui/widgets/buttons.h" LocalStorageBox::LocalStorageBox(QWidget *parent) -: _clear(this, lang(lng_local_storage_clear), st::boxLinkButton) { -} + : _clear(this, lang(lng_local_storage_clear), st::boxLinkButton) {} void LocalStorageBox::prepare() { setTitle(langFactory(lng_local_storage_title)); @@ -84,12 +88,15 @@ void LocalStorageBox::paintEvent(QPaintEvent *e) { checkLocalStoredCounts(); auto top = st::localStorageBoxSkip; if (_imagesCount > 0) { - auto text = lng_settings_images_cached(lt_count, _imagesCount, lt_size, formatSizeText(Local::storageImagesSize() + Local::storageStickersSize() + Local::storageWebFilesSize())); + auto text = lng_settings_images_cached( + lt_count, _imagesCount, lt_size, + formatSizeText(Local::storageImagesSize() + Local::storageStickersSize() + Local::storageWebFilesSize())); p.drawTextLeft(st::boxPadding.left(), top, width(), text); top += st::boxTextFont->height + st::localStorageBoxSkip; } if (_audiosCount > 0) { - auto text = lng_settings_audios_cached(lt_count, _audiosCount, lt_size, formatSizeText(Local::storageAudiosSize())); + auto text = + lng_settings_audios_cached(lt_count, _audiosCount, lt_size, formatSizeText(Local::storageAudiosSize())); p.drawTextLeft(st::boxPadding.left(), top, width(), text); top += st::boxTextFont->height + st::localStorageBoxSkip; } else if (_imagesCount <= 0) { diff --git a/Telegram/SourceFiles/boxes/local_storage_box.h b/Telegram/SourceFiles/boxes/local_storage_box.h index 0b194d78d..946f08977 100644 --- a/Telegram/SourceFiles/boxes/local_storage_box.h +++ b/Telegram/SourceFiles/boxes/local_storage_box.h @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "boxes/abstract_box.h" @@ -30,7 +32,7 @@ class LocalStorageBox : public BoxContent { Q_OBJECT public: - LocalStorageBox(QWidget*); + LocalStorageBox(QWidget *); private slots: void onTempDirCleared(int task); @@ -58,5 +60,4 @@ private slots: int _imagesCount = -1; int _audiosCount = -1; - }; diff --git a/Telegram/SourceFiles/boxes/mute_settings_box.cpp b/Telegram/SourceFiles/boxes/mute_settings_box.cpp index 0a1827142..8193bcdf4 100644 --- a/Telegram/SourceFiles/boxes/mute_settings_box.cpp +++ b/Telegram/SourceFiles/boxes/mute_settings_box.cpp @@ -1,10 +1,11 @@ -/* This file is part of Telegram Desktop, the official desktop version of - * Telegram messaging app, see https://desktop.telegram.org - * - * This code is in Public Domain, see license terms in .github/CONTRIBUTING.md - * Copyright (C) 2017, Nicholas Guriev - */ - +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// This code is in Public Domain, see license terms in .github/CONTRIBUTING.md +// Copyright (C) 2017, Nicholas Guriev +// #include "boxes/mute_settings_box.h" #include "lang/lang_keys.h" @@ -29,15 +30,14 @@ void MuteSettingsBox::prepare() { object_ptr title(this, st::muteChatTitle); title->setText(App::peerName(_peer, true)); - title->moveToLeft(st::boxPadding.left(), - y + icon->height() / 2 - title->height() / 2); + title->moveToLeft(st::boxPadding.left(), y + icon->height() / 2 - title->height() / 2); // the icon is always higher than this chat title y += icon->height() + st::boxMediumSkip; - const int FOREVER = 8760; // in fact, this is mute only for 1 year + const int FOREVER = 8760; // in fact, this is mute only for 1 year auto group = std::make_shared(FOREVER); y += st::boxOptionListPadding.top(); - for (int value : { 1, 4, 18, 72, FOREVER }) { // periods in hours + for (int value : {1, 4, 18, 72, FOREVER}) { // periods in hours QString text; if (value < 24) { text = lng_mute_duration_hours(lt_count, value); @@ -53,8 +53,7 @@ void MuteSettingsBox::prepare() { y += st::boxOptionListPadding.bottom() - st::boxOptionListSkip + st::defaultCheckbox.margin.bottom(); addButton(langFactory(lng_box_ok), [this, group] { - App::main()->updateNotifySetting(_peer, NotifySettingSetMuted, - SilentNotifiesDontChange, group->value() * 3600); + App::main()->updateNotifySetting(_peer, NotifySettingSetMuted, SilentNotifiesDontChange, group->value() * 3600); closeBox(); }); addButton(langFactory(lng_cancel), [this] { closeBox(); }); diff --git a/Telegram/SourceFiles/boxes/mute_settings_box.h b/Telegram/SourceFiles/boxes/mute_settings_box.h index dc689b1fb..6cf2ed76f 100644 --- a/Telegram/SourceFiles/boxes/mute_settings_box.h +++ b/Telegram/SourceFiles/boxes/mute_settings_box.h @@ -1,9 +1,11 @@ -/* This file is part of Telegram Desktop, the official desktop version of - * Telegram messaging app, see https://desktop.telegram.org - * - * This code is in Public Domain, see license terms in .github/CONTRIBUTING.md - * Copyright (C) 2017, Nicholas Guriev - */ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// This code is in Public Domain, see license terms in .github/CONTRIBUTING.md +// Copyright (C) 2017, Nicholas Guriev +// #pragma once #include "boxes/abstract_box.h" @@ -14,15 +16,14 @@ class MuteSettingsBox : public BoxContent { Q_OBJECT - public: - MuteSettingsBox(QWidget *parent, not_null peer) - : _peer(peer) { - } +public: + MuteSettingsBox(QWidget *parent, not_null peer) + : _peer(peer) {} - protected: +protected: void prepare() override; - private: - not_null _peer; +private: + not_null _peer; }; // vi: ts=4 tw=80 diff --git a/Telegram/SourceFiles/boxes/notifications_box.cpp b/Telegram/SourceFiles/boxes/notifications_box.cpp index ed83a00bf..c68001ae6 100644 --- a/Telegram/SourceFiles/boxes/notifications_box.cpp +++ b/Telegram/SourceFiles/boxes/notifications_box.cpp @@ -1,36 +1,40 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/notifications_box.h" +#include "app.h" // For App::pixmapFromImageInPlace +#include "auth_session.h" +#include "config.h" #include "lang/lang_keys.h" -#include "ui/widgets/buttons.h" -#include "ui/widgets/discrete_sliders.h" +#include "messenger.h" +#include "platform/platform_specific.h" +#include "storage/localstorage.h" #include "styles/style_boxes.h" #include "styles/style_dialogs.h" #include "styles/style_window.h" -#include "messenger.h" -#include "storage/localstorage.h" -#include "auth_session.h" +#include "ui/widgets/buttons.h" +#include "ui/widgets/discrete_sliders.h" #include "window/notifications_manager.h" -#include "platform/platform_specific.h" namespace { @@ -42,12 +46,14 @@ using ChangeType = Window::Notifications::ChangeType; class NotificationsBox::SampleWidget : public QWidget { public: - SampleWidget(NotificationsBox *owner, const QPixmap &cache) : QWidget(nullptr) - , _owner(owner) - , _cache(cache) { + SampleWidget(NotificationsBox *owner, const QPixmap &cache) + : QWidget(nullptr) + , _owner(owner) + , _cache(cache) { resize(cache.width() / cache.devicePixelRatio(), cache.height() / cache.devicePixelRatio()); - setWindowFlags(Qt::WindowFlags(Qt::FramelessWindowHint) | Qt::WindowStaysOnTopHint | Qt::BypassWindowManagerHint | Qt::NoDropShadowWindowHint | Qt::Tool); + setWindowFlags(Qt::WindowFlags(Qt::FramelessWindowHint) | Qt::WindowStaysOnTopHint | + Qt::BypassWindowManagerHint | Qt::NoDropShadowWindowHint | Qt::Tool); setAttribute(Qt::WA_MacAlwaysShowToolWindow); setAttribute(Qt::WA_TransparentForMouseEvents); setAttribute(Qt::WA_OpaquePaintEvent); @@ -109,14 +115,12 @@ class NotificationsBox::SampleWidget : public QWidget { Animation _opacity; bool _hiding = false; bool _deleted = false; - }; NotificationsBox::NotificationsBox(QWidget *parent) -: _chosenCorner(Global::NotificationsCorner()) -, _oldCount(snap(Global::NotificationsCount(), 1, kMaxNotificationsCount)) -, _countSlider(this) { -} + : _chosenCorner(Global::NotificationsCorner()) + , _oldCount(snap(Global::NotificationsCount(), 1, kMaxNotificationsCount)) + , _countSlider(this) {} void NotificationsBox::prepare() { addButton(langFactory(lng_close), [this] { closeBox(); }); @@ -149,7 +153,8 @@ void NotificationsBox::paintEvent(QPaintEvent *e) { p.drawTextLeft(contentLeft, st::boxTitlePosition.y(), width(), lang(lng_settings_notifications_position)); auto screenRect = getScreenRect(); - p.fillRect(screenRect.x(), screenRect.y(), st::notificationsBoxScreenSize.width(), st::notificationsBoxScreenSize.height(), st::notificationsBoxScreenBg); + p.fillRect(screenRect.x(), screenRect.y(), st::notificationsBoxScreenSize.width(), + st::notificationsBoxScreenSize.height(), st::notificationsBoxScreenBg); auto monitorTop = st::notificationsBoxMonitorTop; st::notificationsBoxMonitor.paint(p, contentLeft, monitorTop, width()); @@ -158,8 +163,12 @@ void NotificationsBox::paintEvent(QPaintEvent *e) { auto screenCorner = static_cast(corner); auto isLeft = Notify::IsLeftCorner(screenCorner); auto isTop = Notify::IsTopCorner(screenCorner); - auto sampleLeft = isLeft ? (screenRect.x() + st::notificationsSampleSkip) : (screenRect.x() + screenRect.width() - st::notificationsSampleSkip - st::notificationSampleSize.width()); - auto sampleTop = isTop ? (screenRect.y() + st::notificationsSampleTopSkip) : (screenRect.y() + screenRect.height() - st::notificationsSampleBottomSkip - st::notificationSampleSize.height()); + auto sampleLeft = isLeft ? (screenRect.x() + st::notificationsSampleSkip) : + (screenRect.x() + screenRect.width() - st::notificationsSampleSkip - + st::notificationSampleSize.width()); + auto sampleTop = isTop ? (screenRect.y() + st::notificationsSampleTopSkip) : + (screenRect.y() + screenRect.height() - st::notificationsSampleBottomSkip - + st::notificationSampleSize.height()); if (corner == static_cast(_chosenCorner)) { auto count = currentCount(); for (int i = 0; i != kMaxNotificationsCount; ++i) { @@ -207,14 +216,16 @@ int NotificationsBox::getContentLeft() const { QRect NotificationsBox::getScreenRect() const { auto screenLeft = (width() - st::notificationsBoxScreenSize.width()) / 2; auto screenTop = st::notificationsBoxMonitorTop + st::notificationsBoxScreenTop; - return QRect(screenLeft, screenTop, st::notificationsBoxScreenSize.width(), st::notificationsBoxScreenSize.height()); + return QRect(screenLeft, screenTop, st::notificationsBoxScreenSize.width(), + st::notificationsBoxScreenSize.height()); } void NotificationsBox::resizeEvent(QResizeEvent *e) { BoxContent::resizeEvent(e); auto screenRect = getScreenRect(); - auto sliderTop = screenRect.y() + screenRect.height() + st::notificationsBoxCountLabelTop + st::notificationsBoxCountTop; + auto sliderTop = + screenRect.y() + screenRect.height() + st::notificationsBoxCountLabelTop + st::notificationsBoxCountTop; auto contentLeft = getContentLeft(); _countSlider->resizeToWidth(width() - 2 * contentLeft); _countSlider->move(contentLeft, sliderTop); @@ -223,7 +234,8 @@ void NotificationsBox::resizeEvent(QResizeEvent *e) { void NotificationsBox::prepareNotificationSampleSmall() { auto width = st::notificationSampleSize.width(); auto height = st::notificationSampleSize.height(); - auto sampleImage = QImage(width * cIntRetinaFactor(), height * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied); + auto sampleImage = + QImage(width * cIntRetinaFactor(), height * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied); sampleImage.setDevicePixelRatio(cRetinaFactor()); sampleImage.fill(st::notificationBg->c); { @@ -260,7 +272,9 @@ void NotificationsBox::prepareNotificationSampleSmall() { void NotificationsBox::prepareNotificationSampleUserpic() { if (_notificationSampleUserpic.isNull()) { - _notificationSampleUserpic = App::pixmapFromImageInPlace(Messenger::Instance().logoNoMargin().scaled(st::notifyPhotoSize * cIntRetinaFactor(), st::notifyPhotoSize * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + _notificationSampleUserpic = App::pixmapFromImageInPlace(Messenger::Instance().logoNoMargin().scaled( + st::notifyPhotoSize * cIntRetinaFactor(), st::notifyPhotoSize * cIntRetinaFactor(), Qt::IgnoreAspectRatio, + Qt::SmoothTransformation)); _notificationSampleUserpic.setDevicePixelRatio(cRetinaFactor()); } } @@ -274,28 +288,34 @@ void NotificationsBox::prepareNotificationSampleLarge() { Painter p(&sampleImage); p.fillRect(0, 0, w - st::notifyBorderWidth, st::notifyBorderWidth, st::notifyBorder->b); p.fillRect(w - st::notifyBorderWidth, 0, st::notifyBorderWidth, h - st::notifyBorderWidth, st::notifyBorder->b); - p.fillRect(st::notifyBorderWidth, h - st::notifyBorderWidth, w - st::notifyBorderWidth, st::notifyBorderWidth, st::notifyBorder->b); + p.fillRect(st::notifyBorderWidth, h - st::notifyBorderWidth, w - st::notifyBorderWidth, st::notifyBorderWidth, + st::notifyBorder->b); p.fillRect(0, st::notifyBorderWidth, st::notifyBorderWidth, h - st::notifyBorderWidth, st::notifyBorder->b); prepareNotificationSampleUserpic(); p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), _notificationSampleUserpic); - int itemWidth = w - st::notifyPhotoPos.x() - st::notifyPhotoSize - st::notifyTextLeft - st::notifyClosePos.x() - st::notifyClose.width; + int itemWidth = w - st::notifyPhotoPos.x() - st::notifyPhotoSize - st::notifyTextLeft - st::notifyClosePos.x() - + st::notifyClose.width; - auto rectForName = rtlrect(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyTextTop, itemWidth, st::msgNameFont->height, w); + auto rectForName = rtlrect(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyTextTop, + itemWidth, st::msgNameFont->height, w); auto notifyText = st::dialogsTextFont->elided(lang(lng_notification_sample), itemWidth); p.setFont(st::dialogsTextFont); p.setPen(st::dialogsTextFgService); - p.drawText(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyItemTop + st::msgNameFont->height + st::dialogsTextFont->ascent, notifyText); + p.drawText(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, + st::notifyItemTop + st::msgNameFont->height + st::dialogsTextFont->ascent, notifyText); p.setPen(st::dialogsNameFg); p.setFont(st::msgNameFont); - auto notifyTitle = st::msgNameFont->elided(qsl("Telegram Desktop"), rectForName.width()); + auto notifyTitle = st::msgNameFont->elided(str_const_toString(AppName), rectForName.width()); p.drawText(rectForName.left(), rectForName.top() + st::msgNameFont->ascent, notifyTitle); - st::notifyClose.icon.paint(p, w - st::notifyClosePos.x() - st::notifyClose.width + st::notifyClose.iconPosition.x(), st::notifyClosePos.y() + st::notifyClose.iconPosition.y(), w); + st::notifyClose.icon.paint( + p, w - st::notifyClosePos.x() - st::notifyClose.width + st::notifyClose.iconPosition.x(), + st::notifyClosePos.y() + st::notifyClose.iconPosition.y(), w); } _notificationSampleLarge = App::pixmapFromImageInPlace(std::move(sampleImage)); @@ -320,9 +340,12 @@ void NotificationsBox::mouseMoveEvent(QMouseEvent *e) { auto cornerWidth = screenRect.width() / 3; auto cornerHeight = screenRect.height() / 3; auto topLeft = rtlrect(screenRect.x(), screenRect.y(), cornerWidth, cornerHeight, width()); - auto topRight = rtlrect(screenRect.x() + screenRect.width() - cornerWidth, screenRect.y(), cornerWidth, cornerHeight, width()); - auto bottomRight = rtlrect(screenRect.x() + screenRect.width() - cornerWidth, screenRect.y() + screenRect.height() - cornerHeight, cornerWidth, cornerHeight, width()); - auto bottomLeft = rtlrect(screenRect.x(), screenRect.y() + screenRect.height() - cornerHeight, cornerWidth, cornerHeight, width()); + auto topRight = + rtlrect(screenRect.x() + screenRect.width() - cornerWidth, screenRect.y(), cornerWidth, cornerHeight, width()); + auto bottomRight = rtlrect(screenRect.x() + screenRect.width() - cornerWidth, + screenRect.y() + screenRect.height() - cornerHeight, cornerWidth, cornerHeight, width()); + auto bottomLeft = rtlrect(screenRect.x(), screenRect.y() + screenRect.height() - cornerHeight, cornerWidth, + cornerHeight, width()); if (topLeft.contains(e->pos())) { setOverCorner(Notify::ScreenCorner::TopLeft); } else if (topRight.contains(e->pos())) { @@ -345,9 +368,7 @@ void NotificationsBox::setOverCorner(Notify::ScreenCorner corner) { if (corner == _overCorner) { return; } - for_const (auto widget, _cornerSamples[static_cast(_overCorner)]) { - widget->hideFast(); - } + for_const (auto widget, _cornerSamples[static_cast(_overCorner)]) { widget->hideFast(); } } else { _isOverCorner = true; setCursor(style::cur_pointer); @@ -359,7 +380,7 @@ void NotificationsBox::setOverCorner(Notify::ScreenCorner corner) { auto &samples = _cornerSamples[static_cast(_overCorner)]; auto samplesAlready = samples.size(); auto samplesNeeded = currentCount(); - auto samplesLeave = qMin(samplesAlready, samplesNeeded); + auto samplesLeave = std::min(samplesAlready, samplesNeeded); for (int i = 0; i != samplesLeave; ++i) { samples[i]->showFast(); } @@ -367,8 +388,10 @@ void NotificationsBox::setOverCorner(Notify::ScreenCorner corner) { auto r = psDesktopRect(); auto isLeft = Notify::IsLeftCorner(_overCorner); auto isTop = Notify::IsTopCorner(_overCorner); - auto sampleLeft = (isLeft == rtl()) ? (r.x() + r.width() - st::notifyWidth - st::notifyDeltaX) : (r.x() + st::notifyDeltaX); - auto sampleTop = isTop ? (r.y() + st::notifyDeltaY) : (r.y() + r.height() - st::notifyDeltaY - st::notifyMinHeight); + auto sampleLeft = + (isLeft == rtl()) ? (r.x() + r.width() - st::notifyWidth - st::notifyDeltaX) : (r.x() + st::notifyDeltaX); + auto sampleTop = + isTop ? (r.y() + st::notifyDeltaY) : (r.y() + r.height() - st::notifyDeltaY - st::notifyMinHeight); for (int i = samplesLeave; i != samplesNeeded; ++i) { auto widget = std::make_unique(this, _notificationSampleLarge); widget->move(sampleLeft, sampleTop + (isTop ? 1 : -1) * i * (st::notifyMinHeight + st::notifyDeltaY)); @@ -390,9 +413,7 @@ void NotificationsBox::clearOverCorner() { Auth().notifications().settingsChanged().notify(ChangeType::DemoIsShown); for_const (auto &samples, _cornerSamples) { - for_const (auto widget, samples) { - widget->hideFast(); - } + for_const (auto widget, samples) { widget->hideFast(); } } } } @@ -422,9 +443,7 @@ void NotificationsBox::mouseReleaseEvent(QMouseEvent *e) { NotificationsBox::~NotificationsBox() { for_const (auto &samples, _cornerSamples) { - for_const (auto widget, samples) { - widget->detach(); - } + for_const (auto widget, samples) { widget->detach(); } } clearOverCorner(); } diff --git a/Telegram/SourceFiles/boxes/notifications_box.h b/Telegram/SourceFiles/boxes/notifications_box.h index faadc2eca..5be62c61e 100644 --- a/Telegram/SourceFiles/boxes/notifications_box.h +++ b/Telegram/SourceFiles/boxes/notifications_box.h @@ -1,26 +1,29 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "boxes/abstract_box.h" +#include "facades.h" namespace Ui { class LinkButton; @@ -29,7 +32,7 @@ class SettingsSlider; class NotificationsBox : public BoxContent { public: - NotificationsBox(QWidget*); + NotificationsBox(QWidget *); ~NotificationsBox(); protected: @@ -73,6 +76,5 @@ class NotificationsBox : public BoxContent { int _oldCount; object_ptr _countSlider; - QVector _cornerSamples[4]; - + QVector _cornerSamples[4]; }; diff --git a/Telegram/SourceFiles/boxes/passcode_box.cpp b/Telegram/SourceFiles/boxes/passcode_box.cpp index 6df3d36e8..cad995238 100644 --- a/Telegram/SourceFiles/boxes/passcode_box.cpp +++ b/Telegram/SourceFiles/boxes/passcode_box.cpp @@ -1,57 +1,63 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/passcode_box.h" -#include "lang/lang_keys.h" #include "boxes/confirm_box.h" +#include "facades.h" +#include "lang/lang_keys.h" #include "mainwindow.h" #include "storage/localstorage.h" #include "styles/style_boxes.h" #include "ui/widgets/buttons.h" #include "ui/widgets/input_fields.h" -PasscodeBox::PasscodeBox(QWidget*, bool turningOff) -: _turningOff(turningOff) -, _about(st::boxWidth - st::boxPadding.left() * 1.5) -, _oldPasscode(this, st::defaultInputField, langFactory(lng_passcode_enter_old)) -, _newPasscode(this, st::defaultInputField, langFactory(Global::LocalPasscode() ? lng_passcode_enter_new : lng_passcode_enter_first)) -, _reenterPasscode(this, st::defaultInputField, langFactory(lng_passcode_confirm_new)) -, _passwordHint(this, st::defaultInputField, langFactory(lng_cloud_password_hint)) -, _recoverEmail(this, st::defaultInputField, langFactory(lng_cloud_password_email)) -, _recover(this, lang(lng_signin_recover)) { -} - -PasscodeBox::PasscodeBox(QWidget*, const QByteArray &newSalt, const QByteArray &curSalt, bool hasRecovery, const QString &hint, bool turningOff) -: _turningOff(turningOff) -, _cloudPwd(true) -, _newSalt(newSalt) -, _curSalt(curSalt) -, _hasRecovery(hasRecovery) -, _about(st::boxWidth - st::boxPadding.left() * 1.5) -, _oldPasscode(this, st::defaultInputField, langFactory(lng_cloud_password_enter_old)) -, _newPasscode(this, st::defaultInputField, langFactory(curSalt.isEmpty() ? lng_cloud_password_enter_first : lng_cloud_password_enter_new)) -, _reenterPasscode(this, st::defaultInputField, langFactory(lng_cloud_password_confirm_new)) -, _passwordHint(this, st::defaultInputField, langFactory(curSalt.isEmpty() ? lng_cloud_password_hint : lng_cloud_password_change_hint)) -, _recoverEmail(this, st::defaultInputField, langFactory(lng_cloud_password_email)) -, _recover(this, lang(lng_signin_recover)) { +PasscodeBox::PasscodeBox(QWidget *, bool turningOff) + : _turningOff(turningOff) + , _about(st::boxWidth - st::boxPadding.left() * 1.5) + , _oldPasscode(this, st::defaultInputField, langFactory(lng_passcode_enter_old)) + , _newPasscode(this, st::defaultInputField, + langFactory(Global::LocalPasscode() ? lng_passcode_enter_new : lng_passcode_enter_first)) + , _reenterPasscode(this, st::defaultInputField, langFactory(lng_passcode_confirm_new)) + , _passwordHint(this, st::defaultInputField, langFactory(lng_cloud_password_hint)) + , _recoverEmail(this, st::defaultInputField, langFactory(lng_cloud_password_email)) + , _recover(this, lang(lng_signin_recover)) {} + +PasscodeBox::PasscodeBox(QWidget *, const QByteArray &newSalt, const QByteArray &curSalt, bool hasRecovery, + const QString &hint, bool turningOff) + : _turningOff(turningOff) + , _cloudPwd(true) + , _newSalt(newSalt) + , _curSalt(curSalt) + , _hasRecovery(hasRecovery) + , _about(st::boxWidth - st::boxPadding.left() * 1.5) + , _oldPasscode(this, st::defaultInputField, langFactory(lng_cloud_password_enter_old)) + , _newPasscode(this, st::defaultInputField, + langFactory(curSalt.isEmpty() ? lng_cloud_password_enter_first : lng_cloud_password_enter_new)) + , _reenterPasscode(this, st::defaultInputField, langFactory(lng_cloud_password_confirm_new)) + , _passwordHint(this, st::defaultInputField, + langFactory(curSalt.isEmpty() ? lng_cloud_password_hint : lng_cloud_password_change_hint)) + , _recoverEmail(this, st::defaultInputField, langFactory(lng_cloud_password_email)) + , _recover(this, lang(lng_signin_recover)) { if (!hint.isEmpty()) _hintText.setText(st::passcodeTextStyle, lng_signin_hint(lt_password_hint, hint)); } @@ -64,17 +70,30 @@ void PasscodeBox::prepare() { if (_turningOff) { _oldPasscode->show(); setTitle(langFactory(_cloudPwd ? lng_cloud_password_remove : lng_passcode_remove)); - setDimensions(st::boxWidth, st::passcodePadding.top() + _oldPasscode->height() + st::passcodeTextLine + ((_hasRecovery && !_hintText.isEmpty()) ? st::passcodeTextLine : 0) + st::passcodeAboutSkip + _aboutHeight + st::passcodePadding.bottom()); + setDimensions(st::boxWidth, st::passcodePadding.top() + _oldPasscode->height() + st::passcodeTextLine + + ((_hasRecovery && !_hintText.isEmpty()) ? st::passcodeTextLine : 0) + + st::passcodeAboutSkip + _aboutHeight + st::passcodePadding.bottom()); } else { auto has = _cloudPwd ? (!_curSalt.isEmpty()) : Global::LocalPasscode(); if (has) { _oldPasscode->show(); setTitle(langFactory(_cloudPwd ? lng_cloud_password_change : lng_passcode_change)); - setDimensions(st::boxWidth, st::passcodePadding.top() + _oldPasscode->height() + st::passcodeTextLine + ((_hasRecovery && !_hintText.isEmpty()) ? st::passcodeTextLine : 0) + _newPasscode->height() + st::passcodeLittleSkip + _reenterPasscode->height() + st::passcodeSkip + (_cloudPwd ? _passwordHint->height() + st::passcodeLittleSkip : 0) + st::passcodeAboutSkip + _aboutHeight + st::passcodePadding.bottom()); + setDimensions(st::boxWidth, st::passcodePadding.top() + _oldPasscode->height() + st::passcodeTextLine + + ((_hasRecovery && !_hintText.isEmpty()) ? st::passcodeTextLine : 0) + + _newPasscode->height() + st::passcodeLittleSkip + + _reenterPasscode->height() + st::passcodeSkip + + (_cloudPwd ? _passwordHint->height() + st::passcodeLittleSkip : 0) + + st::passcodeAboutSkip + _aboutHeight + st::passcodePadding.bottom()); } else { _oldPasscode->hide(); setTitle(langFactory(_cloudPwd ? lng_cloud_password_create : lng_passcode_create)); - setDimensions(st::boxWidth, st::passcodePadding.top() + _newPasscode->height() + st::passcodeLittleSkip + _reenterPasscode->height() + st::passcodeSkip + (_cloudPwd ? _passwordHint->height() + st::passcodeLittleSkip : 0) + st::passcodeAboutSkip + _aboutHeight + (_cloudPwd ? (st::passcodeLittleSkip + _recoverEmail->height() + st::passcodeSkip) : st::passcodePadding.bottom())); + setDimensions(st::boxWidth, + st::passcodePadding.top() + _newPasscode->height() + st::passcodeLittleSkip + + _reenterPasscode->height() + st::passcodeSkip + + (_cloudPwd ? _passwordHint->height() + st::passcodeLittleSkip : 0) + + st::passcodeAboutSkip + _aboutHeight + + (_cloudPwd ? (st::passcodeLittleSkip + _recoverEmail->height() + st::passcodeSkip) : + st::passcodePadding.bottom())); } } @@ -141,28 +160,41 @@ void PasscodeBox::paintEvent(QPaintEvent *e) { Painter p(this); - int32 w = st::boxWidth - st::boxPadding.left() * 1.5; - int32 abouty = (_passwordHint->isHidden() ? ((_reenterPasscode->isHidden() ? (_oldPasscode->y() + (_hasRecovery && !_hintText.isEmpty() ? st::passcodeTextLine : 0)) : _reenterPasscode->y()) + st::passcodeSkip) : _passwordHint->y()) + _oldPasscode->height() + st::passcodeLittleSkip + st::passcodeAboutSkip; + qint32 w = st::boxWidth - st::boxPadding.left() * 1.5; + qint32 abouty = (_passwordHint->isHidden() ? + ((_reenterPasscode->isHidden() ? + (_oldPasscode->y() + (_hasRecovery && !_hintText.isEmpty() ? st::passcodeTextLine : 0)) : + _reenterPasscode->y()) + + st::passcodeSkip) : + _passwordHint->y()) + + _oldPasscode->height() + st::passcodeLittleSkip + st::passcodeAboutSkip; p.setPen(st::boxTextFg); _about.drawLeft(p, st::boxPadding.left(), abouty, w, width()); if (!_hintText.isEmpty() && _oldError.isEmpty()) { - _hintText.drawLeftElided(p, st::boxPadding.left(), _oldPasscode->y() + _oldPasscode->height() + ((st::passcodeTextLine - st::normalFont->height) / 2), w, width(), 1, style::al_topleft); + _hintText.drawLeftElided(p, st::boxPadding.left(), + _oldPasscode->y() + _oldPasscode->height() + + ((st::passcodeTextLine - st::normalFont->height) / 2), + w, width(), 1, style::al_topleft); } if (!_oldError.isEmpty()) { p.setPen(st::boxTextFgError); - p.drawText(QRect(st::boxPadding.left(), _oldPasscode->y() + _oldPasscode->height(), w, st::passcodeTextLine), _oldError, style::al_left); + p.drawText(QRect(st::boxPadding.left(), _oldPasscode->y() + _oldPasscode->height(), w, st::passcodeTextLine), + _oldError, style::al_left); } if (!_newError.isEmpty()) { p.setPen(st::boxTextFgError); - p.drawText(QRect(st::boxPadding.left(), _reenterPasscode->y() + _reenterPasscode->height(), w, st::passcodeTextLine), _newError, style::al_left); + p.drawText( + QRect(st::boxPadding.left(), _reenterPasscode->y() + _reenterPasscode->height(), w, st::passcodeTextLine), + _newError, style::al_left); } if (!_emailError.isEmpty()) { p.setPen(st::boxTextFgError); - p.drawText(QRect(st::boxPadding.left(), _recoverEmail->y() + _recoverEmail->height(), w, st::passcodeTextLine), _emailError, style::al_left); + p.drawText(QRect(st::boxPadding.left(), _recoverEmail->y() + _recoverEmail->height(), w, st::passcodeTextLine), + _emailError, style::al_left); } } @@ -170,20 +202,32 @@ void PasscodeBox::resizeEvent(QResizeEvent *e) { BoxContent::resizeEvent(e); bool has = _cloudPwd ? (!_curSalt.isEmpty()) : Global::LocalPasscode(); - int32 w = st::boxWidth - st::boxPadding.left() - st::boxPadding.right(); + qint32 w = st::boxWidth - st::boxPadding.left() - st::boxPadding.right(); _oldPasscode->resize(w, _oldPasscode->height()); _oldPasscode->moveToLeft(st::boxPadding.left(), st::passcodePadding.top()); _newPasscode->resize(w, _newPasscode->height()); - _newPasscode->moveToLeft(st::boxPadding.left(), _oldPasscode->y() + ((_turningOff || has) ? (_oldPasscode->height() + st::passcodeTextLine + ((_hasRecovery && !_hintText.isEmpty()) ? st::passcodeTextLine : 0)) : 0)); + _newPasscode->moveToLeft(st::boxPadding.left(), + _oldPasscode->y() + + ((_turningOff || has) ? + (_oldPasscode->height() + st::passcodeTextLine + + ((_hasRecovery && !_hintText.isEmpty()) ? st::passcodeTextLine : 0)) : + 0)); _reenterPasscode->resize(w, _reenterPasscode->height()); - _reenterPasscode->moveToLeft(st::boxPadding.left(), _newPasscode->y() + _newPasscode->height() + st::passcodeLittleSkip); + _reenterPasscode->moveToLeft(st::boxPadding.left(), + _newPasscode->y() + _newPasscode->height() + st::passcodeLittleSkip); _passwordHint->resize(w, _passwordHint->height()); - _passwordHint->moveToLeft(st::boxPadding.left(), _reenterPasscode->y() + _reenterPasscode->height() + st::passcodeSkip); + _passwordHint->moveToLeft(st::boxPadding.left(), + _reenterPasscode->y() + _reenterPasscode->height() + st::passcodeSkip); _recoverEmail->resize(w, _passwordHint->height()); - _recoverEmail->moveToLeft(st::boxPadding.left(), _passwordHint->y() + _passwordHint->height() + st::passcodeLittleSkip + _aboutHeight + st::passcodeLittleSkip); + _recoverEmail->moveToLeft(st::boxPadding.left(), _passwordHint->y() + _passwordHint->height() + + st::passcodeLittleSkip + _aboutHeight + + st::passcodeLittleSkip); if (!_recover->isHidden()) { - _recover->moveToLeft(st::boxPadding.left(), _oldPasscode->y() + _oldPasscode->height() + (_hintText.isEmpty() ? ((st::passcodeTextLine - _recover->height()) / 2) : st::passcodeTextLine)); + _recover->moveToLeft( + st::boxPadding.left(), + _oldPasscode->y() + _oldPasscode->height() + + (_hintText.isEmpty() ? ((st::passcodeTextLine - _recover->height()) / 2) : st::passcodeTextLine)); } } @@ -200,7 +244,9 @@ void PasscodeBox::setInnerFocus() { void PasscodeBox::setPasswordDone(const MTPBool &result) { _setRequest = 0; emit reloadPassword(); - auto text = lang(_reenterPasscode->isHidden() ? lng_cloud_password_removed : (_oldPasscode->isHidden() ? lng_cloud_password_was_set : lng_cloud_password_updated)); + auto text = lang(_reenterPasscode->isHidden() ? + lng_cloud_password_removed : + (_oldPasscode->isHidden() ? lng_cloud_password_was_set : lng_cloud_password_updated)); Ui::show(Box(text)); } @@ -318,9 +364,10 @@ void PasscodeBox::onSave(bool force) { } if (!_recoverEmail->isHidden() && email.isEmpty() && !force) { _skipEmailWarning = true; - _replacedBy = Ui::show(Box(lang(lng_cloud_password_about_recover), lang(lng_cloud_password_skip_email), st::attentionBoxButton, base::lambda_guarded(this, [this] { - onSave(true); - })), KeepOtherLayers); + _replacedBy = + Ui::show(Box(lang(lng_cloud_password_about_recover), lang(lng_cloud_password_skip_email), + st::attentionBoxButton, base::lambda_guarded(this, [this] { onSave(true); })), + KeepOtherLayers); } else { QByteArray newPasswordData = pwd.isEmpty() ? QByteArray() : (_newSalt + pwd.toUtf8() + _newSalt); QByteArray newPasswordHash = pwd.isEmpty() ? QByteArray() : QByteArray(32, Qt::Uninitialized); @@ -335,12 +382,17 @@ void PasscodeBox::onSave(bool force) { if (!_oldPasscode->isHidden()) { hashSha256(oldPasswordData.constData(), oldPasswordData.size(), oldPasswordHash.data()); } - auto flags = MTPDaccount_passwordInputSettings::Flag::f_new_salt | MTPDaccount_passwordInputSettings::Flag::f_new_password_hash | MTPDaccount_passwordInputSettings::Flag::f_hint; + auto flags = MTPDaccount_passwordInputSettings::Flag::f_new_salt | + MTPDaccount_passwordInputSettings::Flag::f_new_password_hash | + MTPDaccount_passwordInputSettings::Flag::f_hint; if (_oldPasscode->isHidden() || _newPasscode->isHidden()) { flags |= MTPDaccount_passwordInputSettings::Flag::f_email; } - MTPaccount_PasswordInputSettings settings(MTP_account_passwordInputSettings(MTP_flags(flags), MTP_bytes(_newSalt), MTP_bytes(newPasswordHash), MTP_string(hint), MTP_string(email))); - _setRequest = MTP::send(MTPaccount_UpdatePasswordSettings(MTP_bytes(oldPasswordHash), settings), rpcDone(&PasscodeBox::setPasswordDone), rpcFail(&PasscodeBox::setPasswordFail)); + MTPaccount_PasswordInputSettings settings( + MTP_account_passwordInputSettings(MTP_flags(flags), MTP_bytes(_newSalt), MTP_bytes(newPasswordHash), + MTP_string(hint), MTP_string(email))); + _setRequest = MTP::send(MTPaccount_UpdatePasswordSettings(MTP_bytes(oldPasswordHash), settings), + rpcDone(&PasscodeBox::setPasswordDone), rpcFail(&PasscodeBox::setPasswordFail)); } } else { cSetPasscodeBadTries(0); @@ -388,7 +440,8 @@ void PasscodeBox::onEmailChanged() { void PasscodeBox::onRecoverByEmail() { if (_pattern.isEmpty()) { _pattern = "-"; - MTP::send(MTPauth_RequestPasswordRecovery(), rpcDone(&PasscodeBox::recoverStarted), rpcFail(&PasscodeBox::recoverStartFail)); + MTP::send(MTPauth_RequestPasswordRecovery(), rpcDone(&PasscodeBox::recoverStarted), + rpcFail(&PasscodeBox::recoverStartFail)); } else { recover(); } @@ -419,10 +472,10 @@ bool PasscodeBox::recoverStartFail(const RPCError &error) { return true; } -RecoverBox::RecoverBox(QWidget*, const QString &pattern) -: _pattern(st::normalFont->elided(lng_signin_recover_hint(lt_recover_email, pattern), st::boxWidth - st::boxPadding.left() * 1.5)) -, _recoverCode(this, st::defaultInputField, langFactory(lng_signin_code)) { -} +RecoverBox::RecoverBox(QWidget *, const QString &pattern) + : _pattern(st::normalFont->elided(lng_signin_recover_hint(lt_recover_email, pattern), + st::boxWidth - st::boxPadding.left() * 1.5)) + , _recoverCode(this, st::defaultInputField, langFactory(lng_signin_code)) {} void RecoverBox::prepare() { setTitle(langFactory(lng_signin_recover_title)); @@ -430,7 +483,8 @@ void RecoverBox::prepare() { addButton(langFactory(lng_passcode_submit), [this] { onSubmit(); }); addButton(langFactory(lng_cancel), [this] { closeBox(); }); - setDimensions(st::boxWidth, st::passcodePadding.top() + st::passcodePadding.bottom() + st::passcodeTextLine + _recoverCode->height() + st::passcodeTextLine); + setDimensions(st::boxWidth, st::passcodePadding.top() + st::passcodePadding.bottom() + st::passcodeTextLine + + _recoverCode->height() + st::passcodeTextLine); connect(_recoverCode, SIGNAL(changed()), this, SLOT(onCodeChanged())); connect(_recoverCode, SIGNAL(submitted(bool)), this, SLOT(onSubmit())); @@ -443,12 +497,15 @@ void RecoverBox::paintEvent(QPaintEvent *e) { p.setFont(st::normalFont); p.setPen(st::boxTextFg); - int32 w = st::boxWidth - st::boxPadding.left() * 1.5; - p.drawText(QRect(st::boxPadding.left(), _recoverCode->y() - st::passcodeTextLine - st::passcodePadding.top(), w, st::passcodePadding.top() + st::passcodeTextLine), _pattern, style::al_left); + qint32 w = st::boxWidth - st::boxPadding.left() * 1.5; + p.drawText(QRect(st::boxPadding.left(), _recoverCode->y() - st::passcodeTextLine - st::passcodePadding.top(), w, + st::passcodePadding.top() + st::passcodeTextLine), + _pattern, style::al_left); if (!_error.isEmpty()) { p.setPen(st::boxTextFgError); - p.drawText(QRect(st::boxPadding.left(), _recoverCode->y() + _recoverCode->height(), w, st::passcodeTextLine), _error, style::al_left); + p.drawText(QRect(st::boxPadding.left(), _recoverCode->y() + _recoverCode->height(), w, st::passcodeTextLine), + _error, style::al_left); } } @@ -456,7 +513,8 @@ void RecoverBox::resizeEvent(QResizeEvent *e) { BoxContent::resizeEvent(e); _recoverCode->resize(st::boxWidth - st::boxPadding.left() - st::boxPadding.right(), _recoverCode->height()); - _recoverCode->moveToLeft(st::boxPadding.left(), st::passcodePadding.top() + st::passcodePadding.bottom() + st::passcodeTextLine); + _recoverCode->moveToLeft(st::boxPadding.left(), + st::passcodePadding.top() + st::passcodePadding.bottom() + st::passcodeTextLine); } void RecoverBox::setInnerFocus() { @@ -473,7 +531,8 @@ void RecoverBox::onSubmit() { return; } - _submitRequest = MTP::send(MTPauth_RecoverPassword(MTP_string(code)), rpcDone(&RecoverBox::codeSubmitDone, true), rpcFail(&RecoverBox::codeSubmitFail)); + _submitRequest = MTP::send(MTPauth_RecoverPassword(MTP_string(code)), rpcDone(&RecoverBox::codeSubmitDone, true), + rpcFail(&RecoverBox::codeSubmitFail)); } void RecoverBox::onCodeChanged() { @@ -521,7 +580,7 @@ bool RecoverBox::codeSubmitFail(const RPCError &error) { return true; } if (cDebug()) { // internal server error - _error = err + ": " + error.description(); + _error = err + ": " + error.description(); } else { _error = lang(lng_server_error); } diff --git a/Telegram/SourceFiles/boxes/passcode_box.h b/Telegram/SourceFiles/boxes/passcode_box.h index bb09b75c0..91ebcd655 100644 --- a/Telegram/SourceFiles/boxes/passcode_box.h +++ b/Telegram/SourceFiles/boxes/passcode_box.h @@ -1,26 +1,29 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "boxes/abstract_box.h" +#include "ui/text/text.h" namespace Ui { class InputField; @@ -32,8 +35,9 @@ class PasscodeBox : public BoxContent, public RPCSender { Q_OBJECT public: - PasscodeBox(QWidget*, bool turningOff); - PasscodeBox(QWidget*, const QByteArray &newSalt, const QByteArray &curSalt, bool hasRecovery, const QString &hint, bool turningOff = false); + PasscodeBox(QWidget *, bool turningOff); + PasscodeBox(QWidget *, const QByteArray &newSalt, const QByteArray &curSalt, bool hasRecovery, const QString &hint, + bool turningOff = false); private slots: void onSave(bool force = false); @@ -88,14 +92,13 @@ private slots: object_ptr _recover; QString _oldError, _newError, _emailError; - }; class RecoverBox : public BoxContent, public RPCSender { Q_OBJECT public: - RecoverBox(QWidget*, const QString &pattern); + RecoverBox(QWidget *, const QString &pattern); public slots: void onSubmit(); @@ -123,5 +126,4 @@ public slots: object_ptr _recoverCode; QString _error; - }; diff --git a/Telegram/SourceFiles/boxes/peer_list_box.cpp b/Telegram/SourceFiles/boxes/peer_list_box.cpp index 11127b473..c735738ef 100644 --- a/Telegram/SourceFiles/boxes/peer_list_box.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_box.cpp @@ -1,42 +1,46 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/peer_list_box.h" +#include "base/algorithm.h" -#include "styles/style_boxes.h" -#include "styles/style_dialogs.h" #include "auth_session.h" -#include "mainwidget.h" -#include "ui/widgets/multi_select.h" -#include "ui/widgets/labels.h" -#include "ui/effects/round_checkbox.h" -#include "ui/effects/ripple_animation.h" -#include "ui/effects/widget_slide_wrap.h" #include "lang/lang_keys.h" +#include "mainwidget.h" #include "observer_peer.h" #include "storage/file_download.h" +#include "styles/style_boxes.h" +#include "styles/style_dialogs.h" +#include "ui/effects/ripple_animation.h" +#include "ui/effects/round_checkbox.h" +#include "ui/effects/widget_slide_wrap.h" +#include "ui/widgets/labels.h" +#include "ui/widgets/multi_select.h" #include "window/themes/window_theme.h" -PeerListBox::PeerListBox(QWidget*, std::unique_ptr controller, base::lambda)> init) -: _controller(std::move(controller)) -, _init(std::move(init)) { +PeerListBox::PeerListBox(QWidget *, std::unique_ptr controller, + Fn)> init) + : _controller(std::move(controller)) + , _init(std::move(init)) { Expects(_controller != nullptr); } @@ -49,7 +53,7 @@ void PeerListBox::createMultiSelect() { _select.create(this, std::move(entity), margins, std::move(callback)); _select->entity()->setSubmittedCallback([this](bool chtrlShiftEnter) { _inner->submitted(); }); _select->entity()->setQueryChangedCallback([this](const QString &query) { searchQueryChanged(query); }); - _select->entity()->setItemRemovedCallback([this](uint64 itemId) { + _select->entity()->setItemRemovedCallback([this](quint64 itemId) { if (auto peer = App::peerLoaded(itemId)) { if (auto row = peerListFindRow(peer->id)) { _inner->changeCheckState(row, false, PeerListRow::SetStyle::Animated); @@ -155,7 +159,7 @@ void PeerListBox::peerListAppendSearchRow(std::unique_ptr row) { _inner->appendSearchRow(std::move(row)); } -void PeerListBox::peerListAppendFoundRow(not_null row) { +void PeerListBox::peerListAppendFoundRow(not_null row) { _inner->appendFoundRow(row); } @@ -163,7 +167,7 @@ void PeerListBox::peerListPrependRow(std::unique_ptr row) { _inner->prependRow(std::move(row)); } -void PeerListBox::peerListPrependRowFromSearchResult(not_null row) { +void PeerListBox::peerListPrependRowFromSearchResult(not_null row) { _inner->prependRowFromSearchResult(row); } @@ -171,19 +175,19 @@ PeerListRow *PeerListBox::peerListFindRow(PeerListRowId id) { return _inner->findRow(id); } -void PeerListBox::peerListUpdateRow(not_null row) { +void PeerListBox::peerListUpdateRow(not_null row) { _inner->updateRow(row); } -void PeerListBox::peerListRemoveRow(not_null row) { +void PeerListBox::peerListRemoveRow(not_null row) { _inner->removeRow(row); } -void PeerListBox::peerListConvertRowToSearchResult(not_null row) { +void PeerListBox::peerListConvertRowToSearchResult(not_null row) { _inner->convertRowToSearchResult(row); } -void PeerListBox::peerListSetRowChecked(not_null row, bool checked) { +void PeerListBox::peerListSetRowChecked(not_null row, bool checked) { auto peer = row->peer(); if (checked) { addSelectItem(peer, PeerListRow::SetStyle::Animated); @@ -203,7 +207,7 @@ int PeerListBox::peerListFullRowsCount() { return _inner->fullRowsCount(); } -not_null PeerListBox::peerListRowAt(int index) { +not_null PeerListBox::peerListRowAt(int index) { return _inner->rowAt(index); } @@ -245,23 +249,20 @@ void PeerListBox::peerListSetSearchMode(PeerListSearchMode mode) { } } -void PeerListBox::peerListSortRows(base::lambda compare) { +void PeerListBox::peerListSortRows(Fn compare) { _inner->reorderRows([compare = std::move(compare)](auto &&begin, auto &&end) { - std::sort(begin, end, [&compare](auto &&a, auto &&b) { - return compare(*a, *b); - }); + std::sort(begin, end, [compare](auto &&a, auto &&b) { return compare(*a, *b); }); }); } -void PeerListBox::peerListPartitionRows(base::lambda border) { +void PeerListBox::peerListPartitionRows(Fn border) { _inner->reorderRows([border = std::move(border)](auto &&begin, auto &&end) { - std::stable_partition(begin, end, [&border](auto &¤t) { - return border(*current); - }); + std::stable_partition(begin, end, [border](auto &¤t) { return border(*current); }); }); } -PeerListController::PeerListController(std::unique_ptr searchController) : _searchController(std::move(searchController)) { +PeerListController::PeerListController(std::unique_ptr searchController) + : _searchController(std::move(searchController)) { if (_searchController) { _searchController->setDelegate(this); } @@ -276,7 +277,7 @@ void PeerListController::search(const QString &query) { _searchController->searchQuery(query); } -void PeerListController::peerListSearchAddRow(not_null peer) { +void PeerListController::peerListSearchAddRow(not_null peer) { if (auto row = delegate()->peerListFindRow(peer->id)) { Assert(row->id() == row->peer()->id); delegate()->peerListAppendFoundRow(row); @@ -314,7 +315,7 @@ void PeerListController::setSearchNoResultsText(const QString &text) { } } -void PeerListBox::addSelectItem(not_null peer, PeerListRow::SetStyle style) { +void PeerListBox::addSelectItem(not_null peer, PeerListRow::SetStyle style) { if (!_select) { createMultiSelect(); _select->toggleFast(false); @@ -322,7 +323,8 @@ void PeerListBox::addSelectItem(not_null peer, PeerListRow::SetStyle if (style == PeerListRow::SetStyle::Fast) { _select->entity()->addItemInBunch(peer->id, peer->shortName(), st::activeButtonBg, PaintUserpicCallback(peer)); } else { - _select->entity()->addItem(peer->id, peer->shortName(), st::activeButtonBg, PaintUserpicCallback(peer), Ui::MultiSelect::AddItemWay::Default); + _select->entity()->addItem(peer->id, peer->shortName(), st::activeButtonBg, PaintUserpicCallback(peer), + Ui::MultiSelect::AddItemWay::Default); } } @@ -331,7 +333,7 @@ void PeerListBox::peerListFinishSelectedRowsBunch() { _select->entity()->finishItemsBunch(); } -bool PeerListBox::peerListIsRowSelected(not_null peer) { +bool PeerListBox::peerListIsRowSelected(not_null peer) { return _select ? _select->entity()->hasItem(peer->id) : false; } @@ -339,27 +341,24 @@ int PeerListBox::peerListSelectedRowsCount() { return _select ? _select->entity()->getItemsCount() : 0; } -std::vector> PeerListBox::peerListCollectSelectedRows() { - auto result = std::vector> {}; - auto items = _select ? _select->entity()->getItems() : QVector {}; +std::vector> PeerListBox::peerListCollectSelectedRows() { + auto result = std::vector>{}; + auto items = _select ? _select->entity()->getItems() : QVector{}; if (!items.empty()) { result.reserve(items.size()); - for_const (auto itemId, items) { - result.push_back(App::peer(itemId)); - } + for_const (auto itemId, items) { result.push_back(App::peer(itemId)); } } return result; } -PeerListRow::PeerListRow(not_null peer) : PeerListRow(peer, peer->id) { -} +PeerListRow::PeerListRow(not_null peer) + : PeerListRow(peer, peer->id) {} -PeerListRow::PeerListRow(not_null peer, PeerListRowId id) -: _id(id) -, _peer(peer) -, _initialized(false) -, _isSearchResult(false) { -} +PeerListRow::PeerListRow(not_null peer, PeerListRowId id) + : _id(id) + , _peer(peer) + , _initialized(false) + , _isSearchResult(false) {} bool PeerListRow::checked() const { return _checkbox && _checkbox->checked(); @@ -419,7 +418,8 @@ void PeerListRow::invalidatePixmapsCache() { void PeerListRow::paintStatusText(Painter &p, int x, int y, int availableWidth, int outerWidth, bool selected) { auto statusHasOnlineColor = (_statusType == PeerListRow::StatusType::Online); p.setFont(st::contactsStatusFont); - p.setPen(statusHasOnlineColor ? st::contactsStatusFgOnline : (selected ? st::contactsStatusFgOver : st::contactsStatusFg)); + p.setPen(statusHasOnlineColor ? st::contactsStatusFgOnline : + (selected ? st::contactsStatusFgOver : st::contactsStatusFg)); _status.drawLeftElided(p, x, y, availableWidth, outerWidth); } @@ -496,7 +496,7 @@ void PeerListRow::setStatusText(const QString &text) { _status.setText(st::defaultTextStyle, text, _textNameOptions); } -float64 PeerListRow::checkedRatio() { +double PeerListRow::checkedRatio() { return _checkbox ? _checkbox->checkedAnimationRatio() : 0.; } @@ -509,8 +509,9 @@ void PeerListRow::lazyInitialize() { refreshStatus(); } -void PeerListRow::createCheckbox(base::lambda updateCallback) { - _checkbox = std::make_unique(st::contactsPhotoCheckbox, std::move(updateCallback), PaintUserpicCallback(_peer)); +void PeerListRow::createCheckbox(Fn updateCallback) { + _checkbox = std::make_unique(st::contactsPhotoCheckbox, std::move(updateCallback), + PaintUserpicCallback(_peer)); } void PeerListRow::setCheckedInternal(bool checked, SetStyle style) { @@ -520,20 +521,21 @@ void PeerListRow::setCheckedInternal(bool checked, SetStyle style) { _checkbox->setChecked(checked, speed); } -PeerListBox::Inner::Inner(QWidget *parent, not_null controller) : TWidget(parent) -, _controller(controller) -, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) { +PeerListBox::Inner::Inner(QWidget *parent, not_null controller) + : TWidget(parent) + , _controller(controller) + , _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) { subscribe(Auth().downloaderTaskFinished(), [this] { update(); }); using UpdateFlag = Notify::PeerUpdate::Flag; auto changes = UpdateFlag::NameChanged | UpdateFlag::PhotoChanged; subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(changes, [this](const Notify::PeerUpdate &update) { - if (update.flags & UpdateFlag::PhotoChanged) { - this->update(); - } else if (update.flags & UpdateFlag::NameChanged) { - handleNameChanged(update); - } - })); + if (update.flags & UpdateFlag::PhotoChanged) { + this->update(); + } else if (update.flags & UpdateFlag::NameChanged) { + handleNameChanged(update); + } + })); subscribe(Window::Theme::Background(), [this](const Window::Theme::BackgroundUpdate &update) { if (update.paletteChanged()) { invalidatePixmapsCache(); @@ -562,7 +564,7 @@ void PeerListBox::Inner::appendSearchRow(std::unique_ptr row) { } } -void PeerListBox::Inner::appendFoundRow(not_null row) { +void PeerListBox::Inner::appendFoundRow(not_null row) { Expects(showingSearch()); auto index = findRowIndex(row); if (index.value < 0) { @@ -570,13 +572,11 @@ void PeerListBox::Inner::appendFoundRow(not_null row) { } } -void PeerListBox::Inner::changeCheckState(not_null row, bool checked, PeerListRow::SetStyle style) { - row->setChecked(checked, style, [this, row] { - updateRow(row); - }); +void PeerListBox::Inner::changeCheckState(not_null row, bool checked, PeerListRow::SetStyle style) { + row->setChecked(checked, style, [this, row] { updateRow(row); }); } -void PeerListBox::Inner::addRowEntry(not_null row) { +void PeerListBox::Inner::addRowEntry(not_null row) { _rowsById.emplace(row->id(), row); _rowsByPeer[row->peer()].push_back(row); if (addingToSearchIndex()) { @@ -599,19 +599,17 @@ bool PeerListBox::Inner::addingToSearchIndex() const { return (_searchMode != PeerListSearchMode::Disabled) || !_searchIndex.empty(); } -void PeerListBox::Inner::addToSearchIndex(not_null row) { +void PeerListBox::Inner::addToSearchIndex(not_null row) { if (row->isSearchResult()) { return; } removeFromSearchIndex(row); row->setNameFirstChars(row->peer()->chars); - for_const (auto ch, row->nameFirstChars()) { - _searchIndex[ch].push_back(row); - } + for_const (auto ch, row->nameFirstChars()) { _searchIndex[ch].push_back(row); } } -void PeerListBox::Inner::removeFromSearchIndex(not_null row) { +void PeerListBox::Inner::removeFromSearchIndex(not_null row) { auto &nameFirstChars = row->nameFirstChars(); if (!nameFirstChars.empty()) { for_const (auto ch, row->nameFirstChars()) { @@ -624,7 +622,7 @@ void PeerListBox::Inner::removeFromSearchIndex(not_null row) { } } } - row->setNameFirstChars(OrderedSet()); + row->setNameFirstChars(std::set()); } } @@ -637,7 +635,7 @@ void PeerListBox::Inner::prependRow(std::unique_ptr row) { } } -void PeerListBox::Inner::prependRowFromSearchResult(not_null row) { +void PeerListBox::Inner::prependRowFromSearchResult(not_null row) { if (!row->isSearchResult()) { return; } @@ -675,7 +673,7 @@ PeerListRow *PeerListBox::Inner::findRow(PeerListRowId id) { return (it == _rowsById.cend()) ? nullptr : it->second.get(); } -void PeerListBox::Inner::removeRow(not_null row) { +void PeerListBox::Inner::removeRow(not_null row) { auto index = row->absoluteIndex(); auto isSearchResult = row->isSearchResult(); auto &eraseFrom = isSearchResult ? _searchRows : _rows; @@ -696,7 +694,7 @@ void PeerListBox::Inner::removeRow(not_null row) { restoreSelection(); } -void PeerListBox::Inner::convertRowToSearchResult(not_null row) { +void PeerListBox::Inner::convertRowToSearchResult(not_null row) { if (row->isSearchResult()) { return; } else if (!showingSearch() || !_controller->hasComplexSearch()) { @@ -717,7 +715,7 @@ int PeerListBox::Inner::fullRowsCount() const { return _rows.size(); } -not_null PeerListBox::Inner::rowAt(int index) const { +not_null PeerListBox::Inner::rowAt(int index) const { Expects(index >= 0 && index < _rows.size()); return _rows[index].get(); } @@ -781,14 +779,13 @@ void PeerListBox::Inner::refreshRows() { void PeerListBox::Inner::setSearchMode(PeerListSearchMode mode) { if (_searchMode != mode) { if (!addingToSearchIndex()) { - for_const (auto &row, _rows) { - addToSearchIndex(row.get()); - } + for_const (auto &row, _rows) { addToSearchIndex(row.get()); } } _searchMode = mode; if (_controller->hasComplexSearch()) { if (!_searchLoading) { - setSearchLoading(object_ptr(this, lang(lng_contacts_loading), Ui::FlatLabel::InitType::Simple, st::membersAbout)); + setSearchLoading(object_ptr(this, lang(lng_contacts_loading), + Ui::FlatLabel::InitType::Simple, st::membersAbout)); } } else { clearSearchRows(); @@ -837,13 +834,14 @@ int PeerListBox::Inner::resizeGetHeight(int newWidth) { _aboveHeight = _aboveWidget->height(); } } - auto labelTop = rowsTop() + qMax(1, shownRowsCount()) * _rowHeight; + auto labelTop = rowsTop() + std::max(1, shownRowsCount()) * _rowHeight; if (_description) { _description->moveToLeft(st::contactsPadding.left(), labelTop + st::membersAboutLimitPadding.top(), newWidth); _description->setVisible(!showingSearch()); } if (_searchNoResults) { - _searchNoResults->moveToLeft(st::contactsPadding.left(), labelTop + st::membersAboutLimitPadding.top(), newWidth); + _searchNoResults->moveToLeft(st::contactsPadding.left(), labelTop + st::membersAboutLimitPadding.top(), + newWidth); _searchNoResults->setVisible(showingSearch() && _filterResults.empty() && !_controller->isSearchLoading()); } if (_searchLoading) { @@ -879,9 +877,7 @@ void PeerListBox::Inner::mousePressEvent(QMouseEvent *e) { setPressed(_selected); if (auto row = getRow(_selected.index)) { - auto updateCallback = [this, row, hint = _selected.index] { - updateRow(row, hint); - }; + auto updateCallback = [this, row, hint = _selected.index] { updateRow(row, hint); }; if (_selected.action) { auto actionRect = getActionRect(row, _selected.index); if (!actionRect.isEmpty()) { @@ -927,7 +923,6 @@ void PeerListBox::Inner::paintRow(Painter &p, TimeMs ms, RowIndex index) { row->lazyInitialize(); auto peer = row->peer(); - auto user = peer->asUser(); auto active = (_pressed.index.value >= 0) ? _pressed : _selected; auto selected = (active.index == index); auto actionSelected = (selected && active.action); @@ -950,7 +945,8 @@ void PeerListBox::Inner::paintRow(Painter &p, TimeMs ms, RowIndex index) { if (row->needsVerifiedIcon()) { auto icon = &st::dialogsVerifiedIcon; namew -= icon->width(); - icon->paint(p, namex + qMin(name.maxWidth(), namew), st::contactsPadding.top() + st::contactsNameTop, width()); + icon->paint(p, namex + std::min(name.maxWidth(), namew), st::contactsPadding.top() + st::contactsNameTop, + width()); } auto nameCheckedRatio = row->disabled() ? 0. : row->checkedRatio(); p.setPen(anim::pen(st::contactsNameFg, st::contactsNameCheckedFg, nameCheckedRatio)); @@ -963,7 +959,8 @@ void PeerListBox::Inner::paintRow(Painter &p, TimeMs ms, RowIndex index) { } p.setFont(st::contactsStatusFont); - if (row->isSearchResult() && !_mentionHighlight.isEmpty() && peer->userName().startsWith(_mentionHighlight, Qt::CaseInsensitive)) { + if (row->isSearchResult() && !_mentionHighlight.isEmpty() && + peer->userName().startsWith(_mentionHighlight, Qt::CaseInsensitive)) { auto username = peer->userName(); auto availableWidth = statusw; auto highlightedPart = '@' + username.mid(0, _mentionHighlight.size()); @@ -977,11 +974,11 @@ void PeerListBox::Inner::paintRow(Painter &p, TimeMs ms, RowIndex index) { p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsStatusTop, width(), highlightedPart); } else { grayedPart = st::contactsStatusFont->elided(grayedPart, availableWidth - highlightedWidth); - auto grayedWidth = st::contactsStatusFont->width(grayedPart); p.setPen(st::contactsStatusFgOnline); p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsStatusTop, width(), highlightedPart); p.setPen(selected ? st::contactsStatusFgOver : st::contactsStatusFg); - p.drawTextLeft(namex + highlightedWidth, st::contactsPadding.top() + st::contactsStatusTop, width(), grayedPart); + p.drawTextLeft(namex + highlightedWidth, st::contactsPadding.top() + st::contactsStatusTop, width(), + grayedPart); } } else { row->paintStatusText(p, namex, st::contactsPadding.top() + st::contactsStatusTop, statusw, width(), selected); @@ -999,7 +996,7 @@ void PeerListBox::Inner::selectSkip(int direction) { auto rowsCount = shownRowsCount(); auto index = 0; auto firstEnabled = -1, lastEnabled = -1; - enumerateShownRows([&firstEnabled, &lastEnabled, &index](not_null row) { + enumerateShownRows([&firstEnabled, &lastEnabled, &index](not_null row) { if (!row->disabled()) { if (firstEnabled < 0) { firstEnabled = index; @@ -1018,8 +1015,8 @@ void PeerListBox::Inner::selectSkip(int direction) { Assert(firstEnabled - 1 <= lastEnabled); // Always pass through the first enabled item when changing from / to none selected. - if ((_selected.index.value > firstEnabled && newSelectedIndex < firstEnabled) - || (_selected.index.value < firstEnabled && newSelectedIndex > firstEnabled)) { + if ((_selected.index.value > firstEnabled && newSelectedIndex < firstEnabled) || + (_selected.index.value < firstEnabled && newSelectedIndex > firstEnabled)) { newSelectedIndex = firstEnabled; } @@ -1033,7 +1030,7 @@ void PeerListBox::Inner::selectSkip(int direction) { newSelectedIndex = lastEnabled; } else if (getRow(RowIndex(newSelectedIndex))->disabled()) { auto delta = (direction > 0) ? 1 : -1; - for (newSelectedIndex += delta; ; newSelectedIndex += delta) { + for (newSelectedIndex += delta;; newSelectedIndex += delta) { // We must find an enabled row, firstEnabled <= us <= lastEnabled. Assert(newSelectedIndex >= 0 && newSelectedIndex < rowsCount); if (!getRow(RowIndex(newSelectedIndex))->disabled()) { @@ -1096,7 +1093,7 @@ void PeerListBox::Inner::searchQueryChanged(QString query) { if (_normalizedSearchQuery != normalizedQuery) { setSearchQuery(query, normalizedQuery); if (_controller->searchInLocal() && !searchWordsList.isEmpty()) { - auto minimalList = (const std::vector>*)nullptr; + auto minimalList = (const std::vector> *)nullptr; for_const (auto &searchWord, searchWordsList) { auto searchWordStart = searchWord[0].toLower(); auto it = _searchIndex.find(searchWordStart); @@ -1186,7 +1183,8 @@ void PeerListBox::Inner::updateSelection() { auto in = parentWidget()->rect().contains(parentWidget()->mapFromGlobal(_lastMousePosition)); auto selected = Selected(); auto rowsPointY = point.y() - rowsTop(); - selected.index.value = (in && rowsPointY >= 0 && rowsPointY < shownRowsCount() * _rowHeight) ? (rowsPointY / _rowHeight) : -1; + selected.index.value = + (in && rowsPointY >= 0 && rowsPointY < shownRowsCount() * _rowHeight) ? (rowsPointY / _rowHeight) : -1; if (selected.index.value >= 0) { auto row = getRow(selected.index); if (row->disabled()) { @@ -1200,7 +1198,7 @@ void PeerListBox::Inner::updateSelection() { setSelected(selected); } -QRect PeerListBox::Inner::getActionRect(not_null row, RowIndex index) const { +QRect PeerListBox::Inner::getActionRect(not_null row, RowIndex index) const { auto actionSize = row->actionSize(); if (actionSize.isEmpty()) { return QRect(); @@ -1224,7 +1222,7 @@ int PeerListBox::Inner::getRowTop(RowIndex index) const { return -1; } -void PeerListBox::Inner::updateRow(not_null row, RowIndex hint) { +void PeerListBox::Inner::updateRow(not_null row, RowIndex hint) { updateRow(findRowIndex(row, hint)); } @@ -1244,13 +1242,11 @@ void PeerListBox::Inner::updateRow(RowIndex index) { update(0, getRowTop(index), width(), _rowHeight); } -template -bool PeerListBox::Inner::enumerateShownRows(Callback callback) { +template bool PeerListBox::Inner::enumerateShownRows(Callback callback) { return enumerateShownRows(0, shownRowsCount(), std::move(callback)); } -template -bool PeerListBox::Inner::enumerateShownRows(int from, int to, Callback callback) { +template bool PeerListBox::Inner::enumerateShownRows(int from, int to, Callback callback) { Assert(0 <= from); Assert(from <= to); if (showingSearch()) { @@ -1284,7 +1280,7 @@ PeerListRow *PeerListBox::Inner::getRow(RowIndex index) { return nullptr; } -PeerListBox::Inner::RowIndex PeerListBox::Inner::findRowIndex(not_null row, RowIndex hint) { +PeerListBox::Inner::RowIndex PeerListBox::Inner::findRowIndex(not_null row, RowIndex hint) { if (!showingSearch()) { Assert(!row->isSearchResult()); return RowIndex(row->absoluteIndex()); diff --git a/Telegram/SourceFiles/boxes/peer_list_box.h b/Telegram/SourceFiles/boxes/peer_list_box.h index 394ba0088..876d86864 100644 --- a/Telegram/SourceFiles/boxes/peer_list_box.h +++ b/Telegram/SourceFiles/boxes/peer_list_box.h @@ -1,35 +1,36 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once +#include "base/timer.h" #include "boxes/abstract_box.h" #include "mtproto/sender.h" -#include "base/timer.h" namespace Ui { class RippleAnimation; class RoundImageCheckbox; class MultiSelect; -template -class WidgetSlideWrap; +template class WidgetSlideWrap; class FlatLabel; } // namespace Ui @@ -43,11 +44,11 @@ inline auto PaintUserpicCallback(PeerData *peer) { }; } -using PeerListRowId = uint64; +using PeerListRowId = quint64; class PeerListRow { public: - PeerListRow(not_null peer); - PeerListRow(not_null peer, PeerListRowId id); + PeerListRow(not_null peer); + PeerListRow(not_null peer, PeerListRowId id); enum class State { Active, @@ -64,7 +65,7 @@ class PeerListRow { // added to the box it is always false. bool checked() const; - not_null peer() const { + not_null peer() const { return _peer; } PeerListRowId id() const { @@ -86,12 +87,9 @@ class PeerListRow { virtual QMargins actionMargins() const { return QMargins(); } - virtual void addActionRipple(QPoint point, base::lambda updateCallback) { - } - virtual void stopLastActionRipple() { - } - virtual void paintAction(Painter &p, TimeMs ms, int x, int y, int outerWidth, bool actionSelected) { - } + virtual void addActionRipple(QPoint point, Fn updateCallback) {} + virtual void stopLastActionRipple() {} + virtual void paintAction(Painter &p, TimeMs ms, int x, int y, int outerWidth, bool actionSelected) {} void refreshName(); const Text &name() const { @@ -125,8 +123,7 @@ class PeerListRow { Animated, Fast, }; - template - void setChecked(bool checked, SetStyle style, UpdateCallback callback) { + template void setChecked(bool checked, SetStyle style, UpdateCallback callback) { if (checked && !_checkbox) { createCheckbox(std::move(callback)); } @@ -134,17 +131,16 @@ class PeerListRow { } void invalidatePixmapsCache(); - template - void addRipple(QSize size, QPoint point, UpdateCallback updateCallback); + template void addRipple(QSize size, QPoint point, UpdateCallback updateCallback); void stopLastRipple(); void paintRipple(Painter &p, TimeMs ms, int x, int y, int outerWidth); void paintUserpic(Painter &p, TimeMs ms, int x, int y, int outerWidth); - float64 checkedRatio(); + double checkedRatio(); - void setNameFirstChars(const OrderedSet &nameFirstChars) { + void setNameFirstChars(const std::set &nameFirstChars) { _nameFirstChars = nameFirstChars; } - const OrderedSet &nameFirstChars() const { + const std::set &nameFirstChars() const { return _nameFirstChars; } @@ -157,24 +153,23 @@ class PeerListRow { } private: - void createCheckbox(base::lambda updateCallback); + void createCheckbox(Fn updateCallback); void setCheckedInternal(bool checked, SetStyle style); void paintDisabledCheckUserpic(Painter &p, int x, int y, int outerWidth) const; void setStatusText(const QString &text); PeerListRowId _id = 0; - not_null _peer; + not_null _peer; std::unique_ptr _ripple; std::unique_ptr _checkbox; Text _name; Text _status; StatusType _statusType = StatusType::Online; - OrderedSet _nameFirstChars; + std::set _nameFirstChars; int _absoluteIndex = -1; State _disabledState = State::Active; bool _initialized : 1; bool _isSearchResult : 1; - }; enum class PeerListSearchMode { @@ -184,8 +179,8 @@ enum class PeerListSearchMode { class PeerListDelegate { public: - virtual void peerListSetTitle(base::lambda title) = 0; - virtual void peerListSetAdditionalTitle(base::lambda title) = 0; + virtual void peerListSetTitle(Fn title) = 0; + virtual void peerListSetAdditionalTitle(Fn title) = 0; virtual void peerListSetDescription(object_ptr description) = 0; virtual void peerListSetSearchLoading(object_ptr loading) = 0; virtual void peerListSetSearchNoResults(object_ptr noResults) = 0; @@ -193,24 +188,23 @@ class PeerListDelegate { virtual void peerListSetSearchMode(PeerListSearchMode mode) = 0; virtual void peerListAppendRow(std::unique_ptr row) = 0; virtual void peerListAppendSearchRow(std::unique_ptr row) = 0; - virtual void peerListAppendFoundRow(not_null row) = 0; + virtual void peerListAppendFoundRow(not_null row) = 0; virtual void peerListPrependRow(std::unique_ptr row) = 0; - virtual void peerListPrependRowFromSearchResult(not_null row) = 0; - virtual void peerListUpdateRow(not_null row) = 0; - virtual void peerListRemoveRow(not_null row) = 0; - virtual void peerListConvertRowToSearchResult(not_null row) = 0; - virtual bool peerListIsRowSelected(not_null peer) = 0; - virtual void peerListSetRowChecked(not_null row, bool checked) = 0; - virtual not_null peerListRowAt(int index) = 0; + virtual void peerListPrependRowFromSearchResult(not_null row) = 0; + virtual void peerListUpdateRow(not_null row) = 0; + virtual void peerListRemoveRow(not_null row) = 0; + virtual void peerListConvertRowToSearchResult(not_null row) = 0; + virtual bool peerListIsRowSelected(not_null peer) = 0; + virtual void peerListSetRowChecked(not_null row, bool checked) = 0; + virtual not_null peerListRowAt(int index) = 0; virtual void peerListRefreshRows() = 0; virtual void peerListScrollToTop() = 0; virtual int peerListFullRowsCount() = 0; virtual PeerListRow *peerListFindRow(PeerListRowId id) = 0; - virtual void peerListSortRows(base::lambda compare) = 0; - virtual void peerListPartitionRows(base::lambda border) = 0; + virtual void peerListSortRows(Fn compare) = 0; + virtual void peerListPartitionRows(Fn border) = 0; - template - void peerListAddSelectedRows(PeerDataRange &&range) { + template void peerListAddSelectedRows(PeerDataRange &&range) { for (auto peer : range) { peerListAddSelectedRowInBunch(peer); } @@ -218,21 +212,19 @@ class PeerListDelegate { } virtual int peerListSelectedRowsCount() = 0; - virtual std::vector> peerListCollectSelectedRows() = 0; + virtual std::vector> peerListCollectSelectedRows() = 0; virtual ~PeerListDelegate() = default; private: - virtual void peerListAddSelectedRowInBunch(not_null peer) = 0; + virtual void peerListAddSelectedRowInBunch(not_null peer) = 0; virtual void peerListFinishSelectedRowsBunch() = 0; - }; class PeerListSearchDelegate { public: - virtual void peerListSearchAddRow(not_null peer) = 0; + virtual void peerListSearchAddRow(not_null peer) = 0; virtual void peerListSearchRefreshRows() = 0; virtual ~PeerListSearchDelegate() = default; - }; class PeerListSearchController { @@ -242,18 +234,17 @@ class PeerListSearchController { virtual bool loadMoreRows() = 0; virtual ~PeerListSearchController() = default; - void setDelegate(not_null delegate) { + void setDelegate(not_null delegate) { _delegate = delegate; } protected: - not_null delegate() const { + not_null delegate() const { return _delegate; } private: PeerListSearchDelegate *_delegate = nullptr; - }; class PeerListController : public PeerListSearchDelegate { @@ -261,27 +252,24 @@ class PeerListController : public PeerListSearchDelegate { // Search works only with RowId == peer->id. PeerListController(std::unique_ptr searchController = nullptr); - void setDelegate(not_null delegate) { + void setDelegate(not_null delegate) { _delegate = delegate; prepare(); } virtual void prepare() = 0; - virtual void rowClicked(not_null row) = 0; - virtual void rowActionClicked(not_null row) { - } - virtual void loadMoreRows() { - } - virtual void itemDeselectedHook(not_null peer) { - } + virtual void rowClicked(not_null row) = 0; + virtual void rowActionClicked(not_null row) {} + virtual void loadMoreRows() {} + virtual void itemDeselectedHook(not_null peer) {} bool isSearchLoading() const { return _searchController ? _searchController->isLoading() : false; } - virtual std::unique_ptr createSearchRow(not_null peer) { + virtual std::unique_ptr createSearchRow(not_null peer) { return nullptr; } - bool isRowSelected(not_null peer) { + bool isRowSelected(not_null peer) { return delegate()->peerListIsRowSelected(peer); } @@ -291,13 +279,13 @@ class PeerListController : public PeerListSearchDelegate { bool hasComplexSearch() const; void search(const QString &query); - void peerListSearchAddRow(not_null peer) override; + void peerListSearchAddRow(not_null peer) override; void peerListSearchRefreshRows() override; virtual ~PeerListController() = default; protected: - not_null delegate() const { + not_null delegate() const { return _delegate; } PeerListSearchController *searchController() const { @@ -320,17 +308,16 @@ class PeerListController : public PeerListSearchDelegate { private: PeerListDelegate *_delegate = nullptr; std::unique_ptr _searchController = nullptr; - }; class PeerListBox : public BoxContent, public PeerListDelegate { public: - PeerListBox(QWidget*, std::unique_ptr controller, base::lambda)> init); + PeerListBox(QWidget *, std::unique_ptr controller, Fn)> init); - void peerListSetTitle(base::lambda title) override { + void peerListSetTitle(Fn title) override { setTitle(std::move(title)); } - void peerListSetAdditionalTitle(base::lambda title) override { + void peerListSetAdditionalTitle(Fn title) override { setAdditionalTitle(std::move(title)); } void peerListSetDescription(object_ptr description) override; @@ -340,23 +327,23 @@ class PeerListBox : public BoxContent, public PeerListDelegate { void peerListSetSearchMode(PeerListSearchMode mode) override; void peerListAppendRow(std::unique_ptr row) override; void peerListAppendSearchRow(std::unique_ptr row) override; - void peerListAppendFoundRow(not_null row) override; + void peerListAppendFoundRow(not_null row) override; void peerListPrependRow(std::unique_ptr row) override; - void peerListPrependRowFromSearchResult(not_null row) override; - void peerListUpdateRow(not_null row) override; - void peerListRemoveRow(not_null row) override; - void peerListConvertRowToSearchResult(not_null row) override; - void peerListSetRowChecked(not_null row, bool checked) override; - not_null peerListRowAt(int index) override; - bool peerListIsRowSelected(not_null peer) override; + void peerListPrependRowFromSearchResult(not_null row) override; + void peerListUpdateRow(not_null row) override; + void peerListRemoveRow(not_null row) override; + void peerListConvertRowToSearchResult(not_null row) override; + void peerListSetRowChecked(not_null row, bool checked) override; + not_null peerListRowAt(int index) override; + bool peerListIsRowSelected(not_null peer) override; int peerListSelectedRowsCount() override; - std::vector> peerListCollectSelectedRows() override; + std::vector> peerListCollectSelectedRows() override; void peerListRefreshRows() override; void peerListScrollToTop() override; int peerListFullRowsCount() override; PeerListRow *peerListFindRow(PeerListRowId id) override; - void peerListSortRows(base::lambda compare) override; - void peerListPartitionRows(base::lambda border) override; + void peerListSortRows(Fn compare) override; + void peerListPartitionRows(Fn border) override; protected: void prepare() override; @@ -367,26 +354,25 @@ class PeerListBox : public BoxContent, public PeerListDelegate { void paintEvent(QPaintEvent *e) override; private: - void peerListAddSelectedRowInBunch(not_null peer) override { + void peerListAddSelectedRowInBunch(not_null peer) override { addSelectItem(peer, PeerListRow::SetStyle::Fast); } void peerListFinishSelectedRowsBunch() override; - void addSelectItem(not_null peer, PeerListRow::SetStyle style); + void addSelectItem(not_null peer, PeerListRow::SetStyle style); void createMultiSelect(); int getTopScrollSkip() const; void updateScrollSkips(); void searchQueryChanged(const QString &query); - object_ptr> _select = { nullptr }; + object_ptr> _select = {nullptr}; class Inner; QPointer _inner; std::unique_ptr _controller; - base::lambda _init; + Fn _init; bool _scrollBottomFixed = true; - }; // This class is hold in header because it requires Qt preprocessing. @@ -394,7 +380,7 @@ class PeerListBox::Inner : public TWidget, private base::Subscriber { Q_OBJECT public: - Inner(QWidget *parent, not_null controller); + Inner(QWidget *parent, not_null controller); void selectSkip(int direction); void selectSkipPage(int height, int direction); @@ -409,17 +395,17 @@ class PeerListBox::Inner : public TWidget, private base::Subscriber { // Interface for the controller. void appendRow(std::unique_ptr row); void appendSearchRow(std::unique_ptr row); - void appendFoundRow(not_null row); + void appendFoundRow(not_null row); void prependRow(std::unique_ptr row); - void prependRowFromSearchResult(not_null row); + void prependRowFromSearchResult(not_null row); PeerListRow *findRow(PeerListRowId id); - void updateRow(not_null row) { + void updateRow(not_null row) { updateRow(row, RowIndex()); } - void removeRow(not_null row); - void convertRowToSearchResult(not_null row); + void removeRow(not_null row); + void convertRowToSearchResult(not_null row); int fullRowsCount() const; - not_null rowAt(int index) const; + not_null rowAt(int index) const; void setDescription(object_ptr description); void setSearchLoading(object_ptr loading); void setSearchNoResults(object_ptr noResults); @@ -427,10 +413,9 @@ class PeerListBox::Inner : public TWidget, private base::Subscriber { void refreshRows(); void setSearchMode(PeerListSearchMode mode); - void changeCheckState(not_null row, bool checked, PeerListRow::SetStyle style); + void changeCheckState(not_null row, bool checked, PeerListRow::SetStyle style); - template - void reorderRows(ReorderCallback &&callback) { + template void reorderRows(ReorderCallback &&callback) { callback(_rows.begin(), _rows.end()); for (auto &searchEntity : _searchIndex) { callback(searchEntity.second.begin(), searchEntity.second.end()); @@ -461,10 +446,9 @@ public slots: void invalidatePixmapsCache(); struct RowIndex { - RowIndex() { - } - explicit RowIndex(int value) : value(value) { - } + RowIndex() {} + explicit RowIndex(int value) + : value(value) {} int value = -1; }; friend inline bool operator==(RowIndex a, RowIndex b) { @@ -475,12 +459,13 @@ public slots: } struct Selected { - Selected() { - } - Selected(RowIndex index, bool action) : index(index), action(action) { - } - Selected(int index, bool action) : index(index), action(action) { - } + Selected() {} + Selected(RowIndex index, bool action) + : index(index) + , action(action) {} + Selected(int index, bool action) + : index(index) + , action(action) {} RowIndex index; bool action = false; }; @@ -499,19 +484,19 @@ public slots: void loadProfilePhotos(); void checkScrollForPreload(); - void updateRow(not_null row, RowIndex hint); + void updateRow(not_null row, RowIndex hint); void updateRow(RowIndex row); int getRowTop(RowIndex row) const; PeerListRow *getRow(RowIndex element); - RowIndex findRowIndex(not_null row, RowIndex hint = RowIndex()); - QRect getActionRect(not_null row, RowIndex index) const; + RowIndex findRowIndex(not_null row, RowIndex hint = RowIndex()); + QRect getActionRect(not_null row, RowIndex index) const; void paintRow(Painter &p, TimeMs ms, RowIndex index); - void addRowEntry(not_null row); - void addToSearchIndex(not_null row); + void addRowEntry(not_null row); + void addToSearchIndex(not_null row); bool addingToSearchIndex() const; - void removeFromSearchIndex(not_null row); + void removeFromSearchIndex(not_null row); void setSearchQuery(const QString &query, const QString &normalizedQuery); bool showingSearch() const { return !_searchQuery.isEmpty(); @@ -519,17 +504,15 @@ public slots: int shownRowsCount() const { return showingSearch() ? _filterResults.size() : _rows.size(); } - template - bool enumerateShownRows(Callback callback); - template - bool enumerateShownRows(int from, int to, Callback callback); + template bool enumerateShownRows(Callback callback); + template bool enumerateShownRows(int from, int to, Callback callback); int rowsTop() const; int labelHeight() const; void clearSearchRows(); - not_null _controller; + not_null _controller; PeerListSearchMode _searchMode = PeerListSearchMode::Disabled; int _rowHeight = 0; @@ -541,23 +524,22 @@ public slots: bool _mouseSelection = false; std::vector> _rows; - std::map> _rowsById; - std::map>> _rowsByPeer; + std::map> _rowsById; + std::map>> _rowsByPeer; - std::map>> _searchIndex; + std::map>> _searchIndex; QString _searchQuery; QString _normalizedSearchQuery; QString _mentionHighlight; - std::vector> _filterResults; + std::vector> _filterResults; int _aboveHeight = 0; - object_ptr _aboveWidget = { nullptr }; - object_ptr _description = { nullptr }; - object_ptr _searchNoResults = { nullptr }; - object_ptr _searchLoading = { nullptr }; + object_ptr _aboveWidget = {nullptr}; + object_ptr _description = {nullptr}; + object_ptr _searchNoResults = {nullptr}; + object_ptr _searchLoading = {nullptr}; QPoint _lastMousePosition; std::vector> _searchRows; - }; diff --git a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp index 49c11281f..cc71613de 100644 --- a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp @@ -1,49 +1,51 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/peer_list_controllers.h" - -#include "styles/style_boxes.h" -#include "styles/style_profile.h" +#include "apiwrap.h" +#include "auth_session.h" +#include "base/algorithm.h" #include "boxes/confirm_box.h" +#include "dialogs/dialogs_indexed_list.h" +#include "lang/lang_keys.h" +#include "mainwidget.h" #include "observer_peer.h" +#include "styles/style_boxes.h" +#include "styles/style_profile.h" #include "ui/widgets/checkbox.h" -#include "auth_session.h" -#include "apiwrap.h" -#include "mainwidget.h" -#include "lang/lang_keys.h" -#include "dialogs/dialogs_indexed_list.h" namespace { -base::flat_set> GetAlreadyInFromPeer(PeerData *peer) { +base::flat_set> GetAlreadyInFromPeer(PeerData *peer) { if (!peer) { return {}; } if (auto chat = peer->asChat()) { auto participants = chat->participants.keys(); - return { participants.cbegin(), participants.cend() }; + return {participants.cbegin(), participants.cend()}; } else if (auto channel = peer->asChannel()) { if (channel->isMegagroup()) { auto &participants = channel->mgInfo->lastParticipants; - return { participants.cbegin(), participants.cend() }; + return {participants.cbegin(), participants.cend()}; } } return {}; @@ -53,13 +55,13 @@ base::flat_set> GetAlreadyInFromPeer(PeerData *peer) { // Not used for now. // -//MembersAddButton::MembersAddButton(QWidget *parent, const style::TwoIconButton &st) : RippleButton(parent, st.ripple) +// MembersAddButton::MembersAddButton(QWidget *parent, const style::TwoIconButton &st) : RippleButton(parent, st.ripple) //, _st(st) { // resize(_st.width, _st.height); // setCursor(style::cur_pointer); //} // -//void MembersAddButton::paintEvent(QPaintEvent *e) { +// void MembersAddButton::paintEvent(QPaintEvent *e) { // Painter p(this); // // auto ms = getms(); @@ -71,17 +73,18 @@ base::flat_set> GetAlreadyInFromPeer(PeerData *peer) { // ((over || down) ? _st.iconAboveOver : _st.iconAbove).paint(p, _st.iconPosition, width()); //} // -//QImage MembersAddButton::prepareRippleMask() const { +// QImage MembersAddButton::prepareRippleMask() const { // return Ui::RippleAnimation::ellipseMask(QSize(_st.rippleAreaSize, _st.rippleAreaSize)); //} // -//QPoint MembersAddButton::prepareRippleStartPosition() const { +// QPoint MembersAddButton::prepareRippleStartPosition() const { // return mapFromGlobal(QCursor::pos()) - _st.rippleAreaPosition; //} class EditChatAdminsBoxController::LabeledCheckbox : public TWidget, private base::Subscriber { public: - LabeledCheckbox(QWidget *parent, const QString &text, bool checked = false, const style::Checkbox &st = st::defaultCheckbox, const style::Check &checkSt = st::defaultCheck); + LabeledCheckbox(QWidget *parent, const QString &text, bool checked = false, + const style::Checkbox &st = st::defaultCheckbox, const style::Check &checkSt = st::defaultCheck); base::Observable checkedChanged; @@ -89,12 +92,8 @@ class EditChatAdminsBoxController::LabeledCheckbox : public TWidget, private bas return _checkbox->checked(); } - void setLabelText( - bool checked, - const style::TextStyle &st, - const QString &text, - const TextParseOptions &options = _defaultOptions, - int minResizeWidth = QFIXED_MAX); + void setLabelText(bool checked, const style::TextStyle &st, const QString &text, + const TextParseOptions &options = _defaultOptions, int minResizeWidth = QFIXED_MAX); protected: int resizeGetHeight(int newWidth) override; @@ -105,7 +104,6 @@ class EditChatAdminsBoxController::LabeledCheckbox : public TWidget, private bas Text _labelUnchecked; Text _labelChecked; int _labelWidth = 0; - }; void PeerListRowWithLink::setActionLink(const QString &action) { @@ -128,7 +126,10 @@ QSize PeerListRowWithLink::actionSize() const { } QMargins PeerListRowWithLink::actionMargins() const { - return QMargins(st::contactsCheckPosition.x(), (st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom() - st::normalFont->height) / 2, st::contactsCheckPosition.x(), 0); + return QMargins( + st::contactsCheckPosition.x(), + (st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom() - st::normalFont->height) / 2, + st::contactsCheckPosition.x(), 0); } void PeerListRowWithLink::paintAction(Painter &p, TimeMs ms, int x, int y, int outerWidth, bool actionSelected) { @@ -164,14 +165,16 @@ bool PeerListGlobalSearchController::searchInCache() { } void PeerListGlobalSearchController::searchOnServer() { - _requestId = request(MTPcontacts_Search(MTP_string(_query), MTP_int(SearchPeopleLimit))).done([this](const MTPcontacts_Found &result, mtpRequestId requestId) { - searchDone(result, requestId); - }).fail([this](const RPCError &error, mtpRequestId requestId) { - if (_requestId == requestId) { - _requestId = 0; - delegate()->peerListSearchRefreshRows(); - } - }).send(); + _requestId = + request(MTPcontacts_Search(MTP_string(_query), MTP_int(SearchPeopleLimit))) + .done([this](const MTPcontacts_Found &result, mtpRequestId requestId) { searchDone(result, requestId); }) + .fail([this](const RPCError &error, mtpRequestId requestId) { + if (_requestId == requestId) { + _requestId = 0; + delegate()->peerListSearchRefreshRows(); + } + }) + .send(); _queries.emplace(_requestId, _query); } @@ -205,8 +208,8 @@ bool PeerListGlobalSearchController::isLoading() { return _timer.isActive() || _requestId; } -ChatsListBoxController::ChatsListBoxController(std::unique_ptr searchController) : PeerListController(std::move(searchController)) { -} +ChatsListBoxController::ChatsListBoxController(std::unique_ptr searchController) + : PeerListController(std::move(searchController)) {} void ChatsListBoxController::prepare() { setSearchNoResultsText(lang(lng_blocked_list_not_found)); @@ -217,15 +220,9 @@ void ChatsListBoxController::prepare() { rebuildRows(); auto &sessionData = Auth().data(); - subscribe(sessionData.contactsLoaded(), [this](bool loaded) { - rebuildRows(); - }); - subscribe(sessionData.moreChatsLoaded(), [this] { - rebuildRows(); - }); - subscribe(sessionData.allChatsLoaded(), [this](bool loaded) { - checkForEmptyRows(); - }); + subscribe(sessionData.contactsLoaded(), [this](bool loaded) { rebuildRows(); }); + subscribe(sessionData.moreChatsLoaded(), [this] { rebuildRows(); }); + subscribe(sessionData.allChatsLoaded(), [this](bool loaded) { checkForEmptyRows(); }); } void ChatsListBoxController::rebuildRows() { @@ -244,7 +241,7 @@ void ChatsListBoxController::rebuildRows() { if (!wasEmpty && added > 0) { // Place dialogs list before contactsNoDialogs list. delegate()->peerListPartitionRows([](PeerListRow &a) { - auto history = static_cast(a).history(); + auto history = static_cast(a).history(); return history->inChatList(Dialogs::Mode::All); }); } @@ -266,13 +263,13 @@ QString ChatsListBoxController::emptyBoxText() const { return lang(lng_contacts_not_found); } -std::unique_ptr ChatsListBoxController::createSearchRow(not_null peer) { +std::unique_ptr ChatsListBoxController::createSearchRow(not_null peer) { return createRow(App::history(peer)); } -bool ChatsListBoxController::appendRow(not_null history) { +bool ChatsListBoxController::appendRow(not_null history) { if (auto row = delegate()->peerListFindRow(history->peer->id)) { - updateRowHook(static_cast(row)); + updateRowHook(static_cast(row)); return false; } if (auto row = createRow(history)) { @@ -282,8 +279,8 @@ bool ChatsListBoxController::appendRow(not_null history) { return false; } -ContactsBoxController::ContactsBoxController(std::unique_ptr searchController) : PeerListController(std::move(searchController)) { -} +ContactsBoxController::ContactsBoxController(std::unique_ptr searchController) + : PeerListController(std::move(searchController)) {} void ContactsBoxController::prepare() { setSearchNoResultsText(lang(lng_blocked_list_not_found)); @@ -295,9 +292,7 @@ void ContactsBoxController::prepare() { rebuildRows(); auto &sessionData = Auth().data(); - subscribe(sessionData.contactsLoaded(), [this](bool loaded) { - rebuildRows(); - }); + subscribe(sessionData.contactsLoaded(), [this](bool loaded) { rebuildRows(); }); } void ContactsBoxController::rebuildRows() { @@ -328,18 +323,18 @@ void ContactsBoxController::checkForEmptyRows() { } } -std::unique_ptr ContactsBoxController::createSearchRow(not_null peer) { +std::unique_ptr ContactsBoxController::createSearchRow(not_null peer) { if (auto user = peer->asUser()) { return createRow(user); } return nullptr; } -void ContactsBoxController::rowClicked(not_null row) { +void ContactsBoxController::rowClicked(not_null row) { Ui::showPeerHistory(row->peer(), ShowAtUnreadMsgId); } -bool ContactsBoxController::appendRow(not_null user) { +bool ContactsBoxController::appendRow(not_null user) { if (auto row = delegate()->peerListFindRow(user->id)) { updateRowHook(row); return false; @@ -351,25 +346,22 @@ bool ContactsBoxController::appendRow(not_null user) { return false; } -std::unique_ptr ContactsBoxController::createRow(not_null user) { +std::unique_ptr ContactsBoxController::createRow(not_null user) { return std::make_unique(user); } AddParticipantsBoxController::AddParticipantsBoxController(PeerData *peer) -: ContactsBoxController(std::make_unique()) -, _peer(peer) -, _alreadyIn(GetAlreadyInFromPeer(peer)) { -} + : ContactsBoxController(std::make_unique()) + , _peer(peer) + , _alreadyIn(GetAlreadyInFromPeer(peer)) {} -AddParticipantsBoxController::AddParticipantsBoxController( - not_null channel, - base::flat_set> &&alreadyIn) -: ContactsBoxController(std::make_unique()) -, _peer(channel) -, _alreadyIn(std::move(alreadyIn)) { -} +AddParticipantsBoxController::AddParticipantsBoxController(not_null channel, + base::flat_set> &&alreadyIn) + : ContactsBoxController(std::make_unique()) + , _peer(channel) + , _alreadyIn(std::move(alreadyIn)) {} -void AddParticipantsBoxController::rowClicked(not_null row) { +void AddParticipantsBoxController::rowClicked(not_null row) { auto count = fullCount(); auto limit = (_peer && _peer->isMegagroup()) ? Global::MegagroupSizeMax() : Global::ChatSizeMax(); if (count < limit || row->checked()) { @@ -380,11 +372,12 @@ void AddParticipantsBoxController::rowClicked(not_null row) { Ui::show(Box(_peer->asChannel()), KeepOtherLayers); } } else if (count >= Global::ChatSizeMax() && count < Global::MegagroupSizeMax()) { - Ui::show(Box(lng_profile_add_more_after_upgrade(lt_count, Global::MegagroupSizeMax())), KeepOtherLayers); + Ui::show(Box(lng_profile_add_more_after_upgrade(lt_count, Global::MegagroupSizeMax())), + KeepOtherLayers); } } -void AddParticipantsBoxController::itemDeselectedHook(not_null peer) { +void AddParticipantsBoxController::itemDeselectedHook(not_null peer) { updateTitle(); } @@ -397,22 +390,22 @@ int AddParticipantsBoxController::alreadyInCount() const { return 1; // self } if (auto chat = _peer->asChat()) { - return qMax(chat->count, 1); + return std::max(chat->count, 1); } else if (auto channel = _peer->asChannel()) { - return qMax(channel->membersCount(), int(_alreadyIn.size())); + return std::max(channel->membersCount(), int(_alreadyIn.size())); } Unexpected("User in AddParticipantsBoxController::alreadyInCount"); } -bool AddParticipantsBoxController::isAlreadyIn(not_null user) const { +bool AddParticipantsBoxController::isAlreadyIn(not_null user) const { if (!_peer) { return false; } if (auto chat = _peer->asChat()) { return chat->participants.contains(user); } else if (auto channel = _peer->asChannel()) { - return _alreadyIn.contains(user) - || (channel->isMegagroup() && channel->mgInfo->lastParticipants.contains(user)); + return _alreadyIn.contains(user) || + (channel->isMegagroup() && channel->mgInfo->lastParticipants.contains(user)); } Unexpected("User in AddParticipantsBoxController::isAlreadyIn"); } @@ -421,7 +414,7 @@ int AddParticipantsBoxController::fullCount() const { return alreadyInCount() + delegate()->peerListSelectedRowsCount(); } -std::unique_ptr AddParticipantsBoxController::createRow(not_null user) { +std::unique_ptr AddParticipantsBoxController::createRow(not_null user) { if (user->isSelf()) { return nullptr; } @@ -433,19 +426,19 @@ std::unique_ptr AddParticipantsBoxController::createRow(not_nullisChannel() && !_peer->isMegagroup()) - ? QString() : - QString("%1 / %2").arg(fullCount()).arg(Global::MegagroupSizeMax()); + auto additional = (_peer && _peer->isChannel() && !_peer->isMegagroup()) ? + QString() : + QString("%1 / %2").arg(fullCount()).arg(Global::MegagroupSizeMax()); delegate()->peerListSetTitle(langFactory(lng_profile_add_participant)); delegate()->peerListSetAdditionalTitle([additional] { return additional; }); } -void AddParticipantsBoxController::Start(not_null chat) { - auto initBox = [chat](not_null box) { +void AddParticipantsBoxController::Start(not_null chat) { + auto initBox = [chat](not_null box) { box->addButton(langFactory(lng_participant_invite), [box, chat] { auto rows = box->peerListCollectSelectedRows(); if (!rows.empty()) { - auto users = std::vector>(); + auto users = std::vector>(); for (auto peer : rows) { auto user = peer->asUser(); Assert(user != nullptr); @@ -461,16 +454,14 @@ void AddParticipantsBoxController::Start(not_null chat) { Ui::show(Box(std::make_unique(chat), std::move(initBox))); } -void AddParticipantsBoxController::Start( - not_null channel, - base::flat_set> &&alreadyIn, - bool justCreated) { - auto initBox = [channel, justCreated](not_null box) { +void AddParticipantsBoxController::Start(not_null channel, + base::flat_set> &&alreadyIn, bool justCreated) { + auto initBox = [channel, justCreated](not_null box) { auto subscription = std::make_shared(); box->addButton(langFactory(lng_participant_invite), [box, channel, subscription] { auto rows = box->peerListCollectSelectedRows(); if (!rows.empty()) { - auto users = std::vector>(); + auto users = std::vector>(); for (auto peer : rows) { auto user = peer->asUser(); Assert(user != nullptr); @@ -487,41 +478,33 @@ void AddParticipantsBoxController::Start( }); box->addButton(langFactory(justCreated ? lng_create_group_skip : lng_cancel), [box] { box->closeBox(); }); if (justCreated) { - *subscription = box->boxClosing.add_subscription([channel] { - Ui::showPeerHistory(channel, ShowAtTheEndMsgId); - }); + *subscription = + box->boxClosing.add_subscription([channel] { Ui::showPeerHistory(channel, ShowAtTheEndMsgId); }); } }; - Ui::show(Box(std::make_unique(channel, std::move(alreadyIn)), std::move(initBox))); + Ui::show(Box(std::make_unique(channel, std::move(alreadyIn)), + std::move(initBox))); } -void AddParticipantsBoxController::Start( - not_null channel, - base::flat_set> &&alreadyIn) { +void AddParticipantsBoxController::Start(not_null channel, + base::flat_set> &&alreadyIn) { Start(channel, std::move(alreadyIn), false); } -void AddParticipantsBoxController::Start(not_null channel) { +void AddParticipantsBoxController::Start(not_null channel) { Start(channel, {}, true); } -EditChatAdminsBoxController::LabeledCheckbox::LabeledCheckbox( - QWidget *parent, - const QString &text, - bool checked, - const style::Checkbox &st, - const style::Check &checkSt) -: TWidget(parent) -, _checkbox(this, text, checked, st, checkSt) { +EditChatAdminsBoxController::LabeledCheckbox::LabeledCheckbox(QWidget *parent, const QString &text, bool checked, + const style::Checkbox &st, const style::Check &checkSt) + : TWidget(parent) + , _checkbox(this, text, checked, st, checkSt) { subscribe(_checkbox->checkedChanged, [this](bool value) { checkedChanged.notify(value, true); }); } -void EditChatAdminsBoxController::LabeledCheckbox::setLabelText( - bool checked, - const style::TextStyle &st, - const QString &text, - const TextParseOptions &options, - int minResizeWidth) { +void EditChatAdminsBoxController::LabeledCheckbox::setLabelText(bool checked, const style::TextStyle &st, + const QString &text, const TextParseOptions &options, + int minResizeWidth) { auto &label = (checked ? _labelChecked : _labelUnchecked); label = Text(st, text, options, minResizeWidth); } @@ -530,9 +513,7 @@ int EditChatAdminsBoxController::LabeledCheckbox::resizeGetHeight(int newWidth) _labelWidth = newWidth - st::contactsPadding.left() - st::contactsPadding.right(); _checkbox->resizeToNaturalWidth(_labelWidth); _checkbox->moveToLeft(st::contactsPadding.left(), st::contactsAllAdminsTop); - auto labelHeight = qMax( - _labelChecked.countHeight(_labelWidth), - _labelUnchecked.countHeight(_labelWidth)); + auto labelHeight = std::max(_labelChecked.countHeight(_labelWidth), _labelUnchecked.countHeight(_labelWidth)); return st::contactsAboutTop + labelHeight + st::contactsAboutBottom; } @@ -544,17 +525,18 @@ void EditChatAdminsBoxController::LabeledCheckbox::paintEvent(QPaintEvent *e) { p.fillRect(infoRect, st::contactsAboutBg); auto dividerFillTop = rtlrect(0, infoRect.y(), width(), st::profileDividerTop.height(), width()); st::profileDividerTop.fill(p, dividerFillTop); - auto dividerFillBottom = rtlrect(0, infoRect.y() + infoRect.height() - st::profileDividerBottom.height(), width(), st::profileDividerBottom.height(), width()); + auto dividerFillBottom = rtlrect(0, infoRect.y() + infoRect.height() - st::profileDividerBottom.height(), width(), + st::profileDividerBottom.height(), width()); st::profileDividerBottom.fill(p, dividerFillBottom); p.setPen(st::contactsAboutFg); - (checked() ? _labelChecked : _labelUnchecked).draw(p, st::contactsPadding.left(), st::contactsAboutTop, _labelWidth); + (checked() ? _labelChecked : _labelUnchecked) + .draw(p, st::contactsPadding.left(), st::contactsAboutTop, _labelWidth); } -EditChatAdminsBoxController::EditChatAdminsBoxController(not_null chat) -: PeerListController() -, _chat(chat) { -} +EditChatAdminsBoxController::EditChatAdminsBoxController(not_null chat) + : PeerListController() + , _chat(chat) {} bool EditChatAdminsBoxController::allAreAdmins() const { return _allAdmins->checked(); @@ -570,16 +552,16 @@ void EditChatAdminsBoxController::prepare() { rebuildRows(); if (!delegate()->peerListFullRowsCount()) { Auth().api().requestFullPeer(_chat); - _adminsUpdatedSubscription = subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler( - Notify::PeerUpdate::Flag::AdminsChanged, [this]( - const Notify::PeerUpdate &update) { - if (update.peer == _chat) { - rebuildRows(); - if (delegate()->peerListFullRowsCount()) { - unsubscribe(_adminsUpdatedSubscription); - } - } - })); + _adminsUpdatedSubscription = subscribe( + Notify::PeerUpdated(), Notify::PeerUpdatedHandler(Notify::PeerUpdate::Flag::AdminsChanged, + [this](const Notify::PeerUpdate &update) { + if (update.peer == _chat) { + rebuildRows(); + if (delegate()->peerListFullRowsCount()) { + unsubscribe(_adminsUpdatedSubscription); + } + } + })); } subscribe(_allAdmins->checkedChanged, [this](bool checked) { @@ -598,7 +580,8 @@ void EditChatAdminsBoxController::prepare() { void EditChatAdminsBoxController::createAllAdminsCheckbox() { auto labelWidth = st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.right(); - auto checkbox = object_ptr(nullptr, lang(lng_chat_all_members_admins), !_chat->adminsEnabled(), st::defaultBoxCheckbox); + auto checkbox = object_ptr(nullptr, lang(lng_chat_all_members_admins), !_chat->adminsEnabled(), + st::defaultBoxCheckbox); checkbox->setLabelText(true, st::defaultTextStyle, lang(lng_chat_about_all_admins), _defaultOptions, labelWidth); checkbox->setLabelText(false, st::defaultTextStyle, lang(lng_chat_about_admins), _defaultOptions, labelWidth); _allAdmins = checkbox; @@ -612,14 +595,14 @@ void EditChatAdminsBoxController::rebuildRows() { auto allAdmins = allAreAdmins(); - auto admins = std::vector>(); + auto admins = std::vector>(); auto others = admins; admins.reserve(allAdmins ? _chat->participants.size() : _chat->admins.size()); others.reserve(_chat->participants.size()); for (auto i = _chat->participants.cbegin(), e = _chat->participants.cend(); i != e; ++i) { if (i.key()->id == peerFromUser(_chat->creator)) continue; - if (_chat->admins.contains(i.key())) { + if (_chat->admins.find(i.key()) != _chat->admins.end()) { admins.push_back(i.key()); } else { others.push_back(i.key()); @@ -633,13 +616,11 @@ void EditChatAdminsBoxController::rebuildRows() { admins.insert(admins.end(), others.begin(), others.end()); others.clear(); } - auto sortByName = [](auto a, auto b) { - return (a->name.compare(b->name, Qt::CaseInsensitive) < 0); - }; + auto sortByName = [](auto a, auto b) { return (a->name.compare(b->name, Qt::CaseInsensitive) < 0); }; std::sort(admins.begin(), admins.end(), sortByName); std::sort(others.begin(), others.end(), sortByName); - auto addOne = [this](not_null user) { + auto addOne = [this](not_null user) { if (auto row = createRow(user)) { delegate()->peerListAppendRow(std::move(row)); } @@ -655,7 +636,7 @@ void EditChatAdminsBoxController::rebuildRows() { delegate()->peerListRefreshRows(); } -std::unique_ptr EditChatAdminsBoxController::createRow(not_null user) { +std::unique_ptr EditChatAdminsBoxController::createRow(not_null user) { auto result = std::make_unique(user); if (allAreAdmins() || user->id == peerFromUser(_chat->creator)) { result->setDisabledState(PeerListRow::State::DisabledChecked); @@ -663,23 +644,23 @@ std::unique_ptr EditChatAdminsBoxController::createRow(not_null row) { +void EditChatAdminsBoxController::rowClicked(not_null row) { delegate()->peerListSetRowChecked(row, !row->checked()); } -void EditChatAdminsBoxController::Start(not_null chat) { +void EditChatAdminsBoxController::Start(not_null chat) { auto controller = std::make_unique(chat); - auto initBox = [chat, controller = controller.get()](not_null box) { + auto initBox = [chat, controller = controller.get()](not_null box) { box->addButton(langFactory(lng_settings_save), [box, chat, controller] { auto rows = box->peerListCollectSelectedRows(); - auto users = std::vector>(); + auto users = std::vector>(); for (auto peer : rows) { auto user = peer->asUser(); Assert(user != nullptr); Assert(!user->isSelf()); users.push_back(peer->asUser()); } - Auth().api().editChatAdmins(chat, !controller->allAreAdmins(), { users.cbegin(), users.cend() }); + Auth().api().editChatAdmins(chat, !controller->allAreAdmins(), {users.cbegin(), users.cend()}); box->closeBox(); }); box->addButton(langFactory(lng_cancel), [box] { box->closeBox(); }); @@ -687,21 +668,18 @@ void EditChatAdminsBoxController::Start(not_null chat) { Ui::show(Box(std::move(controller), std::move(initBox))); } -void AddBotToGroupBoxController::Start(not_null bot) { - auto initBox = [bot](not_null box) { +void AddBotToGroupBoxController::Start(not_null bot) { + auto initBox = [](not_null box) { box->addButton(langFactory(lng_cancel), [box] { box->closeBox(); }); }; Ui::show(Box(std::make_unique(bot), std::move(initBox))); } -AddBotToGroupBoxController::AddBotToGroupBoxController(not_null bot) -: ChatsListBoxController(SharingBotGame(bot) - ? std::make_unique() - : nullptr) -, _bot(bot) { -} +AddBotToGroupBoxController::AddBotToGroupBoxController(not_null bot) + : ChatsListBoxController(SharingBotGame(bot) ? std::make_unique() : nullptr) + , _bot(bot) {} -void AddBotToGroupBoxController::rowClicked(not_null row) { +void AddBotToGroupBoxController::rowClicked(not_null row) { if (sharingBotGame()) { shareBotGame(row->peer()); } else { @@ -709,7 +687,7 @@ void AddBotToGroupBoxController::rowClicked(not_null row) { } } -void AddBotToGroupBoxController::shareBotGame(not_null chat) { +void AddBotToGroupBoxController::shareBotGame(not_null chat) { auto weak = base::make_weak_unique(this); auto send = [weak, bot = _bot, chat] { if (!weak) { @@ -717,18 +695,11 @@ void AddBotToGroupBoxController::shareBotGame(not_null chat) { } auto history = App::historyLoaded(chat); auto afterRequestId = history ? history->sendRequestId : 0; - auto randomId = rand_value(); + auto randomId = rand_value(); auto gameShortName = bot->botInfo->shareGameShortName; - auto inputGame = MTP_inputGameShortName( - bot->inputUser, - MTP_string(gameShortName)); - auto request = MTPmessages_SendMedia( - MTP_flags(0), - chat->input, - MTP_int(0), - MTP_inputMediaGame(inputGame), - MTP_long(randomId), - MTPnullMarkup); + auto inputGame = MTP_inputGameShortName(bot->inputUser, MTP_string(gameShortName)); + auto request = MTPmessages_SendMedia(MTP_flags(0), chat->input, MTP_int(0), MTP_inputMediaGame(inputGame), + MTP_long(randomId), MTPnullMarkup); auto done = App::main()->rpcDone(&MainWidget::sentUpdatesReceived); auto fail = App::main()->rpcFail(&MainWidget::sendMessageFail); auto requestId = MTP::send(request, done, fail, 0, 0, afterRequestId); @@ -747,7 +718,7 @@ void AddBotToGroupBoxController::shareBotGame(not_null chat) { Ui::show(Box(confirmText(), send), KeepOtherLayers); } -void AddBotToGroupBoxController::addBotToGroup(not_null chat) { +void AddBotToGroupBoxController::addBotToGroup(not_null chat) { if (auto megagroup = chat->asMegagroup()) { if (!megagroup->canAddMembers()) { Ui::show(Box(lang(lng_error_cant_add_member)), KeepOtherLayers); @@ -761,26 +732,16 @@ void AddBotToGroupBoxController::addBotToGroup(not_null chat) { } if (auto &info = bot->botInfo) { if (!info->startGroupToken.isEmpty()) { - auto request = MTPmessages_StartBot( - bot->inputUser, - chat->input, - MTP_long(rand_value()), - MTP_string(info->startGroupToken)); - auto done = App::main()->rpcDone( - &MainWidget::sentUpdatesReceived); - auto fail = App::main()->rpcFail( - &MainWidget::addParticipantFail, - { bot, chat }); + auto request = MTPmessages_StartBot(bot->inputUser, chat->input, MTP_long(rand_value()), + MTP_string(info->startGroupToken)); + auto done = App::main()->rpcDone(&MainWidget::sentUpdatesReceived); + auto fail = App::main()->rpcFail(&MainWidget::addParticipantFail, {bot, chat}); MTP::send(request, done, fail); } else { - App::main()->addParticipants( - chat, - { 1, bot }); + App::main()->addParticipants(chat, {1, bot}); } } else { - App::main()->addParticipants( - chat, - { 1, bot }); + App::main()->addParticipants(chat, {1, bot}); } Ui::hideLayer(); Ui::showPeerHistory(chat, ShowAtUnreadMsgId); @@ -789,14 +750,14 @@ void AddBotToGroupBoxController::addBotToGroup(not_null chat) { Ui::show(Box(confirmText, send), KeepOtherLayers); } -std::unique_ptr AddBotToGroupBoxController::createRow(not_null history) { +std::unique_ptr AddBotToGroupBoxController::createRow(not_null history) { if (!needToCreateRow(history->peer)) { return nullptr; } return std::make_unique(history); } -bool AddBotToGroupBoxController::needToCreateRow(not_null peer) const { +bool AddBotToGroupBoxController::needToCreateRow(not_null peer) const { if (sharingBotGame()) { if (!peer->canWrite()) { return false; @@ -818,7 +779,7 @@ bool AddBotToGroupBoxController::needToCreateRow(not_null peer) const return false; } -bool AddBotToGroupBoxController::SharingBotGame(not_null bot) { +bool AddBotToGroupBoxController::SharingBotGame(not_null bot) { auto &info = bot->botInfo; return (info && !info->shareGameShortName.isEmpty()); } @@ -828,15 +789,14 @@ bool AddBotToGroupBoxController::sharingBotGame() const { } QString AddBotToGroupBoxController::emptyBoxText() const { - return lang(Auth().data().allChatsLoaded().value() - ? (sharingBotGame() ? lng_bot_no_chats : lng_bot_no_groups) - : lng_contacts_loading); + return lang(Auth().data().allChatsLoaded().value() ? (sharingBotGame() ? lng_bot_no_chats : lng_bot_no_groups) : + lng_contacts_loading); } QString AddBotToGroupBoxController::noResultsText() const { - return lang(Auth().data().allChatsLoaded().value() - ? (sharingBotGame() ? lng_bot_chats_not_found : lng_bot_groups_not_found) - : lng_contacts_loading); + return lang(Auth().data().allChatsLoaded().value() ? + (sharingBotGame() ? lng_bot_chats_not_found : lng_bot_groups_not_found) : + lng_contacts_loading); } void AddBotToGroupBoxController::updateLabels() { @@ -844,9 +804,7 @@ void AddBotToGroupBoxController::updateLabels() { } void AddBotToGroupBoxController::prepareViewHook() { - delegate()->peerListSetTitle(langFactory(sharingBotGame() - ? lng_bot_choose_chat - : lng_bot_choose_group)); + delegate()->peerListSetTitle(langFactory(sharingBotGame() ? lng_bot_choose_chat : lng_bot_choose_group)); updateLabels(); subscribe(Auth().data().allChatsLoaded(), [this](bool) { updateLabels(); }); } diff --git a/Telegram/SourceFiles/boxes/peer_list_controllers.h b/Telegram/SourceFiles/boxes/peer_list_controllers.h index de0952580..0d5deb500 100644 --- a/Telegram/SourceFiles/boxes/peer_list_controllers.h +++ b/Telegram/SourceFiles/boxes/peer_list_controllers.h @@ -1,42 +1,45 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once -#include "boxes/peer_list_box.h" #include "base/flat_set.h" #include "base/weak_unique_ptr.h" +#include "boxes/peer_list_box.h" +#include "history/history.h" // Not used for now. // -//class MembersAddButton : public Ui::RippleButton { -//public: +// class MembersAddButton : public Ui::RippleButton { +// public: // MembersAddButton(QWidget *parent, const style::TwoIconButton &st); // -//protected: +// protected: // void paintEvent(QPaintEvent *e) override; // // QImage prepareRippleMask() const override; // QPoint prepareRippleStartPosition() const override; // -//private: +// private: // const style::TwoIconButton &_st; // //}; @@ -57,7 +60,6 @@ class PeerListRowWithLink : public PeerListRow { QString _action; int _actionWidth = 0; - }; class PeerListGlobalSearchController : public PeerListSearchController, private MTP::Sender { @@ -80,151 +82,138 @@ class PeerListGlobalSearchController : public PeerListSearchController, private mtpRequestId _requestId = 0; std::map _cache; std::map _queries; - }; class ChatsListBoxController : public PeerListController, protected base::Subscriber { public: - ChatsListBoxController(std::unique_ptr searchController = std::make_unique()); + ChatsListBoxController(std::unique_ptr searchController = + std::make_unique()); void prepare() override final; - std::unique_ptr createSearchRow(not_null peer) override final; + std::unique_ptr createSearchRow(not_null peer) override final; protected: class Row : public PeerListRow { public: - Row(not_null history) : PeerListRow(history->peer), _history(history) { - } - not_null history() const { + Row(not_null history) + : PeerListRow(history->peer) + , _history(history) {} + not_null history() const { return _history; } private: - not_null _history; - + not_null _history; }; - virtual std::unique_ptr createRow(not_null history) = 0; + virtual std::unique_ptr createRow(not_null history) = 0; virtual void prepareViewHook() = 0; - virtual void updateRowHook(not_null row) { - } + virtual void updateRowHook(not_null row) {} virtual QString emptyBoxText() const; private: void rebuildRows(); void checkForEmptyRows(); - bool appendRow(not_null history); - + bool appendRow(not_null history); }; class ContactsBoxController : public PeerListController, protected base::Subscriber { public: - ContactsBoxController(std::unique_ptr searchController = std::make_unique()); + ContactsBoxController(std::unique_ptr searchController = + std::make_unique()); void prepare() override final; - std::unique_ptr createSearchRow(not_null peer) override final; - void rowClicked(not_null row) override; + std::unique_ptr createSearchRow(not_null peer) override final; + void rowClicked(not_null row) override; protected: - virtual std::unique_ptr createRow(not_null user); - virtual void prepareViewHook() { - } - virtual void updateRowHook(not_null row) { - } + virtual std::unique_ptr createRow(not_null user); + virtual void prepareViewHook() {} + virtual void updateRowHook(not_null row) {} private: void rebuildRows(); void checkForEmptyRows(); - bool appendRow(not_null user); - + bool appendRow(not_null user); }; class EditChatAdminsBoxController : public PeerListController, private base::Subscriber { public: - static void Start(not_null chat); + static void Start(not_null chat); - EditChatAdminsBoxController(not_null chat); + EditChatAdminsBoxController(not_null chat); bool allAreAdmins() const; void prepare() override; - void rowClicked(not_null row) override; + void rowClicked(not_null row) override; private: void createAllAdminsCheckbox(); void rebuildRows(); - std::unique_ptr createRow(not_null user); + std::unique_ptr createRow(not_null user); - not_null _chat; + not_null _chat; int _adminsUpdatedSubscription = 0; class LabeledCheckbox; QPointer _allAdmins; - }; class AddParticipantsBoxController : public ContactsBoxController { public: - static void Start(not_null chat); - static void Start(not_null channel); - static void Start( - not_null channel, - base::flat_set> &&alreadyIn); + static void Start(not_null chat); + static void Start(not_null channel); + static void Start(not_null channel, base::flat_set> &&alreadyIn); AddParticipantsBoxController(PeerData *peer); - AddParticipantsBoxController( - not_null channel, - base::flat_set> &&alreadyIn); + AddParticipantsBoxController(not_null channel, base::flat_set> &&alreadyIn); using ContactsBoxController::ContactsBoxController; - void rowClicked(not_null row) override; - void itemDeselectedHook(not_null peer) override; + void rowClicked(not_null row) override; + void itemDeselectedHook(not_null peer) override; protected: void prepareViewHook() override; - std::unique_ptr createRow(not_null user) override; + std::unique_ptr createRow(not_null user) override; private: - static void Start( - not_null channel, - base::flat_set> &&alreadyIn, - bool justCreated); + static void Start(not_null channel, base::flat_set> &&alreadyIn, + bool justCreated); int alreadyInCount() const; - bool isAlreadyIn(not_null user) const; + bool isAlreadyIn(not_null user) const; int fullCount() const; void updateTitle(); PeerData *_peer = nullptr; - base::flat_set> _alreadyIn; - + base::flat_set> _alreadyIn; }; class AddBotToGroupBoxController : public ChatsListBoxController, public base::enable_weak_from_this { public: - static void Start(not_null bot); + static void Start(not_null bot); - AddBotToGroupBoxController(not_null bot); + AddBotToGroupBoxController(not_null bot); - void rowClicked(not_null row) override; + void rowClicked(not_null row) override; protected: - std::unique_ptr createRow(not_null history) override; + std::unique_ptr createRow(not_null history) override; void prepareViewHook() override; QString emptyBoxText() const override; private: - static bool SharingBotGame(not_null bot); + static bool SharingBotGame(not_null bot); - bool needToCreateRow(not_null peer) const; + bool needToCreateRow(not_null peer) const; bool sharingBotGame() const; QString noResultsText() const; QString descriptionText() const; void updateLabels(); - void shareBotGame(not_null chat); - void addBotToGroup(not_null chat); - - not_null _bot; + void shareBotGame(not_null chat); + void addBotToGroup(not_null chat); + not_null _bot; }; diff --git a/Telegram/SourceFiles/boxes/photo_crop_box.cpp b/Telegram/SourceFiles/boxes/photo_crop_box.cpp index 5c4bb2c89..2f25d8d6b 100644 --- a/Telegram/SourceFiles/boxes/photo_crop_box.cpp +++ b/Telegram/SourceFiles/boxes/photo_crop_box.cpp @@ -1,41 +1,43 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/photo_crop_box.h" #include "lang/lang_keys.h" -#include "messenger.h" #include "mainwidget.h" +#include "messenger.h" #include "storage/file_upload.h" -#include "ui/widgets/buttons.h" #include "styles/style_boxes.h" +#include "ui/widgets/buttons.h" -PhotoCropBox::PhotoCropBox(QWidget*, const QImage &img, const PeerId &peer) -: _img(img) -, _peerId(peer) { +PhotoCropBox::PhotoCropBox(QWidget *, const QImage &img, const PeerId &peer) + : _img(img) + , _peerId(peer) { init(img, nullptr); } -PhotoCropBox::PhotoCropBox(QWidget*, const QImage &img, PeerData *peer) -: _img(img) -, _peerId(peer->id) { +PhotoCropBox::PhotoCropBox(QWidget *, const QImage &img, PeerData *peer) + : _img(img) + , _peerId(peer->id) { init(img, peer); } @@ -53,11 +55,12 @@ void PhotoCropBox::prepare() { addButton(langFactory(lng_settings_save), [this] { sendPhoto(); }); addButton(langFactory(lng_cancel), [this] { closeBox(); }); if (peerToBareInt(_peerId)) { - connect(this, SIGNAL(ready(const QImage&)), this, SLOT(onReady(const QImage&))); + connect(this, SIGNAL(ready(const QImage &)), this, SLOT(onReady(const QImage &))); } - int32 s = st::boxWideWidth - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(); - _thumb = App::pixmapFromImageInPlace(_img.scaled(s * cIntRetinaFactor(), s * cIntRetinaFactor(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); + qint32 s = st::boxWideWidth - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(); + _thumb = App::pixmapFromImageInPlace( + _img.scaled(s * cIntRetinaFactor(), s * cIntRetinaFactor(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); _thumb.setDevicePixelRatio(cRetinaFactor()); _mask = QImage(_thumb.size(), QImage::Format_ARGB32_Premultiplied); _mask.setDevicePixelRatio(cRetinaFactor()); @@ -77,7 +80,8 @@ void PhotoCropBox::prepare() { _thumby = st::boxPhotoPadding.top(); setMouseTracking(true); - setDimensions(st::boxWideWidth, st::boxPhotoPadding.top() + _thumbh + st::boxPhotoPadding.bottom() + st::boxTextFont->height + st::cropSkip); + setDimensions(st::boxWideWidth, st::boxPhotoPadding.top() + _thumbh + st::boxPhotoPadding.bottom() + + st::boxTextFont->height + st::cropSkip); } void PhotoCropBox::mousePressEvent(QMouseEvent *e) { @@ -94,7 +98,7 @@ void PhotoCropBox::mousePressEvent(QMouseEvent *e) { int PhotoCropBox::mouseState(QPoint p) { p -= QPoint(_thumbx, _thumby); - int32 delta = st::cropPointSize, mdelta(-delta / 2); + qint32 delta = st::cropPointSize, mdelta(-delta / 2); if (QRect(_cropx + mdelta, _cropy + mdelta, delta, delta).contains(p)) { return 1; } else if (QRect(_cropx + _cropw + mdelta, _cropy + mdelta, delta, delta).contains(p)) { @@ -122,7 +126,7 @@ void PhotoCropBox::mouseMoveEvent(QMouseEvent *e) { } if (_downState) { if (_downState == 1) { - int32 dx = e->pos().x() - _fromposx, dy = e->pos().y() - _fromposy, d = (dx < dy) ? dx : dy; + qint32 dx = e->pos().x() - _fromposx, dy = e->pos().y() - _fromposy, d = (dx < dy) ? dx : dy; if (_fromcropx + d < 0) { d = -_fromcropx; } @@ -139,7 +143,7 @@ void PhotoCropBox::mouseMoveEvent(QMouseEvent *e) { update(); } } else if (_downState == 2) { - int32 dx = _fromposx - e->pos().x(), dy = e->pos().y() - _fromposy, d = (dx < dy) ? dx : dy; + qint32 dx = _fromposx - e->pos().x(), dy = e->pos().y() - _fromposy, d = (dx < dy) ? dx : dy; if (_fromcropx + _fromcropw - d > _thumbw) { d = _fromcropx + _fromcropw - _thumbw; } @@ -155,7 +159,7 @@ void PhotoCropBox::mouseMoveEvent(QMouseEvent *e) { update(); } } else if (_downState == 3) { - int32 dx = _fromposx - e->pos().x(), dy = _fromposy - e->pos().y(), d = (dx < dy) ? dx : dy; + qint32 dx = _fromposx - e->pos().x(), dy = _fromposy - e->pos().y(), d = (dx < dy) ? dx : dy; if (_fromcropx + _fromcropw - d > _thumbw) { d = _fromcropx + _fromcropw - _thumbw; } @@ -170,7 +174,7 @@ void PhotoCropBox::mouseMoveEvent(QMouseEvent *e) { update(); } } else if (_downState == 4) { - int32 dx = e->pos().x() - _fromposx, dy = _fromposy - e->pos().y(), d = (dx < dy) ? dx : dy; + qint32 dx = e->pos().x() - _fromposx, dy = _fromposy - e->pos().y(), d = (dx < dy) ? dx : dy; if (_fromcropx + d < 0) { d = -_fromcropx; } @@ -186,7 +190,7 @@ void PhotoCropBox::mouseMoveEvent(QMouseEvent *e) { update(); } } else if (_downState == 5) { - int32 dx = e->pos().x() - _fromposx, dy = e->pos().y() - _fromposy; + qint32 dx = e->pos().x() - _fromposx, dy = e->pos().y() - _fromposy; if (_fromcropx + dx < 0) { dx = -_fromcropx; } else if (_fromcropx + _fromcropw + dx > _thumbw) { @@ -204,7 +208,7 @@ void PhotoCropBox::mouseMoveEvent(QMouseEvent *e) { } } } - int32 cursorState = _downState ? _downState : mouseState(e->pos()); + qint32 cursorState = _downState ? _downState : mouseState(e->pos()); QCursor cur(style::cur_default); if (cursorState == 1 || cursorState == 3) { cur = style::cur_sizefdiag; @@ -231,7 +235,9 @@ void PhotoCropBox::paintEvent(QPaintEvent *e) { p.setFont(st::boxTextFont); p.setPen(st::boxPhotoTextFg); - p.drawText(QRect(st::boxPhotoPadding.left(), st::boxPhotoPadding.top() + _thumbh + st::boxPhotoPadding.bottom(), width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(), st::boxTextFont->height), _title, style::al_top); + p.drawText(QRect(st::boxPhotoPadding.left(), st::boxPhotoPadding.top() + _thumbh + st::boxPhotoPadding.bottom(), + width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(), st::boxTextFont->height), + _title, style::al_top); p.translate(_thumbx, _thumby); p.drawPixmap(0, 0, _thumb); @@ -260,8 +266,8 @@ void PhotoCropBox::sendPhoto() { if (_img.width() < _thumb.width()) { from = _thumb.toImage(); } - float64 x = float64(_cropx) / _thumbw, y = float64(_cropy) / _thumbh, w = float64(_cropw) / _thumbw; - int32 ix = int32(x * from.width()), iy = int32(y * from.height()), iw = int32(w * from.width()); + double x = double(_cropx) / _thumbw, y = double(_cropy) / _thumbh, w = double(_cropw) / _thumbw; + qint32 ix = qint32(x * from.width()), iy = qint32(y * from.height()), iw = qint32(w * from.width()); if (ix < 0) { ix = 0; } @@ -274,7 +280,7 @@ void PhotoCropBox::sendPhoto() { if (iy + iw > from.height()) { iw = from.height() - iy; } - int32 offset = ix * from.depth() / 8 + iy * from.bytesPerLine(); + qint32 offset = ix * from.depth() / 8 + iy * from.bytesPerLine(); QImage cropped(from.constBits() + offset, iw, iw, from.bytesPerLine(), from.format()), tosend; if (from.format() == QImage::Format_Indexed8) { cropped.setColorCount(from.colorCount()); diff --git a/Telegram/SourceFiles/boxes/photo_crop_box.h b/Telegram/SourceFiles/boxes/photo_crop_box.h index 69a36f504..cc6a6fef4 100644 --- a/Telegram/SourceFiles/boxes/photo_crop_box.h +++ b/Telegram/SourceFiles/boxes/photo_crop_box.h @@ -1,35 +1,39 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "boxes/abstract_box.h" +#include "structs.h" // temporarily, need PeerId. + class PhotoCropBox : public BoxContent { Q_OBJECT public: - PhotoCropBox(QWidget*, const QImage &img, const PeerId &peer); - PhotoCropBox(QWidget*, const QImage &img, PeerData *peer); + PhotoCropBox(QWidget *, const QImage &img, const PeerId &peer); + PhotoCropBox(QWidget *, const QImage &img, PeerData *peer); - int32 mouseState(QPoint p); + qint32 mouseState(QPoint p); signals: void ready(const QImage &tosend); @@ -51,13 +55,12 @@ private slots: void sendPhoto(); QString _title; - int32 _downState = 0; - int32 _thumbx, _thumby, _thumbw, _thumbh; - int32 _cropx, _cropy, _cropw; - int32 _fromposx, _fromposy, _fromcropx, _fromcropy, _fromcropw; + qint32 _downState = 0; + qint32 _thumbx, _thumby, _thumbw, _thumbh; + qint32 _cropx, _cropy, _cropw; + qint32 _fromposx, _fromposy, _fromcropx, _fromcropy, _fromcropw; QImage _img; QPixmap _thumb; QImage _mask, _fade; PeerId _peerId; - }; diff --git a/Telegram/SourceFiles/boxes/rate_call_box.cpp b/Telegram/SourceFiles/boxes/rate_call_box.cpp index f562b4d7b..17a003467 100644 --- a/Telegram/SourceFiles/boxes/rate_call_box.cpp +++ b/Telegram/SourceFiles/boxes/rate_call_box.cpp @@ -1,34 +1,36 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/rate_call_box.h" +#include "boxes/confirm_box.h" #include "lang/lang_keys.h" +#include "mainwidget.h" +#include "mainwindow.h" #include "styles/style_boxes.h" #include "styles/style_calls.h" -#include "boxes/confirm_box.h" -#include "ui/widgets/labels.h" #include "ui/widgets/buttons.h" #include "ui/widgets/input_fields.h" -#include "mainwindow.h" -#include "mainwidget.h" +#include "ui/widgets/labels.h" namespace { @@ -36,10 +38,9 @@ constexpr auto kMaxRating = 5; } // namespace -RateCallBox::RateCallBox(QWidget*, uint64 callId, uint64 callAccessHash) -: _callId(callId) -, _callAccessHash(callAccessHash) { -} +RateCallBox::RateCallBox(QWidget *, quint64 callId, quint64 callAccessHash) + : _callId(callId) + , _callAccessHash(callAccessHash) {} void RateCallBox::prepare() { setTitle(langFactory(lng_call_rate_label)); @@ -88,7 +89,8 @@ void RateCallBox::ratingChanged(int value) { _comment->show(); _comment->setCtrlEnterSubmit(Ui::CtrlEnterSubmit::Both); _comment->setMaxLength(MaxPhotoCaption); - _comment->resize(width() - (st::callRatingPadding.left() + st::callRatingPadding.right()), _comment->height()); + _comment->resize(width() - (st::callRatingPadding.left() + st::callRatingPadding.right()), + _comment->height()); updateMaxHeight(); connect(_comment, SIGNAL(resized()), this, SLOT(onCommentResized())); @@ -121,14 +123,19 @@ void RateCallBox::onSend() { return; } auto comment = _comment ? _comment->getLastText().trimmed() : QString(); - _requestId = request(MTPphone_SetCallRating(MTP_inputPhoneCall(MTP_long(_callId), MTP_long(_callAccessHash)), MTP_int(_rating), MTP_string(comment))).done([this](const MTPUpdates &updates) { - App::main()->sentUpdatesReceived(updates); - closeBox(); - }).fail([this](const RPCError &error) { closeBox(); }).send(); + _requestId = request(MTPphone_SetCallRating(MTP_inputPhoneCall(MTP_long(_callId), MTP_long(_callAccessHash)), + MTP_int(_rating), MTP_string(comment))) + .done([this](const MTPUpdates &updates) { + App::main()->sentUpdatesReceived(updates); + closeBox(); + }) + .fail([this](const RPCError &error) { closeBox(); }) + .send(); } void RateCallBox::updateMaxHeight() { - auto newHeight = st::callRatingPadding.top() + st::callRatingStarTop + _stars.back()->heightNoMargins() + st::callRatingPadding.bottom(); + auto newHeight = st::callRatingPadding.top() + st::callRatingStarTop + _stars.back()->heightNoMargins() + + st::callRatingPadding.bottom(); if (_comment) { newHeight += st::callRatingCommentTop + _comment->height(); } diff --git a/Telegram/SourceFiles/boxes/rate_call_box.h b/Telegram/SourceFiles/boxes/rate_call_box.h index a4270828e..58e1f5b03 100644 --- a/Telegram/SourceFiles/boxes/rate_call_box.h +++ b/Telegram/SourceFiles/boxes/rate_call_box.h @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "boxes/abstract_box.h" @@ -33,7 +35,7 @@ class RateCallBox : public BoxContent, private MTP::Sender { Q_OBJECT public: - RateCallBox(QWidget*, uint64 callId, uint64 callAccessHash); + RateCallBox(QWidget *, quint64 callId, quint64 callAccessHash); private slots: void onSend(); @@ -52,13 +54,12 @@ private slots: void updateMaxHeight(); void ratingChanged(int value); - uint64 _callId = 0; - uint64 _callAccessHash = 0; + quint64 _callId = 0; + quint64 _callAccessHash = 0; int _rating = 0; std::vector> _stars; - object_ptr _comment = { nullptr }; + object_ptr _comment = {nullptr}; mtpRequestId _requestId = 0; - }; diff --git a/Telegram/SourceFiles/boxes/report_box.cpp b/Telegram/SourceFiles/boxes/report_box.cpp index 81b0a2cb8..dcb975ddb 100644 --- a/Telegram/SourceFiles/boxes/report_box.cpp +++ b/Telegram/SourceFiles/boxes/report_box.cpp @@ -1,44 +1,49 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/report_box.h" +#include "boxes/confirm_box.h" +#include "facades.h" #include "lang/lang_keys.h" +#include "mainwindow.h" #include "styles/style_boxes.h" #include "styles/style_profile.h" -#include "boxes/confirm_box.h" -#include "ui/widgets/checkbox.h" #include "ui/widgets/buttons.h" +#include "ui/widgets/checkbox.h" #include "ui/widgets/input_fields.h" -#include "mainwindow.h" -ReportBox::ReportBox(QWidget*, PeerData *peer) : _peer(peer) -, _reasonGroup(std::make_shared>(Reason::Spam)) -, _reasonSpam(this, _reasonGroup, Reason::Spam, lang(lng_report_reason_spam), st::defaultBoxCheckbox) -, _reasonViolence(this, _reasonGroup, Reason::Violence, lang(lng_report_reason_violence), st::defaultBoxCheckbox) -, _reasonPornography(this, _reasonGroup, Reason::Pornography, lang(lng_report_reason_pornography), st::defaultBoxCheckbox) -, _reasonOther(this, _reasonGroup, Reason::Other, lang(lng_report_reason_other), st::defaultBoxCheckbox) { -} +ReportBox::ReportBox(QWidget *, PeerData *peer) + : _peer(peer) + , _reasonGroup(std::make_shared>(Reason::Spam)) + , _reasonSpam(this, _reasonGroup, Reason::Spam, lang(lng_report_reason_spam), st::defaultBoxCheckbox) + , _reasonViolence(this, _reasonGroup, Reason::Violence, lang(lng_report_reason_violence), st::defaultBoxCheckbox) + , _reasonPornography(this, _reasonGroup, Reason::Pornography, lang(lng_report_reason_pornography), + st::defaultBoxCheckbox) + , _reasonOther(this, _reasonGroup, Reason::Other, lang(lng_report_reason_other), st::defaultBoxCheckbox) {} void ReportBox::prepare() { - setTitle(langFactory(_peer->isUser() ? lng_report_bot_title : (_peer->isMegagroup() ? lng_report_group_title : lng_report_title))); + setTitle(langFactory(_peer->isUser() ? lng_report_bot_title : + (_peer->isMegagroup() ? lng_report_group_title : lng_report_title))); addButton(langFactory(lng_report_button), [this] { onReport(); }); addButton(langFactory(lng_cancel), [this] { closeBox(); }); @@ -51,13 +56,19 @@ void ReportBox::prepare() { void ReportBox::resizeEvent(QResizeEvent *e) { BoxContent::resizeEvent(e); - _reasonSpam->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), st::boxOptionListPadding.top() + _reasonSpam->getMargins().top()); - _reasonViolence->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), _reasonSpam->bottomNoMargins() + st::boxOptionListSkip); - _reasonPornography->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), _reasonViolence->bottomNoMargins() + st::boxOptionListSkip); - _reasonOther->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), _reasonPornography->bottomNoMargins() + st::boxOptionListSkip); + _reasonSpam->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), + st::boxOptionListPadding.top() + _reasonSpam->getMargins().top()); + _reasonViolence->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), + _reasonSpam->bottomNoMargins() + st::boxOptionListSkip); + _reasonPornography->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), + _reasonViolence->bottomNoMargins() + st::boxOptionListSkip); + _reasonOther->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), + _reasonPornography->bottomNoMargins() + st::boxOptionListSkip); if (_reasonOtherText) { - _reasonOtherText->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left() - st::defaultInputField.textMargins.left(), _reasonOther->bottomNoMargins() + st::newGroupDescriptionPadding.top()); + _reasonOtherText->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left() - + st::defaultInputField.textMargins.left(), + _reasonOther->bottomNoMargins() + st::newGroupDescriptionPadding.top()); } } @@ -68,7 +79,9 @@ void ReportBox::reasonChanged(Reason reason) { _reasonOtherText->show(); _reasonOtherText->setCtrlEnterSubmit(Ui::CtrlEnterSubmit::Both); _reasonOtherText->setMaxLength(MaxPhotoCaption); - _reasonOtherText->resize(width() - (st::boxPadding.left() + st::boxOptionListPadding.left() + st::boxPadding.right()), _reasonOtherText->height()); + _reasonOtherText->resize( + width() - (st::boxPadding.left() + st::boxOptionListPadding.left() + st::boxPadding.right()), + _reasonOtherText->height()); updateMaxHeight(); connect(_reasonOtherText, SIGNAL(resized()), this, SLOT(onReasonResized())); @@ -112,7 +125,8 @@ void ReportBox::onReport() { } Unexpected("Bad reason group value."); }; - _requestId = MTP::send(MTPaccount_ReportPeer(_peer->input, getReason()), rpcDone(&ReportBox::reportDone), rpcFail(&ReportBox::reportFail)); + _requestId = MTP::send(MTPaccount_ReportPeer(_peer->input, getReason()), rpcDone(&ReportBox::reportDone), + rpcFail(&ReportBox::reportFail)); } void ReportBox::reportDone(const MTPBool &result) { @@ -131,9 +145,12 @@ bool ReportBox::reportFail(const RPCError &error) { } void ReportBox::updateMaxHeight() { - auto newHeight = st::boxOptionListPadding.top() + _reasonSpam->getMargins().top() + 4 * _reasonSpam->heightNoMargins() + 3 * st::boxOptionListSkip + _reasonSpam->getMargins().bottom() + st::boxOptionListPadding.bottom(); + auto newHeight = st::boxOptionListPadding.top() + _reasonSpam->getMargins().top() + + 4 * _reasonSpam->heightNoMargins() + 3 * st::boxOptionListSkip + + _reasonSpam->getMargins().bottom() + st::boxOptionListPadding.bottom(); if (_reasonOtherText) { - newHeight += st::newGroupDescriptionPadding.top() + _reasonOtherText->height() + st::newGroupDescriptionPadding.bottom(); + newHeight += + st::newGroupDescriptionPadding.top() + _reasonOtherText->height() + st::newGroupDescriptionPadding.bottom(); } setDimensions(st::boxWidth, newHeight); } diff --git a/Telegram/SourceFiles/boxes/report_box.h b/Telegram/SourceFiles/boxes/report_box.h index 9d588179a..33fc41238 100644 --- a/Telegram/SourceFiles/boxes/report_box.h +++ b/Telegram/SourceFiles/boxes/report_box.h @@ -1,32 +1,32 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "boxes/abstract_box.h" namespace Ui { -template -class RadioenumGroup; -template -class Radioenum; +template class RadioenumGroup; +template class Radioenum; class InputArea; } // namespace Ui @@ -34,7 +34,7 @@ class ReportBox : public BoxContent, public RPCSender { Q_OBJECT public: - ReportBox(QWidget*, PeerData *peer); + ReportBox(QWidget *, PeerData *peer); private slots: void onReport(); @@ -69,8 +69,7 @@ private slots: object_ptr> _reasonViolence; object_ptr> _reasonPornography; object_ptr> _reasonOther; - object_ptr _reasonOtherText = { nullptr }; + object_ptr _reasonOtherText = {nullptr}; mtpRequestId _requestId = 0; - }; diff --git a/Telegram/SourceFiles/boxes/self_destruction_box.cpp b/Telegram/SourceFiles/boxes/self_destruction_box.cpp index ebd03b616..ba085036d 100644 --- a/Telegram/SourceFiles/boxes/self_destruction_box.cpp +++ b/Telegram/SourceFiles/boxes/self_destruction_box.cpp @@ -1,81 +1,90 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/self_destruction_box.h" #include "lang/lang_keys.h" +#include "styles/style_boxes.h" #include "ui/widgets/checkbox.h" #include "ui/widgets/labels.h" -#include "styles/style_boxes.h" void SelfDestructionBox::prepare() { setTitle(langFactory(lng_self_destruct_title)); - _ttlValues = { 30, 90, 180, 365 }; + _ttlValues = {30, 90, 180, 365}; - auto fake = object_ptr(this, lang(lng_self_destruct_description), Ui::FlatLabel::InitType::Simple, st::boxLabel); - auto boxHeight = st::boxOptionListPadding.top() - + fake->height() + st::boxMediumSkip - + _ttlValues.size() * (st::defaultRadio.diameter + st::boxOptionListSkip) - st::boxOptionListSkip - + st::boxOptionListPadding.bottom() + st::boxPadding.bottom(); + auto fake = object_ptr(this, lang(lng_self_destruct_description), Ui::FlatLabel::InitType::Simple, + st::boxLabel); + auto boxHeight = st::boxOptionListPadding.top() + fake->height() + st::boxMediumSkip + + _ttlValues.size() * (st::defaultRadio.diameter + st::boxOptionListSkip) - st::boxOptionListSkip + + st::boxOptionListPadding.bottom() + st::boxPadding.bottom(); fake.destroy(); setDimensions(st::boxWidth, boxHeight); - auto loading = object_ptr(this, lang(lng_contacts_loading), Ui::FlatLabel::InitType::Simple, st::membersAbout); + auto loading = + object_ptr(this, lang(lng_contacts_loading), Ui::FlatLabel::InitType::Simple, st::membersAbout); loading->moveToLeft((st::boxWidth - loading->width()) / 2, boxHeight / 3); addButton(langFactory(lng_cancel), [this] { closeBox(); }); - request(MTPaccount_GetAccountTTL()).done([this, loading = std::move(loading)](const MTPAccountDaysTTL &result) mutable { - Expects(result.type() == mtpc_accountDaysTTL); - Expects(!_ttlValues.empty()); + request(MTPaccount_GetAccountTTL()) + .done([this, loading = std::move(loading)](const MTPAccountDaysTTL &result) mutable { + Expects(result.type() == mtpc_accountDaysTTL); + Expects(!_ttlValues.empty()); - loading.destroy(); - auto y = st::boxOptionListPadding.top(); - _description.create(this, lang(lng_self_destruct_description), Ui::FlatLabel::InitType::Simple, st::boxLabel); - _description->moveToLeft(st::boxPadding.left(), y); - y += _description->height() + st::boxMediumSkip; + loading.destroy(); + auto y = st::boxOptionListPadding.top(); + _description.create(this, lang(lng_self_destruct_description), Ui::FlatLabel::InitType::Simple, + st::boxLabel); + _description->moveToLeft(st::boxPadding.left(), y); + y += _description->height() + st::boxMediumSkip; - auto current = result.c_accountDaysTTL().vdays.v; - auto currentAdjusted = _ttlValues[0]; - for (auto days : _ttlValues) { - if (qAbs(current - days) < qAbs(current - currentAdjusted)) { - currentAdjusted = days; - } - } - auto group = std::make_shared(currentAdjusted); - auto count = int(_ttlValues.size()); - _options.reserve(count); - for (auto days : _ttlValues) { - _options.emplace_back(this, group, days, (days > 364) ? lng_self_destruct_years(lt_count, days / 365) : lng_self_destruct_months(lt_count, qMax(days / 30, 1)), st::langsButton); - _options.back()->moveToLeft(st::boxPadding.left(), y); - y += _options.back()->heightNoMargins() + st::boxOptionListSkip; - } - showChildren(); + auto current = result.c_accountDaysTTL().vdays.v; + auto currentAdjusted = _ttlValues[0]; + for (auto days : _ttlValues) { + if (qAbs(current - days) < qAbs(current - currentAdjusted)) { + currentAdjusted = days; + } + } + auto group = std::make_shared(currentAdjusted); + auto count = int(_ttlValues.size()); + _options.reserve(count); + for (auto days : _ttlValues) { + _options.emplace_back(this, group, days, + (days > 364) ? lng_self_destruct_years(lt_count, days / 365) : + lng_self_destruct_months(lt_count, std::max(days / 30, 1)), + st::langsButton); + _options.back()->moveToLeft(st::boxPadding.left(), y); + y += _options.back()->heightNoMargins() + st::boxOptionListSkip; + } + showChildren(); - clearButtons(); - addButton(langFactory(lng_settings_save), [this, group] { - MTP::send(MTPaccount_SetAccountTTL(MTP_accountDaysTTL(MTP_int(group->value())))); - closeBox(); - }); - addButton(langFactory(lng_cancel), [this] { closeBox(); }); - }).send(); + clearButtons(); + addButton(langFactory(lng_settings_save), [this, group] { + MTP::send(MTPaccount_SetAccountTTL(MTP_accountDaysTTL(MTP_int(group->value())))); + closeBox(); + }); + addButton(langFactory(lng_cancel), [this] { closeBox(); }); + }) + .send(); } diff --git a/Telegram/SourceFiles/boxes/self_destruction_box.h b/Telegram/SourceFiles/boxes/self_destruction_box.h index 8b4740164..12bd3c8eb 100644 --- a/Telegram/SourceFiles/boxes/self_destruction_box.h +++ b/Telegram/SourceFiles/boxes/self_destruction_box.h @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "boxes/abstract_box.h" @@ -33,16 +35,14 @@ class SelfDestructionBox : public BoxContent, private MTP::Sender { Q_OBJECT public: - SelfDestructionBox(QWidget*) { - } + SelfDestructionBox(QWidget*) {} protected: void prepare() override; private: std::vector _ttlValues; - object_ptr _description = { nullptr }; + object_ptr _description = {nullptr}; std::shared_ptr _ttlGroup; std::vector> _options; - }; diff --git a/Telegram/SourceFiles/boxes/send_files_box.cpp b/Telegram/SourceFiles/boxes/send_files_box.cpp index 6f1068da2..d307476ef 100644 --- a/Telegram/SourceFiles/boxes/send_files_box.cpp +++ b/Telegram/SourceFiles/boxes/send_files_box.cpp @@ -1,36 +1,38 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/send_files_box.h" +#include "core/file_utilities.h" +#include "history/history_media_types.h" #include "lang/lang_keys.h" -#include "storage/localstorage.h" #include "mainwidget.h" -#include "history/history_media_types.h" -#include "core/file_utilities.h" -#include "ui/widgets/checkbox.h" +#include "media/media_clip_reader.h" +#include "storage/localstorage.h" +#include "styles/style_boxes.h" +#include "styles/style_history.h" #include "ui/widgets/buttons.h" +#include "ui/widgets/checkbox.h" #include "ui/widgets/input_fields.h" -#include "styles/style_history.h" -#include "styles/style_boxes.h" -#include "media/media_clip_reader.h" #include "window/window_controller.h" namespace { @@ -43,18 +45,18 @@ bool ValidatePhotoDimensions(int width, int height) { } // namespace -SendFilesBox::SendFilesBox(QWidget*, QImage image, CompressConfirm compressed) -: _image(image) -, _compressConfirm(compressed) -, _caption(this, st::confirmCaptionArea, langFactory(lng_photo_caption)) { +SendFilesBox::SendFilesBox(QWidget *, QImage image, CompressConfirm compressed) + : _image(image) + , _compressConfirm(compressed) + , _caption(this, st::confirmCaptionArea, langFactory(lng_photo_caption)) { _files.push_back(QString()); prepareSingleFileLayout(); } -SendFilesBox::SendFilesBox(QWidget*, const QStringList &files, CompressConfirm compressed) -: _files(files) -, _compressConfirm(compressed) -, _caption(this, st::confirmCaptionArea, langFactory(_files.size() > 1 ? lng_photos_comment : lng_photo_caption)) { +SendFilesBox::SendFilesBox(QWidget *, const QStringList &files, CompressConfirm compressed) + : _files(files) + , _compressConfirm(compressed) + , _caption(this, st::confirmCaptionArea, langFactory(_files.size() > 1 ? lng_photos_comment : lng_photo_caption)) { if (_files.size() == 1) { prepareSingleFileLayout(); } @@ -79,16 +81,19 @@ void SendFilesBox::prepareSingleFileLayout() { if (originalWidth > originalHeight) { thumbWidth = (originalWidth * st::msgFileThumbSize) / originalHeight; } - auto options = Images::Option::Smooth | Images::Option::RoundedSmall | Images::Option::RoundedTopLeft | Images::Option::RoundedTopRight | Images::Option::RoundedBottomLeft | Images::Option::RoundedBottomRight; - _fileThumb = Images::pixmap(image, thumbWidth * cIntRetinaFactor(), 0, options, st::msgFileThumbSize, st::msgFileThumbSize); + auto options = Images::Option::Smooth | Images::Option::RoundedSmall | Images::Option::RoundedTopLeft | + Images::Option::RoundedTopRight | Images::Option::RoundedBottomLeft | + Images::Option::RoundedBottomRight; + _fileThumb = Images::pixmap(image, thumbWidth * cIntRetinaFactor(), 0, options, st::msgFileThumbSize, + st::msgFileThumbSize); } else { auto maxW = 0; auto maxH = 0; if (_animated) { auto limitW = st::boxWideWidth - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(); auto limitH = st::confirmMaxHeight; - maxW = qMax(image.width(), 1); - maxH = qMax(image.height(), 1); + maxW = std::max(image.width(), 1); + maxH = std::max(image.height(), 1); if (maxW * limitH > maxH * limitW) { if (maxW < limitW) { maxH = maxH * limitW / maxW; @@ -100,7 +105,8 @@ void SendFilesBox::prepareSingleFileLayout() { maxH = limitH; } } - image = Images::prepare(image, maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), Images::Option::Smooth | Images::Option::Blurred, maxW, maxH); + image = Images::prepare(image, maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), + Images::Option::Smooth | Images::Option::Blurred, maxW, maxH); } auto originalWidth = image.width(); auto originalHeight = image.height(); @@ -109,18 +115,19 @@ void SendFilesBox::prepareSingleFileLayout() { } _previewWidth = st::boxWideWidth - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(); if (image.width() < _previewWidth) { - _previewWidth = qMax(image.width(), kMinPreviewWidth); + _previewWidth = std::max(image.width(), kMinPreviewWidth); } - auto maxthumbh = qMin(qRound(1.5 * _previewWidth), st::confirmMaxHeight); - _previewHeight = qRound(originalHeight * float64(_previewWidth) / originalWidth); + auto maxthumbh = std::min(std::round(1.5 * _previewWidth), st::confirmMaxHeight); + _previewHeight = std::round(originalHeight * double(_previewWidth) / originalWidth); if (_previewHeight > maxthumbh) { - _previewWidth = qRound(_previewWidth * float64(maxthumbh) / _previewHeight); + _previewWidth = std::round(_previewWidth * double(maxthumbh) / _previewHeight); accumulate_max(_previewWidth, kMinPreviewWidth); _previewHeight = maxthumbh; } _previewLeft = (st::boxWideWidth - _previewWidth) / 2; - image = std::move(image).scaled(_previewWidth * cIntRetinaFactor(), _previewHeight * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + image = std::move(image).scaled(_previewWidth * cIntRetinaFactor(), _previewHeight * cIntRetinaFactor(), + Qt::IgnoreAspectRatio, Qt::SmoothTransformation); image = Images::prepareOpaque(std::move(image)); _preview = App::pixmapFromImageInPlace(std::move(image)); _preview.setDevicePixelRatio(cRetinaFactor()); @@ -145,9 +152,8 @@ void SendFilesBox::prepareGifPreview() { return _animated; }; if (createGifPreview()) { - _gifPreview = Media::Clip::MakeReader(_files.front(), [this](Media::Clip::Notification notification) { - clipCallback(notification); - }); + _gifPreview = Media::Clip::MakeReader( + _files.front(), [this](Media::Clip::Notification notification) { clipCallback(notification); }); if (_gifPreview) _gifPreview->setAutoplay(); } } @@ -162,7 +168,8 @@ void SendFilesBox::clipCallback(Media::Clip::Notification notification) { if (_gifPreview && _gifPreview->ready() && !_gifPreview->started()) { auto s = QSize(_previewWidth, _previewHeight); - _gifPreview->start(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None, ImageRoundCorner::None); + _gifPreview->start(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None, + ImageRoundCorner::None); } update(); @@ -182,7 +189,7 @@ void SendFilesBox::prepareDocumentLayout() { auto filename = filedialogDefaultName(qsl("image"), qsl(".png"), QString(), true); _nameText.setText(st::semiboldTextStyle, filename, _textNameOptions); _statusText = qsl("%1x%2").arg(_image.width()).arg(_image.height()); - _statusWidth = qMax(_nameText.maxWidth(), st::normalFont->width(_statusText)); + _statusWidth = std::max(_nameText.maxWidth(), st::normalFont->width(_statusText)); _fileIsImage = true; } else { auto fileinfo = QFileInfo(filepath); @@ -199,10 +206,10 @@ void SendFilesBox::prepareDocumentLayout() { } } - auto nameString = DocumentData::composeNameString(filename, songTitle, songPerformer); + auto nameString = DocumentData::ComposeNameString(filename, songTitle, songPerformer); _nameText.setText(st::semiboldTextStyle, nameString, _textNameOptions); _statusText = formatSizeText(fileinfo.size()); - _statusWidth = qMax(_nameText.maxWidth(), st::normalFont->width(_statusText)); + _statusWidth = std::max(_nameText.maxWidth(), st::normalFont->width(_statusText)); } } @@ -219,14 +226,14 @@ void SendFilesBox::tryToReadSingleFile() { } } -SendFilesBox::SendFilesBox(QWidget*, const QString &phone, const QString &firstname, const QString &lastname) -: _contactPhone(phone) -, _contactFirstName(firstname) -, _contactLastName(lastname) { +SendFilesBox::SendFilesBox(QWidget *, const QString &phone, const QString &firstname, const QString &lastname) + : _contactPhone(phone) + , _contactFirstName(firstname) + , _contactLastName(lastname) { auto name = lng_full_name(lt_first_name, _contactFirstName, lt_last_name, _contactLastName); _nameText.setText(st::semiboldTextStyle, name, _textNameOptions); _statusText = _contactPhone; - _statusWidth = qMax(_nameText.maxWidth(), st::normalFont->width(_statusText)); + _statusWidth = std::max(_nameText.maxWidth(), st::normalFont->width(_statusText)); _contactPhotoEmpty.set(0, name); } @@ -241,7 +248,8 @@ void SendFilesBox::prepare() { addButton(langFactory(lng_cancel), [this] { closeBox(); }); if (_compressConfirm != CompressConfirm::None) { - auto compressed = (_compressConfirm == CompressConfirm::Auto) ? cCompressPastedImage() : (_compressConfirm == CompressConfirm::Yes); + auto compressed = (_compressConfirm == CompressConfirm::Auto) ? cCompressPastedImage() : + (_compressConfirm == CompressConfirm::Yes); auto text = lng_send_images_compress(lt_count, _files.size()); _compressed.create(this, text, compressed, st::defaultBoxCheckbox); subscribe(_compressed->checkedChanged, [this](bool checked) { onCompressedChange(); }); @@ -263,7 +271,7 @@ void SendFilesBox::prepare() { updateBoxSize(); } -base::lambda SendFilesBox::getSendButtonText() const { +Fn SendFilesBox::getSendButtonText() const { if (!_contactPhone.isEmpty()) { return langFactory(lng_send_button); } else if (_compressed && _compressed->checked()) { @@ -286,7 +294,8 @@ void SendFilesBox::onCaptionResized() { } void SendFilesBox::updateTitleText() { - _titleText = (_compressConfirm == CompressConfirm::None) ? lng_send_files_selected(lt_count, _files.size()) : lng_send_images_selected(lt_count, _files.size()); + _titleText = (_compressConfirm == CompressConfirm::None) ? lng_send_files_selected(lt_count, _files.size()) : + lng_send_images_selected(lt_count, _files.size()); update(); } @@ -295,11 +304,13 @@ void SendFilesBox::updateBoxSize() { if (!_preview.isNull()) { newHeight += st::boxPhotoPadding.top() + _previewHeight; } else if (!_fileThumb.isNull()) { - newHeight += st::boxPhotoPadding.top() + st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom(); + newHeight += st::boxPhotoPadding.top() + st::msgFileThumbPadding.top() + st::msgFileThumbSize + + st::msgFileThumbPadding.bottom(); } else if (_files.size() > 1) { newHeight += 0; } else { - newHeight += st::boxPhotoPadding.top() + st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom(); + newHeight += + st::boxPhotoPadding.top() + st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom(); } if (_compressed) { newHeight += st::boxPhotoCompressedSkip + _compressed->heightNoMargins(); @@ -312,7 +323,8 @@ void SendFilesBox::updateBoxSize() { void SendFilesBox::keyPressEvent(QKeyEvent *e) { if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { - onSend((e->modifiers().testFlag(Qt::ControlModifier) || e->modifiers().testFlag(Qt::MetaModifier)) && e->modifiers().testFlag(Qt::ShiftModifier)); + onSend((e->modifiers().testFlag(Qt::ControlModifier) || e->modifiers().testFlag(Qt::MetaModifier)) && + e->modifiers().testFlag(Qt::ShiftModifier)); } else { BoxContent::keyPressEvent(e); } @@ -331,21 +343,27 @@ void SendFilesBox::paintEvent(QPaintEvent *e) { if (!_preview.isNull()) { if (_previewLeft > st::boxPhotoPadding.left()) { - p.fillRect(st::boxPhotoPadding.left(), st::boxPhotoPadding.top(), _previewLeft - st::boxPhotoPadding.left(), _previewHeight, st::confirmBg); + p.fillRect(st::boxPhotoPadding.left(), st::boxPhotoPadding.top(), _previewLeft - st::boxPhotoPadding.left(), + _previewHeight, st::confirmBg); } if (_previewLeft + _previewWidth < width() - st::boxPhotoPadding.right()) { - p.fillRect(_previewLeft + _previewWidth, st::boxPhotoPadding.top(), width() - st::boxPhotoPadding.right() - _previewLeft - _previewWidth, _previewHeight, st::confirmBg); + p.fillRect(_previewLeft + _previewWidth, st::boxPhotoPadding.top(), + width() - st::boxPhotoPadding.right() - _previewLeft - _previewWidth, _previewHeight, + st::confirmBg); } if (_gifPreview && _gifPreview->started()) { auto s = QSize(_previewWidth, _previewHeight); auto paused = controller()->isGifPausedAtLeastFor(Window::GifPauseReason::Layer); - auto frame = _gifPreview->current(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None, ImageRoundCorner::None, paused ? 0 : getms()); + auto frame = _gifPreview->current(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None, + ImageRoundCorner::None, paused ? 0 : getms()); p.drawPixmap(_previewLeft, st::boxPhotoPadding.top(), frame); } else { p.drawPixmap(_previewLeft, st::boxPhotoPadding.top(), _preview); } if (_animated && !_gifPreview) { - auto inner = QRect(_previewLeft + (_previewWidth - st::msgFileSize) / 2, st::boxPhotoPadding.top() + (_previewHeight - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize); + auto inner = QRect(_previewLeft + (_previewWidth - st::msgFileSize) / 2, + st::boxPhotoPadding.top() + (_previewHeight - st::msgFileSize) / 2, st::msgFileSize, + st::msgFileSize); p.setPen(Qt::NoPen); p.setBrush(st::msgDateImgBg); @@ -359,7 +377,9 @@ void SendFilesBox::paintEvent(QPaintEvent *e) { } } else if (_files.size() < 2) { auto w = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(); - auto h = _fileThumb.isNull() ? (st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom()) : (st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom()); + auto h = _fileThumb.isNull() ? + (st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom()) : + (st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom()); auto nameleft = 0, nametop = 0, nameright = 0, statustop = 0, linktop = 0; if (_fileThumb.isNull()) { nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right(); @@ -373,14 +393,16 @@ void SendFilesBox::paintEvent(QPaintEvent *e) { statustop = st::msgFileThumbStatusTop; linktop = st::msgFileThumbLinkTop; } - auto namewidth = w - nameleft - (_fileThumb.isNull() ? st::msgFilePadding.left() : st::msgFileThumbPadding.left()); - int32 x = (width() - w) / 2, y = st::boxPhotoPadding.top(); + auto namewidth = + w - nameleft - (_fileThumb.isNull() ? st::msgFilePadding.left() : st::msgFileThumbPadding.left()); + qint32 x = (width() - w) / 2, y = st::boxPhotoPadding.top(); App::roundRect(p, x, y, w, h, st::msgOutBg, MessageOutCorners, &st::msgOutShadow); if (_fileThumb.isNull()) { if (_contactPhone.isNull()) { - QRect inner(rtlrect(x + st::msgFilePadding.left(), y + st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, width())); + QRect inner(rtlrect(x + st::msgFilePadding.left(), y + st::msgFilePadding.top(), st::msgFileSize, + st::msgFileSize, width())); p.setPen(Qt::NoPen); p.setBrush(st::msgFileOutBg); @@ -389,13 +411,16 @@ void SendFilesBox::paintEvent(QPaintEvent *e) { p.drawEllipse(inner); } - auto &icon = _fileIsAudio ? st::historyFileOutPlay : _fileIsImage ? st::historyFileOutImage : st::historyFileOutDocument; + auto &icon = _fileIsAudio ? st::historyFileOutPlay : + _fileIsImage ? st::historyFileOutImage : st::historyFileOutDocument; icon.paintInCenter(p, inner); } else { - _contactPhotoEmpty.paint(p, x + st::msgFilePadding.left(), y + st::msgFilePadding.top(), width(), st::msgFileSize); + _contactPhotoEmpty.paint(p, x + st::msgFilePadding.left(), y + st::msgFilePadding.top(), width(), + st::msgFileSize); } } else { - QRect rthumb(rtlrect(x + st::msgFileThumbPadding.left(), y + st::msgFileThumbPadding.top(), st::msgFileThumbSize, st::msgFileThumbSize, width())); + QRect rthumb(rtlrect(x + st::msgFileThumbPadding.left(), y + st::msgFileThumbPadding.top(), + st::msgFileThumbSize, st::msgFileThumbSize, width())); p.drawPixmap(rthumb.topLeft(), _fileThumb); } p.setFont(st::semiboldFont); @@ -417,7 +442,8 @@ void SendFilesBox::resizeEvent(QResizeEvent *e) { void SendFilesBox::updateControlsGeometry() { auto bottom = height(); if (_caption) { - _caption->resize(st::boxWideWidth - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(), _caption->height()); + _caption->resize(st::boxWideWidth - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(), + _caption->height()); _caption->moveToLeft(st::boxPhotoPadding.left(), bottom - _caption->height()); bottom -= st::boxPhotoCaptionSkip + _caption->height(); } @@ -443,13 +469,17 @@ void SendFilesBox::onSend(bool ctrlShiftEnter) { _confirmed = true; if (_confirmedCallback) { auto compressed = _compressed ? _compressed->checked() : false; - auto caption = _caption ? TextUtilities::PrepareForSending(_caption->getLastText(), TextUtilities::PrepareTextOption::CheckLinks) : QString(); - _confirmedCallback(_files, _animated ? QImage() : _image, std::move(_information), compressed, caption, ctrlShiftEnter); + auto caption = _caption ? TextUtilities::PrepareForSending(_caption->getLastText(), + TextUtilities::PrepareTextOption::CheckLinks) : + QString(); + _confirmedCallback(_files, _animated ? QImage() : _image, std::move(_information), compressed, caption, + ctrlShiftEnter); } closeBox(); } -EditCaptionBox::EditCaptionBox(QWidget*, HistoryMedia *media, FullMsgId msgId) : _msgId(msgId) { +EditCaptionBox::EditCaptionBox(QWidget *, HistoryMedia *media, FullMsgId msgId) + : _msgId(msgId) { Expects(media->canEditCaption()); QSize dimensions; @@ -460,21 +490,21 @@ EditCaptionBox::EditCaptionBox(QWidget*, HistoryMedia *media, FullMsgId msgId) : switch (media->type()) { case MediaTypeGif: { _animated = true; - doc = static_cast(media)->getDocument(); + doc = static_cast(media)->getDocument(); dimensions = doc->dimensions; image = doc->thumb; } break; case MediaTypePhoto: { _photo = true; - auto photo = static_cast(media)->photo(); + auto photo = static_cast(media)->photo(); dimensions = QSize(photo->full->width(), photo->full->height()); image = photo->full; } break; case MediaTypeVideo: { _animated = true; - doc = static_cast(media)->getDocument(); + doc = static_cast(media)->getDocument(); dimensions = doc->dimensions; image = doc->thumb; } break; @@ -483,7 +513,7 @@ EditCaptionBox::EditCaptionBox(QWidget*, HistoryMedia *media, FullMsgId msgId) : case MediaTypeMusicFile: case MediaTypeVoiceFile: { _doc = true; - doc = static_cast(media)->getDocument(); + doc = static_cast(media)->getDocument(); image = doc->thumb; } break; } @@ -493,34 +523,34 @@ EditCaptionBox::EditCaptionBox(QWidget*, HistoryMedia *media, FullMsgId msgId) : if (image->isNull()) { _thumbw = 0; } else { - int32 tw = image->width(), th = image->height(); + qint32 tw = image->width(), th = image->height(); if (tw > th) { _thumbw = (tw * st::msgFileThumbSize) / th; } else { _thumbw = st::msgFileThumbSize; } - auto options = Images::Option::Smooth | Images::Option::RoundedSmall | Images::Option::RoundedTopLeft | Images::Option::RoundedTopRight | Images::Option::RoundedBottomLeft | Images::Option::RoundedBottomRight; - _thumb = Images::pixmap(image->pix().toImage(), _thumbw * cIntRetinaFactor(), 0, options, st::msgFileThumbSize, st::msgFileThumbSize); + auto options = Images::Option::Smooth | Images::Option::RoundedSmall | Images::Option::RoundedTopLeft | + Images::Option::RoundedTopRight | Images::Option::RoundedBottomLeft | + Images::Option::RoundedBottomRight; + _thumb = Images::pixmap(image->pix().toImage(), _thumbw * cIntRetinaFactor(), 0, options, + st::msgFileThumbSize, st::msgFileThumbSize); } if (doc) { - if (doc->voice()) { - _name.setText(st::semiboldTextStyle, lang(lng_media_audio), _textNameOptions); - } else { - _name.setText(st::semiboldTextStyle, doc->composeNameString(), _textNameOptions); - } + auto nameString = doc->voice() ? lang(lng_media_audio) : doc->composeNameString(); + _name.setText(st::semiboldTextStyle, nameString, _textNameOptions); _status = formatSizeText(doc->size); - _statusw = qMax(_name.maxWidth(), st::normalFont->width(_status)); + _statusw = std::max(_name.maxWidth(), st::normalFont->width(_status)); _isImage = doc->isImage(); _isAudio = (doc->voice() || doc->song()); } } else { - int32 maxW = 0, maxH = 0; + qint32 maxW = 0, maxH = 0; if (_animated) { - int32 limitW = st::boxWideWidth - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(); - int32 limitH = st::confirmMaxHeight; - maxW = qMax(dimensions.width(), 1); - maxH = qMax(dimensions.height(), 1); + qint32 limitW = st::boxWideWidth - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(); + qint32 limitH = st::confirmMaxHeight; + maxW = std::max(dimensions.width(), 1); + maxH = std::max(dimensions.height(), 1); if (maxW * limitH > maxH * limitW) { if (maxW < limitW) { maxH = maxH * limitW / maxW; @@ -532,14 +562,16 @@ EditCaptionBox::EditCaptionBox(QWidget*, HistoryMedia *media, FullMsgId msgId) : maxH = limitH; } } - _thumb = image->pixNoCache(maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), Images::Option::Smooth | Images::Option::Blurred, maxW, maxH); + _thumb = image->pixNoCache(maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), + Images::Option::Smooth | Images::Option::Blurred, maxW, maxH); prepareGifPreview(doc); } else { maxW = dimensions.width(); maxH = dimensions.height(); - _thumb = image->pixNoCache(maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), Images::Option::Smooth, maxW, maxH); + _thumb = image->pixNoCache(maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), Images::Option::Smooth, + maxW, maxH); } - int32 tw = _thumb.width(), th = _thumb.height(); + qint32 tw = _thumb.width(), th = _thumb.height(); if (!tw || !th) { tw = th = 1; } @@ -547,10 +579,10 @@ EditCaptionBox::EditCaptionBox(QWidget*, HistoryMedia *media, FullMsgId msgId) : if (_thumb.width() < _thumbw) { _thumbw = (_thumb.width() > 20) ? _thumb.width() : 20; } - int32 maxthumbh = qMin(qRound(1.5 * _thumbw), int(st::confirmMaxHeight)); - _thumbh = qRound(th * float64(_thumbw) / tw); + qint32 maxthumbh = std::min(std::round(1.5 * _thumbw), int(st::confirmMaxHeight)); + _thumbh = std::round(th * double(_thumbw) / tw); if (_thumbh > maxthumbh) { - _thumbw = qRound(_thumbw * float64(maxthumbh) / _thumbh); + _thumbw = std::round(_thumbw * double(maxthumbh) / _thumbh); _thumbh = maxthumbh; if (_thumbw < 10) { _thumbw = 10; @@ -558,7 +590,9 @@ EditCaptionBox::EditCaptionBox(QWidget*, HistoryMedia *media, FullMsgId msgId) : } _thumbx = (st::boxWideWidth - _thumbw) / 2; - _thumb = App::pixmapFromImageInPlace(_thumb.toImage().scaled(_thumbw * cIntRetinaFactor(), _thumbh * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + _thumb = App::pixmapFromImageInPlace(_thumb.toImage().scaled(_thumbw * cIntRetinaFactor(), + _thumbh * cIntRetinaFactor(), + Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); _thumb.setDevicePixelRatio(cRetinaFactor()); } Assert(_animated || _photo || _doc); @@ -569,14 +603,11 @@ EditCaptionBox::EditCaptionBox(QWidget*, HistoryMedia *media, FullMsgId msgId) : } void EditCaptionBox::prepareGifPreview(DocumentData *document) { - auto createGifPreview = [document] { - return (document && document->isAnimation()); - }; + auto createGifPreview = [document] { return (document && document->isAnimation()); }; auto createGifPreviewResult = createGifPreview(); // Clang freeze workaround. if (createGifPreviewResult) { - _gifPreview = Media::Clip::MakeReader(document, _msgId, [this](Media::Clip::Notification notification) { - clipCallback(notification); - }); + _gifPreview = Media::Clip::MakeReader( + document, _msgId, [this](Media::Clip::Notification notification) { clipCallback(notification); }); if (_gifPreview) _gifPreview->setAutoplay(); } } @@ -591,7 +622,8 @@ void EditCaptionBox::clipCallback(Media::Clip::Notification notification) { if (_gifPreview && _gifPreview->ready() && !_gifPreview->started()) { auto s = QSize(_thumbw, _thumbh); - _gifPreview->start(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None, ImageRoundCorner::None); + _gifPreview->start(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None, + ImageRoundCorner::None); } update(); @@ -626,7 +658,8 @@ void EditCaptionBox::onCaptionResized() { } void EditCaptionBox::updateBoxSize() { - auto newHeight = st::boxPhotoPadding.top() + st::boxPhotoCaptionSkip + _field->height() + errorTopSkip() + st::normalFont->height; + auto newHeight = st::boxPhotoPadding.top() + st::boxPhotoCaptionSkip + _field->height() + errorTopSkip() + + st::normalFont->height; if (_photo || _animated) { newHeight += _thumbh; } else if (_thumbw) { @@ -650,21 +683,25 @@ void EditCaptionBox::paintEvent(QPaintEvent *e) { if (_photo || _animated) { if (_thumbx > st::boxPhotoPadding.left()) { - p.fillRect(st::boxPhotoPadding.left(), st::boxPhotoPadding.top(), _thumbx - st::boxPhotoPadding.left(), _thumbh, st::confirmBg); + p.fillRect(st::boxPhotoPadding.left(), st::boxPhotoPadding.top(), _thumbx - st::boxPhotoPadding.left(), + _thumbh, st::confirmBg); } if (_thumbx + _thumbw < width() - st::boxPhotoPadding.right()) { - p.fillRect(_thumbx + _thumbw, st::boxPhotoPadding.top(), width() - st::boxPhotoPadding.right() - _thumbx - _thumbw, _thumbh, st::confirmBg); + p.fillRect(_thumbx + _thumbw, st::boxPhotoPadding.top(), + width() - st::boxPhotoPadding.right() - _thumbx - _thumbw, _thumbh, st::confirmBg); } if (_gifPreview && _gifPreview->started()) { auto s = QSize(_thumbw, _thumbh); auto paused = controller()->isGifPausedAtLeastFor(Window::GifPauseReason::Layer); - auto frame = _gifPreview->current(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None, ImageRoundCorner::None, paused ? 0 : getms()); + auto frame = _gifPreview->current(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None, + ImageRoundCorner::None, paused ? 0 : getms()); p.drawPixmap(_thumbx, st::boxPhotoPadding.top(), frame); } else { p.drawPixmap(_thumbx, st::boxPhotoPadding.top(), _thumb); } if (_animated && !_gifPreview) { - QRect inner(_thumbx + (_thumbw - st::msgFileSize) / 2, st::boxPhotoPadding.top() + (_thumbh - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize); + QRect inner(_thumbx + (_thumbw - st::msgFileSize) / 2, + st::boxPhotoPadding.top() + (_thumbh - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize); p.setPen(Qt::NoPen); p.setBrush(st::msgDateImgBg); @@ -677,9 +714,8 @@ void EditCaptionBox::paintEvent(QPaintEvent *e) { icon->paintInCenter(p, inner); } } else if (_doc) { - int32 w = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(); - int32 h = _thumbw ? (0 + st::msgFileThumbSize + 0) : (0 + st::msgFileSize + 0); - int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0; + qint32 w = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(); + qint32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0; if (_thumbw) { nameleft = 0 + st::msgFileThumbSize + st::msgFileThumbPadding.right(); nametop = st::msgFileThumbNameTop - st::msgFileThumbPadding.top(); @@ -691,14 +727,14 @@ void EditCaptionBox::paintEvent(QPaintEvent *e) { nameright = 0; statustop = st::msgFileStatusTop - st::msgFilePadding.top(); } - int32 namewidth = w - nameleft - 0; + qint32 namewidth = w - nameleft - 0; if (namewidth > _statusw) { - //w -= (namewidth - _statusw); - //namewidth = _statusw; + // w -= (namewidth - _statusw); + // namewidth = _statusw; } - int32 x = (width() - w) / 2, y = st::boxPhotoPadding.top(); + qint32 x = (width() - w) / 2, y = st::boxPhotoPadding.top(); -// App::roundRect(p, x, y, w, h, st::msgInBg, MessageInCorners, &st::msgInShadow); + // App::roundRect(p, x, y, w, h, st::msgInBg, MessageInCorners, &st::msgInShadow); if (_thumbw) { QRect rthumb(rtlrect(x + 0, y + 0, st::msgFileThumbSize, st::msgFileThumbSize, width())); @@ -713,7 +749,8 @@ void EditCaptionBox::paintEvent(QPaintEvent *e) { p.drawEllipse(inner); } - auto icon = &(_isAudio ? st::historyFileInPlay : _isImage ? st::historyFileInImage : st::historyFileInDocument); + auto icon = + &(_isAudio ? st::historyFileInPlay : _isImage ? st::historyFileInImage : st::historyFileInDocument); icon->paintInCenter(p, inner); } p.setFont(st::semiboldFont); @@ -740,7 +777,8 @@ void EditCaptionBox::paintEvent(QPaintEvent *e) { void EditCaptionBox::resizeEvent(QResizeEvent *e) { BoxContent::resizeEvent(e); _field->resize(st::boxWideWidth - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(), _field->height()); - _field->moveToLeft(st::boxPhotoPadding.left(), height() - st::normalFont->height - errorTopSkip() - _field->height()); + _field->moveToLeft(st::boxPhotoPadding.left(), + height() - st::normalFont->height - errorTopSkip() - _field->height()); } void EditCaptionBox::setInnerFocus() { @@ -766,7 +804,10 @@ void EditCaptionBox::onSave(bool ctrlShiftEnter) { flags |= MTPmessages_EditMessage::Flag::f_entities; } auto text = TextUtilities::PrepareForSending(_field->getLastText(), TextUtilities::PrepareTextOption::CheckLinks); - _saveRequestId = MTP::send(MTPmessages_EditMessage(MTP_flags(flags), item->history()->peer->input, MTP_int(item->id), MTP_string(text), MTPnullMarkup, sentEntities), rpcDone(&EditCaptionBox::saveDone), rpcFail(&EditCaptionBox::saveFail)); + _saveRequestId = + MTP::send(MTPmessages_EditMessage(MTP_flags(flags), item->history()->peer->input, MTP_int(item->id), + MTP_string(text), MTPnullMarkup, sentEntities, MTP_inputGeoPointEmpty()), + rpcDone(&EditCaptionBox::saveDone), rpcFail(&EditCaptionBox::saveFail)); } void EditCaptionBox::saveDone(const MTPUpdates &updates) { @@ -782,7 +823,8 @@ bool EditCaptionBox::saveFail(const RPCError &error) { _saveRequestId = 0; QString err = error.type(); - if (err == qstr("MESSAGE_ID_INVALID") || err == qstr("CHAT_ADMIN_REQUIRED") || err == qstr("MESSAGE_EDIT_TIME_EXPIRED")) { + if (err == qstr("MESSAGE_ID_INVALID") || err == qstr("CHAT_ADMIN_REQUIRED") || + err == qstr("MESSAGE_EDIT_TIME_EXPIRED")) { _error = lang(lng_edit_error); } else if (err == qstr("MESSAGE_NOT_MODIFIED")) { closeBox(); diff --git a/Telegram/SourceFiles/boxes/send_files_box.h b/Telegram/SourceFiles/boxes/send_files_box.h index 724b0689b..194a90ef1 100644 --- a/Telegram/SourceFiles/boxes/send_files_box.h +++ b/Telegram/SourceFiles/boxes/send_files_box.h @@ -1,26 +1,29 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "boxes/abstract_box.h" +#include "history/history_media.h" #include "storage/localimageloader.h" namespace Ui { @@ -33,14 +36,17 @@ class SendFilesBox : public BoxContent { Q_OBJECT public: - SendFilesBox(QWidget*, QImage image, CompressConfirm compressed); - SendFilesBox(QWidget*, const QStringList &files, CompressConfirm compressed); - SendFilesBox(QWidget*, const QString &phone, const QString &firstname, const QString &lastname); - - void setConfirmedCallback(base::lambda information, bool compressed, const QString &caption, bool ctrlShiftEnter)> callback) { + SendFilesBox(QWidget *, QImage image, CompressConfirm compressed); + SendFilesBox(QWidget *, const QStringList &files, CompressConfirm compressed); + SendFilesBox(QWidget *, const QString &phone, const QString &firstname, const QString &lastname); + + void setConfirmedCallback(Fn information, bool compressed, + const QString &caption, bool ctrlShiftEnter)> + callback) { _confirmedCallback = std::move(callback); } - void setCancelledCallback(base::lambda callback) { + void setCancelledCallback(Fn callback) { _cancelledCallback = std::move(callback); } @@ -70,7 +76,7 @@ private slots: void updateTitleText(); void updateBoxSize(); void updateControlsGeometry(); - base::lambda getSendButtonText() const; + Fn getSendButtonText() const; QString _titleText; QStringList _files; @@ -98,22 +104,23 @@ private slots: QString _contactLastName; EmptyUserpic _contactPhotoEmpty; - base::lambda information, bool compressed, const QString &caption, bool ctrlShiftEnter)> _confirmedCallback; - base::lambda _cancelledCallback; + Fn information, + bool compressed, const QString &caption, bool ctrlShiftEnter)> + _confirmedCallback; + Fn _cancelledCallback; bool _confirmed = false; - object_ptr _caption = { nullptr }; - object_ptr _compressed = { nullptr }; + object_ptr _caption = {nullptr}; + object_ptr _compressed = {nullptr}; QPointer _send; - }; class EditCaptionBox : public BoxContent, public RPCSender { Q_OBJECT public: - EditCaptionBox(QWidget*, HistoryMedia *media, FullMsgId msgId); + EditCaptionBox(QWidget *, HistoryMedia *media, FullMsgId msgId); public slots: void onCaptionResized(); @@ -147,7 +154,7 @@ public slots: QPixmap _thumb; Media::Clip::ReaderPointer _gifPreview; - object_ptr _field = { nullptr }; + object_ptr _field = {nullptr}; int _thumbx = 0; int _thumby = 0; @@ -163,5 +170,4 @@ public slots: mtpRequestId _saveRequestId = 0; QString _error; - }; diff --git a/Telegram/SourceFiles/boxes/sessions_box.cpp b/Telegram/SourceFiles/boxes/sessions_box.cpp index 48cda4d77..343a44e65 100644 --- a/Telegram/SourceFiles/boxes/sessions_box.cpp +++ b/Telegram/SourceFiles/boxes/sessions_box.cpp @@ -1,38 +1,39 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/sessions_box.h" +#include "boxes/confirm_box.h" +#include "countries.h" #include "lang/lang_keys.h" -#include "storage/localstorage.h" #include "mainwidget.h" #include "mainwindow.h" -#include "countries.h" -#include "boxes/confirm_box.h" +#include "storage/localstorage.h" +#include "styles/style_boxes.h" #include "ui/widgets/buttons.h" #include "ui/widgets/scroll_area.h" -#include "styles/style_boxes.h" -SessionsBox::SessionsBox(QWidget*) -: _shortPollTimer(this) { -} +SessionsBox::SessionsBox(QWidget *) + : _shortPollTimer(this) {} void SessionsBox::prepare() { setTitle(langFactory(lng_sessions_other_header)); @@ -85,7 +86,8 @@ void SessionsBox::gotAuthorizations(const MTPaccount_Authorizations &result) { setLoading(false); auto availCurrent = st::boxWideWidth - st::sessionPadding.left() - st::sessionTerminateSkip; - auto availOther = availCurrent - st::sessionTerminate.iconPosition.x();// -st::sessionTerminate.width - st::sessionTerminateSkip; + auto availOther = + availCurrent - st::sessionTerminate.iconPosition.x(); // -st::sessionTerminate.width - st::sessionTerminateSkip; _list.clear(); if (result.type() != mtpc_account_authorizations) { @@ -104,24 +106,26 @@ void SessionsBox::gotAuthorizations(const MTPaccount_Authorizations &result) { Data data; data.hash = d.vhash.v; - QString appName, appVer = qs(d.vapp_version), systemVer = qs(d.vsystem_version), deviceModel = qs(d.vdevice_model); + 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) ? qstr("Telegram Desktop") : qstr("Telegram Desktop (GitHub)"); - // if (systemVer == qstr("windows")) { - // deviceModel = qsl("Windows"); - // } else if (systemVer == qstr("os x")) { - // deviceModel = qsl("OS X"); - // } else if (systemVer == qstr("linux")) { - // deviceModel = qsl("Linux"); - // } + appName = str_const_toString(AppName); + // if (systemVer == qstr("windows")) { + // deviceModel = qsl("Windows"); + // } else if (systemVer == qstr("os x")) { + // deviceModel = qsl("OS X"); + // } else if (systemVer == qstr("linux")) { + // deviceModel = qsl("Linux"); + // } if (appVer == QString::number(appVer.toInt())) { - int32 ver = appVer.toInt(); - appVer = QString("%1.%2").arg(ver / 1000000).arg((ver % 1000000) / 1000) + ((ver % 1000) ? ('.' + QString::number(ver % 1000)) : QString()); - //} else { - // appVer = QString(); + qint32 ver = appVer.toInt(); + appVer = QString("%1.%2").arg(ver / 1000000).arg((ver % 1000000) / 1000) + + ((ver % 1000) ? ('.' + QString::number(ver % 1000)) : QString()); + //} else { + // appVer = QString(); } } else { - appName = qs(d.vapp_name);// +qsl(" for ") + qs(d.vplatform); + appName = qs(d.vapp_name); // +qsl(" for ") + qs(d.vplatform); if (appVer.indexOf('(') >= 0) appVer = appVer.mid(appVer.indexOf('(')); } data.name = appName; @@ -129,18 +133,19 @@ void SessionsBox::gotAuthorizations(const MTPaccount_Authorizations &result) { data.nameWidth = st::sessionNameFont->width(data.name); QString country = qs(d.vcountry), platform = qs(d.vplatform); - //CountriesByISO2::const_iterator j = countries.constFind(country); - //if (j != countries.cend()) country = QString::fromUtf8(j.value()->name); + // CountriesByISO2::const_iterator j = countries.constFind(country); + // if (j != countries.cend()) country = QString::fromUtf8(j.value()->name); MTPint active = d.vdate_active.v ? d.vdate_active : d.vdate_created; data.activeTime = active.v; - data.info = qs(d.vdevice_model) + qstr(", ") + (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 = lang(lng_sessions_header); data.activeWidth = st::sessionWhenFont->width(lang(lng_sessions_header)); - int32 availForName = availCurrent - st::sessionPadding.right() - data.activeWidth; + qint32 availForName = availCurrent - st::sessionPadding.right() - data.activeWidth; if (data.nameWidth > availForName) { data.name = st::sessionNameFont->elided(data.name, availForName); data.nameWidth = st::sessionNameFont->width(data.name); @@ -168,7 +173,7 @@ void SessionsBox::gotAuthorizations(const MTPaccount_Authorizations &result) { data.active = lastDate.toString(qsl("d.MM.yy")); } data.activeWidth = st::sessionWhenFont->width(data.active); - int32 availForName = availOther - st::sessionPadding.right() - data.activeWidth; + qint32 availForName = availOther - st::sessionPadding.right() - data.activeWidth; if (data.nameWidth > availForName) { data.name = st::sessionNameFont->elided(data.name, availForName); data.nameWidth = st::sessionNameFont->width(data.name); @@ -185,7 +190,7 @@ void SessionsBox::gotAuthorizations(const MTPaccount_Authorizations &result) { } _list.push_back(data); - for (int32 i = _list.size(); i > 1;) { + for (qint32 i = _list.size(); i > 1;) { --i; if (_list.at(i).activeTime > _list.at(i - 1).activeTime) { qSwap(_list[i], _list[i - 1]); @@ -213,7 +218,7 @@ void SessionsBox::onShortPollAuthorizations() { void SessionsBox::onCheckNewAuthorization() { onShortPollAuthorizations(); -// _shortPollTimer.start(1000); + // _shortPollTimer.start(1000); } void SessionsBox::onAllTerminated() { @@ -228,10 +233,11 @@ void SessionsBox::onTerminateAll() { setLoading(true); } -SessionsBox::Inner::Inner(QWidget *parent, SessionsBox::List *list, SessionsBox::Data *current) : TWidget(parent) -, _list(list) -, _current(current) -, _terminateAll(this, lang(lng_sessions_terminate_all), st::sessionTerminateAllButton) { +SessionsBox::Inner::Inner(QWidget *parent, SessionsBox::List *list, SessionsBox::Data *current) + : TWidget(parent) + , _list(list) + , _current(current) + , _terminateAll(this, lang(lng_sessions_terminate_all), st::sessionTerminateAllButton) { connect(_terminateAll, SIGNAL(clicked()), this, SLOT(onTerminateAll())); _terminateAll->hide(); setAttribute(Qt::WA_OpaquePaintEvent); @@ -242,8 +248,11 @@ void SessionsBox::Inner::paintEvent(QPaintEvent *e) { Painter p(this); p.fillRect(r, st::boxBg); - int32 x = st::sessionPadding.left(), xact = st::sessionTerminateSkip + st::sessionTerminate.iconPosition.x();// st::sessionTerminateSkip + st::sessionTerminate.width + st::sessionTerminateSkip; - int32 w = width(); + qint32 x = st::sessionPadding.left(), + xact = st::sessionTerminateSkip + + st::sessionTerminate.iconPosition + .x(); // st::sessionTerminateSkip + st::sessionTerminate.width + st::sessionTerminateSkip; + qint32 w = width(); if (_current->active.isEmpty() && _list->isEmpty()) { p.setFont(st::noContactsFont->f); @@ -264,24 +273,28 @@ void SessionsBox::Inner::paintEvent(QPaintEvent *e) { p.setFont(st::sessionInfoFont); p.setPen(st::boxTextFg); - p.drawTextLeft(x, st::sessionPadding.top() + st::sessionNameFont->height, w, _current->info, _current->infoWidth); + p.drawTextLeft(x, st::sessionPadding.top() + st::sessionNameFont->height, w, _current->info, + _current->infoWidth); p.setPen(st::sessionInfoFg); - p.drawTextLeft(x, st::sessionPadding.top() + st::sessionNameFont->height + st::sessionInfoFont->height, w, _current->ip, _current->ipWidth); + p.drawTextLeft(x, st::sessionPadding.top() + st::sessionNameFont->height + st::sessionInfoFont->height, w, + _current->ip, _current->ipWidth); } p.translate(0, st::sessionCurrentHeight - st::sessionCurrentPadding.top()); if (_list->isEmpty()) { p.setFont(st::sessionInfoFont); p.setPen(st::sessionInfoFg); - p.drawText(QRect(st::sessionPadding.left(), 0, width() - st::sessionPadding.left() - st::sessionPadding.right(), st::noContactsHeight), lang(lng_sessions_other_desc), style::al_topleft); + p.drawText(QRect(st::sessionPadding.left(), 0, width() - st::sessionPadding.left() - st::sessionPadding.right(), + st::noContactsHeight), + lang(lng_sessions_other_desc), style::al_topleft); return; } p.setFont(st::linkFont->f); - int32 count = _list->size(); - int32 from = floorclamp(r.y() - st::sessionCurrentHeight, st::sessionHeight, 0, count); - int32 to = ceilclamp(r.y() + r.height() - st::sessionCurrentHeight, st::sessionHeight, 0, count); + qint32 count = _list->size(); + qint32 from = floorclamp(r.y() - st::sessionCurrentHeight, st::sessionHeight, 0, count); + qint32 to = ceilclamp(r.y() + r.height() - st::sessionCurrentHeight, st::sessionHeight, 0, count); p.translate(0, from * st::sessionHeight); - for (int32 i = from; i < to; ++i) { + for (qint32 i = from; i < to; ++i) { const SessionsBox::Data &auth(_list->at(i)); p.setFont(st::sessionNameFont); @@ -296,7 +309,8 @@ void SessionsBox::Inner::paintEvent(QPaintEvent *e) { p.setPen(st::boxTextFg); p.drawTextLeft(x, st::sessionPadding.top() + st::sessionNameFont->height, w, auth.info, auth.infoWidth); p.setPen(st::sessionInfoFg); - p.drawTextLeft(x, st::sessionPadding.top() + st::sessionNameFont->height + st::sessionInfoFont->height, w, auth.ip, auth.ipWidth); + p.drawTextLeft(x, st::sessionPadding.top() + st::sessionNameFont->height + st::sessionInfoFont->height, w, + auth.ip, auth.ipWidth); p.translate(0, st::sessionHeight); } @@ -306,36 +320,49 @@ void SessionsBox::Inner::onTerminate() { for (auto i = _terminateButtons.begin(), e = _terminateButtons.end(); i != e; ++i) { if (i.value()->isOver()) { if (_terminateBox) _terminateBox->deleteLater(); - _terminateBox = Ui::show(Box(lang(lng_settings_reset_one_sure), lang(lng_settings_reset_button), st::attentionBoxButton, base::lambda_guarded(this, [this, terminating = i.key()] { - if (_terminateBox) { - _terminateBox->closeBox(); - _terminateBox = nullptr; - } - MTP::send(MTPaccount_ResetAuthorization(MTP_long(terminating)), rpcDone(&Inner::terminateDone, terminating), rpcFail(&Inner::terminateFail, terminating)); - auto i = _terminateButtons.find(terminating); - if (i != _terminateButtons.cend()) { - i.value()->clearState(); - i.value()->hide(); - } - })), KeepOtherLayers); + _terminateBox = + Ui::show(Box( + lang(lng_settings_reset_one_sure), lang(lng_settings_reset_button), st::attentionBoxButton, + base::lambda_guarded(this, + [this, terminating = i.key()] { + if (_terminateBox) { + _terminateBox->closeBox(); + _terminateBox = nullptr; + } + MTP::send(MTPaccount_ResetAuthorization(MTP_long(terminating)), + rpcDone(&Inner::terminateDone, terminating), + rpcFail(&Inner::terminateFail, terminating)); + auto i = _terminateButtons.find(terminating); + if (i != _terminateButtons.cend()) { + i.value()->clearState(); + i.value()->hide(); + } + })), + KeepOtherLayers); } } } void SessionsBox::Inner::onTerminateAll() { if (_terminateBox) _terminateBox->deleteLater(); - _terminateBox = Ui::show(Box(lang(lng_settings_reset_sure), lang(lng_settings_reset_button), st::attentionBoxButton, base::lambda_guarded(this, [this] { - if (_terminateBox) { - _terminateBox->closeBox(); - _terminateBox = nullptr; - } - MTP::send(MTPauth_ResetAuthorizations(), rpcDone(&Inner::terminateAllDone), rpcFail(&Inner::terminateAllFail)); - emit terminateAll(); - })), KeepOtherLayers); + _terminateBox = + Ui::show(Box(lang(lng_settings_reset_sure), lang(lng_settings_reset_button), st::attentionBoxButton, + base::lambda_guarded(this, + [this] { + if (_terminateBox) { + _terminateBox->closeBox(); + _terminateBox = nullptr; + } + MTP::send(MTPauth_ResetAuthorizations(), + rpcDone(&Inner::terminateAllDone), + rpcFail(&Inner::terminateAllFail)); + emit terminateAll(); + })), + KeepOtherLayers); } -void SessionsBox::Inner::terminateDone(uint64 hash, const MTPBool &result) { - for (int32 i = 0, l = _list->size(); i < l; ++i) { +void SessionsBox::Inner::terminateDone(quint64 hash, const MTPBool &result) { + for (qint32 i = 0, l = _list->size(); i < l; ++i) { if (_list->at(i).hash == hash) { _list->removeAt(i); break; @@ -345,7 +372,7 @@ void SessionsBox::Inner::terminateDone(uint64 hash, const MTPBool &result) { emit oneTerminated(); } -bool SessionsBox::Inner::terminateFail(uint64 hash, const RPCError &error) { +bool SessionsBox::Inner::terminateFail(quint64 hash, const RPCError &error) { if (MTP::isDefaultHandledError(error)) return false; TerminateButtons::iterator i = _terminateButtons.find(hash); @@ -367,7 +394,8 @@ bool SessionsBox::Inner::terminateAllFail(const RPCError &error) { } void SessionsBox::Inner::resizeEvent(QResizeEvent *e) { - _terminateAll->moveToLeft(st::sessionPadding.left(), st::sessionCurrentPadding.top() + st::sessionHeight + st::sessionCurrentPadding.bottom()); + _terminateAll->moveToLeft(st::sessionPadding.left(), + st::sessionCurrentPadding.top() + st::sessionHeight + st::sessionCurrentPadding.bottom()); } void SessionsBox::Inner::listUpdated() { @@ -379,13 +407,14 @@ void SessionsBox::Inner::listUpdated() { for (TerminateButtons::iterator i = _terminateButtons.begin(), e = _terminateButtons.end(); i != e; ++i) { i.value()->move(0, -1); } - for (int32 i = 0, l = _list->size(); i < l; ++i) { + for (qint32 i = 0, l = _list->size(); i < l; ++i) { TerminateButtons::iterator j = _terminateButtons.find(_list->at(i).hash); if (j == _terminateButtons.cend()) { j = _terminateButtons.insert(_list->at(i).hash, new Ui::IconButton(this, st::sessionTerminate)); connect(j.value(), SIGNAL(clicked()), this, SLOT(onTerminate())); } - j.value()->moveToRight(st::sessionTerminateSkip, st::sessionCurrentHeight + i * st::sessionHeight + st::sessionTerminateTop, width()); + j.value()->moveToRight(st::sessionTerminateSkip, + st::sessionCurrentHeight + i * st::sessionHeight + st::sessionTerminateTop, width()); j.value()->show(); } for (TerminateButtons::iterator i = _terminateButtons.begin(); i != _terminateButtons.cend();) { @@ -396,6 +425,7 @@ void SessionsBox::Inner::listUpdated() { i = _terminateButtons.erase(i); } } - resize(width(), _list->isEmpty() ? (st::sessionCurrentHeight + st::noContactsHeight) : (st::sessionCurrentHeight + _list->size() * st::sessionHeight)); + resize(width(), _list->isEmpty() ? (st::sessionCurrentHeight + st::noContactsHeight) : + (st::sessionCurrentHeight + _list->size() * st::sessionHeight)); update(); } diff --git a/Telegram/SourceFiles/boxes/sessions_box.h b/Telegram/SourceFiles/boxes/sessions_box.h index 707b06bd5..cd4e49f6d 100644 --- a/Telegram/SourceFiles/boxes/sessions_box.h +++ b/Telegram/SourceFiles/boxes/sessions_box.h @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "boxes/abstract_box.h" @@ -34,7 +36,7 @@ class SessionsBox : public BoxContent, public RPCSender { Q_OBJECT public: - SessionsBox(QWidget*); + SessionsBox(QWidget *); protected: void prepare() override; @@ -52,10 +54,10 @@ private slots: private: void setLoading(bool loading); struct Data { - uint64 hash; + quint64 hash; - int32 activeTime; - int32 nameWidth, activeWidth, infoWidth, ipWidth; + qint32 activeTime; + qint32 nameWidth, activeWidth, infoWidth, ipWidth; QString name, active, info, ip; }; using List = QList; @@ -72,7 +74,6 @@ private slots: object_ptr _shortPollTimer; mtpRequestId _shortPollRequest = 0; - }; // This class is hold in header because it requires Qt preprocessing. @@ -98,8 +99,8 @@ public slots: void onTerminateAll(); private: - void terminateDone(uint64 hash, const MTPBool &result); - bool terminateFail(uint64 hash, const RPCError &error); + void terminateDone(quint64 hash, const MTPBool &result); + bool terminateFail(quint64 hash, const RPCError &error); void terminateAllDone(const MTPBool &res); bool terminateAllFail(const RPCError &error); @@ -107,10 +108,9 @@ public slots: SessionsBox::List *_list; SessionsBox::Data *_current; - typedef QMap TerminateButtons; + typedef QMap TerminateButtons; TerminateButtons _terminateButtons; object_ptr _terminateAll; QPointer _terminateBox; - }; diff --git a/Telegram/SourceFiles/boxes/share_box.cpp b/Telegram/SourceFiles/boxes/share_box.cpp index 0936070e5..84d92fb04 100644 --- a/Telegram/SourceFiles/boxes/share_box.cpp +++ b/Telegram/SourceFiles/boxes/share_box.cpp @@ -1,54 +1,56 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/share_box.h" +#include "apiwrap.h" +#include "auth_session.h" +#include "base/qthelp_url.h" +#include "boxes/confirm_box.h" +#include "boxes/peer_list_box.h" #include "dialogs/dialogs_indexed_list.h" -#include "styles/style_boxes.h" -#include "styles/style_history.h" -#include "observer_peer.h" +#include "history/history_media_types.h" +#include "history/history_message.h" #include "lang/lang_keys.h" -#include "mainwindow.h" #include "mainwidget.h" -#include "base/qthelp_url.h" +#include "mainwindow.h" +#include "messenger.h" +#include "observer_peer.h" #include "storage/localstorage.h" -#include "boxes/confirm_box.h" -#include "apiwrap.h" +#include "styles/style_boxes.h" +#include "styles/style_history.h" #include "ui/toast/toast.h" -#include "ui/widgets/multi_select.h" -#include "history/history_media_types.h" -#include "history/history_message.h" #include "ui/widgets/buttons.h" +#include "ui/widgets/multi_select.h" #include "ui/widgets/scroll_area.h" #include "window/themes/window_theme.h" -#include "boxes/peer_list_box.h" -#include "auth_session.h" -#include "messenger.h" -ShareBox::ShareBox(QWidget*, CopyCallback &©Callback, SubmitCallback &&submitCallback, FilterCallback &&filterCallback) -: _copyCallback(std::move(copyCallback)) -, _submitCallback(std::move(submitCallback)) -, _filterCallback(std::move(filterCallback)) -, _select(this, st::contactsMultiSelect, langFactory(lng_participant_filter)) -, _searchTimer(this) { -} +ShareBox::ShareBox(QWidget *, CopyCallback &©Callback, SubmitCallback &&submitCallback, + FilterCallback &&filterCallback) + : _copyCallback(std::move(copyCallback)) + , _submitCallback(std::move(submitCallback)) + , _filterCallback(std::move(filterCallback)) + , _select(this, st::contactsMultiSelect, langFactory(lng_participant_filter)) + , _searchTimer(this) {} void ShareBox::prepare() { _select->resizeToWidth(st::boxWideWidth); @@ -57,14 +59,14 @@ void ShareBox::prepare() { setTitle(langFactory(lng_share_title)); _inner = setInnerWidget(object_ptr(this, std::move(_filterCallback)), getTopScrollSkip()); - connect(_inner, SIGNAL(mustScrollTo(int,int)), this, SLOT(onMustScrollTo(int,int))); + connect(_inner, SIGNAL(mustScrollTo(int, int)), this, SLOT(onMustScrollTo(int, int))); createButtons(); setDimensions(st::boxWideWidth, st::boxMaxListHeight); _select->setQueryChangedCallback([this](const QString &query) { onFilterUpdate(query); }); - _select->setItemRemovedCallback([this](uint64 itemId) { + _select->setItemRemovedCallback([this](quint64 itemId) { if (auto peer = App::peerLoaded(itemId)) { _inner->peerUnselected(peer); onSelectedChanged(); @@ -74,9 +76,8 @@ void ShareBox::prepare() { _select->setResizedCallback([this] { updateScrollSkips(); }); _select->setSubmittedCallback([this](bool) { _inner->onSelectActive(); }); connect(_inner, SIGNAL(searchByUsername()), this, SLOT(onNeedSearchByUsername())); - _inner->setPeerSelectedChangedCallback([this](PeerData *peer, bool checked) { - onPeerSelectedChanged(peer, checked); - }); + _inner->setPeerSelectedChangedCallback( + [this](PeerData *peer, bool checked) { onPeerSelectedChanged(peer, checked); }); _searchTimer->setSingleShot(true); connect(_searchTimer, SIGNAL(timeout()), this, SLOT(onSearchByUsername())); @@ -116,7 +117,8 @@ bool ShareBox::onSearchByUsername(bool searchCache) { } else if (_peopleQuery != query) { _peopleQuery = query; _peopleFull = false; - _peopleRequest = MTP::send(MTPcontacts_Search(MTP_string(_peopleQuery), MTP_int(SearchPeopleLimit)), rpcDone(&ShareBox::peopleReceived), rpcFail(&ShareBox::peopleFailed)); + _peopleRequest = MTP::send(MTPcontacts_Search(MTP_string(_peopleQuery), MTP_int(SearchPeopleLimit)), + rpcDone(&ShareBox::peopleReceived), rpcFail(&ShareBox::peopleFailed)); _peopleQueries.insert(_peopleRequest, _peopleQuery); } } @@ -256,26 +258,28 @@ void ShareBox::onSelectedChanged() { void ShareBox::onMustScrollTo(int top, int bottom) { onScrollToY(top, bottom); - //auto scrollTop = scrollArea()->scrollTop(), scrollBottom = scrollTop + scrollArea()->height(); - //auto from = scrollTop, to = scrollTop; - //if (scrollTop > top) { - // to = top; - //} else if (scrollBottom < bottom) { - // to = bottom - (scrollBottom - scrollTop); - //} - //if (from != to) { - // _scrollAnimation.start([this]() { scrollAnimationCallback(); }, from, to, st::shareScrollDuration, anim::sineInOut); - //} + // auto scrollTop = scrollArea()->scrollTop(), scrollBottom = scrollTop + scrollArea()->height(); + // auto from = scrollTop, to = scrollTop; + // if (scrollTop > top) { + // to = top; + // } else if (scrollBottom < bottom) { + // to = bottom - (scrollBottom - scrollTop); + // } + // if (from != to) { + // _scrollAnimation.start([this]() { scrollAnimationCallback(); }, from, to, st::shareScrollDuration, + // anim::sineInOut); + // } } void ShareBox::scrollAnimationCallback() { - //auto scrollTop = qRound(_scrollAnimation.current(scrollArea()->scrollTop())); - //scrollArea()->scrollToY(scrollTop); + // auto scrollTop = std::round(_scrollAnimation.current(scrollArea()->scrollTop())); + // scrollArea()->scrollToY(scrollTop); } -ShareBox::Inner::Inner(QWidget *parent, ShareBox::FilterCallback &&filterCallback) : TWidget(parent) -, _filterCallback(std::move(filterCallback)) -, _chatsIndexed(std::make_unique(Dialogs::SortMode::Add)) { +ShareBox::Inner::Inner(QWidget *parent, ShareBox::FilterCallback &&filterCallback) + : TWidget(parent) + , _filterCallback(std::move(filterCallback)) + , _chatsIndexed(std::make_unique(Dialogs::SortMode::Add)) { _rowsTop = st::shareRowsTop; _rowHeight = st::shareRowHeight; setAttribute(Qt::WA_OpaquePaintEvent); @@ -293,9 +297,9 @@ ShareBox::Inner::Inner(QWidget *parent, ShareBox::FilterCallback &&filterCallbac using UpdateFlag = Notify::PeerUpdate::Flag; auto observeEvents = UpdateFlag::NameChanged | UpdateFlag::PhotoChanged; - subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) { - notifyPeerUpdated(update); - })); + subscribe(Notify::PeerUpdated(), + Notify::PeerUpdatedHandler(observeEvents, + [this](const Notify::PeerUpdate &update) { notifyPeerUpdated(update); })); subscribe(Auth().downloaderTaskFinished(), [this] { update(); }); subscribe(Window::Theme::Background(), [this](const Window::Theme::BackgroundUpdate &update) { @@ -306,9 +310,7 @@ ShareBox::Inner::Inner(QWidget *parent, ShareBox::FilterCallback &&filterCallbac } void ShareBox::Inner::invalidateCache() { - for_const (auto data, _dataMap) { - data->checkbox.invalidateCache(); - } + for_const (auto data, _dataMap) { data->checkbox.invalidateCache(); } } void ShareBox::Inner::setVisibleTopBottom(int visibleTop, int visibleBottom) { @@ -370,17 +372,17 @@ void ShareBox::Inner::repaintChatAtIndex(int index) { auto row = index / _columnCount; auto column = index % _columnCount; - update(rtlrect(_rowsLeft + qFloor(column * _rowWidthReal), row * _rowHeight, _rowWidth, _rowHeight, width())); + update(rtlrect(_rowsLeft + std::floor(column * _rowWidthReal), row * _rowHeight, _rowWidth, _rowHeight, width())); } ShareBox::Inner::Chat *ShareBox::Inner::getChatAtIndex(int index) { if (index < 0) return nullptr; - auto row = ([this, index]() -> Dialogs::Row* { + auto row = ([this, index]() -> Dialogs::Row * { if (_filter.isEmpty()) return _chatsIndexed->rowAtY(index, 1); return (index < _filtered.size()) ? _filtered[index] : nullptr; })(); if (row) { - return static_cast(row->attached); + return static_cast(row->attached); } if (!_filter.isEmpty()) { @@ -463,7 +465,7 @@ void ShareBox::Inner::loadProfilePhotos(int yFrom) { } ShareBox::Inner::Chat *ShareBox::Inner::getChat(Dialogs::Row *row) { - auto data = static_cast(row->attached); + auto data = static_cast(row->attached); if (!data) { auto peer = row->history()->peer; auto i = _dataMap.constFind(peer); @@ -481,11 +483,10 @@ ShareBox::Inner::Chat *ShareBox::Inner::getChat(Dialogs::Row *row) { void ShareBox::Inner::setActive(int active) { if (active != _active) { - auto changeNameFg = [this](int index, float64 from, float64 to) { + auto changeNameFg = [this](int index, double from, double to) { if (auto chat = getChatAtIndex(index)) { - chat->nameActive.start([this, peer = chat->peer] { - repaintChat(peer); - }, from, to, st::shareActivateDuration); + chat->nameActive.start([this, peer = chat->peer] { repaintChat(peer); }, from, to, + st::shareActivateDuration); } }; changeNameFg(_active, 1., 0.); @@ -497,7 +498,7 @@ void ShareBox::Inner::setActive(int active) { } void ShareBox::Inner::paintChat(Painter &p, TimeMs ms, Chat *chat, int index) { - auto x = _rowsLeft + qFloor((index % _columnCount) * _rowWidthReal); + auto x = _rowsLeft + std::floor((index % _columnCount) * _rowWidthReal); auto y = _rowsTop + (index / _columnCount) * _rowHeight; auto outerWidth = width(); @@ -514,11 +515,10 @@ void ShareBox::Inner::paintChat(Painter &p, TimeMs ms, Chat *chat, int index) { chat->name.drawLeftElided(p, x + nameLeft, y + nameTop, nameWidth, outerWidth, 2, style::al_top, 0, -1, 0, true); } -ShareBox::Inner::Chat::Chat(PeerData *peer, base::lambda updateCallback) -: peer(peer) -, checkbox(st::sharePhotoCheckbox, updateCallback, PaintUserpicCallback(peer)) -, name(st::sharePhotoCheckbox.imageRadius * 2) { -} +ShareBox::Inner::Chat::Chat(PeerData *peer, Fn updateCallback) + : peer(peer) + , checkbox(st::sharePhotoCheckbox, updateCallback, PaintUserpicCallback(peer)) + , name(st::sharePhotoCheckbox.imageRadius * 2) {} void ShareBox::Inner::paintEvent(QPaintEvent *e) { Painter p(this); @@ -596,11 +596,12 @@ void ShareBox::Inner::mouseMoveEvent(QMouseEvent *e) { void ShareBox::Inner::updateUpon(const QPoint &pos) { auto x = pos.x(), y = pos.y(); auto row = (y - _rowsTop) / _rowHeight; - auto column = qFloor((x - _rowsLeft) / _rowWidthReal); - auto left = _rowsLeft + qFloor(column * _rowWidthReal) + st::shareColumnSkip / 2; + auto column = std::floor((x - _rowsLeft) / _rowWidthReal); + auto left = _rowsLeft + std::floor(column * _rowWidthReal) + st::shareColumnSkip / 2; auto top = _rowsTop + row * _rowHeight + st::sharePhotoTop; auto xupon = (x >= left) && (x < left + (_rowWidth - st::shareColumnSkip)); - auto yupon = (y >= top) && (y < top + st::sharePhotoCheckbox.imageRadius * 2 + st::shareNameTop + st::shareNameStyle.font->height * 2); + auto yupon = (y >= top) && (y < top + st::sharePhotoCheckbox.imageRadius * 2 + st::shareNameTop + + st::shareNameStyle.font->height * 2); auto upon = (xupon && yupon) ? (row * _columnCount + column) : -1; if (upon >= displayedChatsCount()) { upon = -1; @@ -620,10 +621,10 @@ void ShareBox::Inner::onSelectActive() { } void ShareBox::Inner::resizeEvent(QResizeEvent *e) { - _columnSkip = (width() - _columnCount * st::sharePhotoCheckbox.imageRadius * 2) / float64(_columnCount + 1); + _columnSkip = (width() - _columnCount * st::sharePhotoCheckbox.imageRadius * 2) / double(_columnCount + 1); _rowWidthReal = st::sharePhotoCheckbox.imageRadius * 2 + _columnSkip; - _rowsLeft = qFloor(_columnSkip / 2); - _rowWidth = qFloor(_rowWidthReal); + _rowsLeft = std::floor(_columnSkip / 2); + _rowWidth = std::floor(_rowWidthReal); update(); } @@ -650,7 +651,7 @@ void ShareBox::Inner::peerUnselected(PeerData *peer) { changePeerCheckState(chat, false, ChangeStateWay::SkipCallback); } -void ShareBox::Inner::setPeerSelectedChangedCallback(base::lambda callback) { +void ShareBox::Inner::setPeerSelectedChangedCallback(Fn callback) { _peerSelectedChangedCallback = std::move(callback); } @@ -662,7 +663,7 @@ void ShareBox::Inner::changePeerCheckState(Chat *chat, bool checked, ChangeState _selected.insert(chat->peer); setActive(chatIndex(chat->peer)); } else { - _selected.remove(chat->peer); + _selected.erase(chat->peer); } if (useCallback != ChangeStateWay::SkipCallback && _peerSelectedChangedCallback) { _peerSelectedChangedCallback(chat->peer, checked); @@ -743,7 +744,7 @@ void ShareBox::Inner::updateFilter(QString filter) { void ShareBox::Inner::peopleReceived(const QString &query, const QVector &people) { _lastQuery = query.toLower().trimmed(); if (_lastQuery.at(0) == '@') _lastQuery = _lastQuery.mid(1); - int32 already = _byUsernameFiltered.size(); + qint32 already = _byUsernameFiltered.size(); _byUsernameFiltered.reserve(already + people.size()); d_byUsernameFiltered.reserve(already + people.size()); for_const (auto &mtpPeer, people) { @@ -782,13 +783,11 @@ void ShareBox::Inner::refresh() { } ShareBox::Inner::~Inner() { - for_const (auto chat, _dataMap) { - delete chat; - } + for_const (auto chat, _dataMap) { delete chat; } } -QVector ShareBox::Inner::selected() const { - QVector result; +QVector ShareBox::Inner::selected() const { + QVector result; result.reserve(_dataMap.size()); for_const (auto chat, _dataMap) { if (chat->checkbox.checked()) { @@ -800,10 +799,10 @@ QVector ShareBox::Inner::selected() const { QString AppendShareGameScoreUrl(const QString &url, const FullMsgId &fullId) { auto shareHashData = QByteArray(0x10, Qt::Uninitialized); - auto shareHashDataInts = reinterpret_cast(shareHashData.data()); - auto channel = fullId.channel ? App::channelLoaded(fullId.channel) : static_cast(nullptr); + auto shareHashDataInts = reinterpret_cast(shareHashData.data()); + auto channel = fullId.channel ? App::channelLoaded(fullId.channel) : static_cast(nullptr); auto channelAccessHash = channel ? channel->access : 0ULL; - auto channelAccessHashInts = reinterpret_cast(&channelAccessHash); + auto channelAccessHashInts = reinterpret_cast(&channelAccessHash); shareHashDataInts[0] = Auth().userId(); shareHashDataInts[1] = fullId.channel; shareHashDataInts[2] = fullId.msg; @@ -815,10 +814,11 @@ QString AppendShareGameScoreUrl(const QString &url, const FullMsgId &fullId) { hashSha1(shareHashData.constData(), shareHashData.size(), shareHashEncrypted.data()); // Mix in channel access hash to the first 64 bits of SHA1 of data. - *reinterpret_cast(shareHashEncrypted.data()) ^= *reinterpret_cast(channelAccessHashInts); + *reinterpret_cast(shareHashEncrypted.data()) ^= *reinterpret_cast(channelAccessHashInts); // Encrypt data. - if (!Local::encrypt(shareHashData.constData(), shareHashEncrypted.data() + key128Size, shareHashData.size(), shareHashEncrypted.constData())) { + if (!Local::encrypt(shareHashData.constData(), shareHashEncrypted.data() + key128Size, shareHashData.size(), + shareHashEncrypted.constData())) { return url; } @@ -844,7 +844,8 @@ QString AppendShareGameScoreUrl(const QString &url, const FullMsgId &fullId) { void ShareGameScoreByHash(const QString &hash) { auto key128Size = 0x10; - auto hashEncrypted = QByteArray::fromBase64(hash.toLatin1(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); + auto hashEncrypted = + QByteArray::fromBase64(hash.toLatin1(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); if (hashEncrypted.size() <= key128Size || (hashEncrypted.size() % 0x10) != 0) { Ui::show(Box(lang(lng_confirm_phone_link_invalid))); return; @@ -852,16 +853,18 @@ void ShareGameScoreByHash(const QString &hash) { // Decrypt data. auto hashData = QByteArray(hashEncrypted.size() - key128Size, Qt::Uninitialized); - if (!Local::decrypt(hashEncrypted.constData() + key128Size, hashData.data(), hashEncrypted.size() - key128Size, hashEncrypted.constData())) { + if (!Local::decrypt(hashEncrypted.constData() + key128Size, hashData.data(), hashEncrypted.size() - key128Size, + hashEncrypted.constData())) { return; } // Count SHA1() of data. - char dataSha1[20] = { 0 }; + char dataSha1[20] = {0}; hashSha1(hashData.constData(), hashData.size(), dataSha1); // Mix out channel access hash from the first 64 bits of SHA1 of data. - auto channelAccessHash = *reinterpret_cast(hashEncrypted.data()) ^ *reinterpret_cast(dataSha1); + auto channelAccessHash = + *reinterpret_cast(hashEncrypted.data()) ^ *reinterpret_cast(dataSha1); // Check next 64 bits of SHA1() of data. auto skipSha1Part = sizeof(channelAccessHash); @@ -870,14 +873,14 @@ void ShareGameScoreByHash(const QString &hash) { return; } - auto hashDataInts = reinterpret_cast(hashData.data()); + auto hashDataInts = reinterpret_cast(hashData.data()); if (!AuthSession::Exists() || hashDataInts[0] != Auth().userId()) { Ui::show(Box(lang(lng_share_wrong_user))); return; } // Check first 32 bits of channel access hash. - auto channelAccessHashInts = reinterpret_cast(&channelAccessHash); + auto channelAccessHashInts = reinterpret_cast(&channelAccessHash); if (channelAccessHashInts[0] != hashDataInts[3]) { Ui::show(Box(lang(lng_share_wrong_user))); return; @@ -908,16 +911,18 @@ void ShareGameScoreByHash(const QString &hash) { if (channel || !channelId) { resolveMessageAndShareScore(channel); } else { - auto requestChannelIds = MTP_vector(1, MTP_inputChannel(MTP_int(channelId), MTP_long(channelAccessHash))); + auto requestChannelIds = + MTP_vector(1, MTP_inputChannel(MTP_int(channelId), MTP_long(channelAccessHash))); auto requestChannel = MTPchannels_GetChannels(requestChannelIds); - MTP::send(requestChannel, rpcDone([channelId, resolveMessageAndShareScore](const MTPmessages_Chats &result) { - if (auto chats = Api::getChatsFromMessagesChats(result)) { - App::feedChats(*chats); - } - if (auto channel = App::channelLoaded(channelId)) { - resolveMessageAndShareScore(channel); - } - })); + MTP::send(requestChannel, + rpcDone([channelId, resolveMessageAndShareScore](const MTPmessages_Chats &result) { + if (auto chats = Api::getChatsFromMessagesChats(result)) { + App::feedChats(*chats); + } + if (auto channel = App::channelLoaded(channelId)) { + resolveMessageAndShareScore(channel); + } + })); } } } diff --git a/Telegram/SourceFiles/boxes/share_box.h b/Telegram/SourceFiles/boxes/share_box.h index b4861b279..2f294ff55 100644 --- a/Telegram/SourceFiles/boxes/share_box.h +++ b/Telegram/SourceFiles/boxes/share_box.h @@ -1,28 +1,33 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once -#include "boxes/abstract_box.h" #include "base/observer.h" +#include "boxes/abstract_box.h" #include "ui/effects/round_checkbox.h" +#include "ui/text/text.h" + +#include "structs.h" // temporarily: FullMsgId, CharData namespace Dialogs { class Row; @@ -44,10 +49,10 @@ class ShareBox : public BoxContent, public RPCSender { Q_OBJECT public: - using CopyCallback = base::lambda; - using SubmitCallback = base::lambda &)>; - using FilterCallback = base::lambda; - ShareBox(QWidget*, CopyCallback &©Callback, SubmitCallback &&submitCallback, FilterCallback &&filterCallback); + using CopyCallback = Fn; + using SubmitCallback = Fn &)>; + using FilterCallback = Fn; + ShareBox(QWidget *, CopyCallback &©Callback, SubmitCallback &&submitCallback, FilterCallback &&filterCallback); protected: void prepare() override; @@ -104,7 +109,6 @@ private slots: PeopleQueries _peopleQueries; Animation _scrollAnimation; - }; // This class is hold in header because it requires Qt preprocessing. @@ -114,10 +118,10 @@ class ShareBox::Inner : public TWidget, public RPCSender, private base::Subscrib public: Inner(QWidget *parent, ShareBox::FilterCallback &&filterCallback); - void setPeerSelectedChangedCallback(base::lambda callback); + void setPeerSelectedChangedCallback(Fn callback); void peerUnselected(PeerData *peer); - QVector selected() const; + QVector selected() const; bool hasSelected() const; void peopleReceived(const QString &query, const QVector &people); @@ -153,7 +157,7 @@ public slots: int displayedChatsCount() const; struct Chat { - Chat(PeerData *peer, base::lambda updateCallback); + Chat(PeerData *peer, Fn updateCallback); PeerData *peer; Ui::RoundImageCheckbox checkbox; @@ -182,8 +186,8 @@ public slots: void refresh(); - float64 _columnSkip = 0.; - float64 _rowWidthReal = 0.; + double _columnSkip = 0.; + double _rowWidthReal = 0.; int _rowsLeft = 0; int _rowsTop = 0; int _rowWidth = 0; @@ -195,23 +199,22 @@ public slots: ShareBox::FilterCallback _filterCallback; std::unique_ptr _chatsIndexed; QString _filter; - using FilteredDialogs = QVector; + using FilteredDialogs = QVector; FilteredDialogs _filtered; - using DataMap = QMap; + using DataMap = QMap; DataMap _dataMap; - using SelectedChats = OrderedSet; + using SelectedChats = std::set; SelectedChats _selected; - base::lambda _peerSelectedChangedCallback; + Fn _peerSelectedChangedCallback; ChatData *data(Dialogs::Row *row); bool _searching = false; QString _lastQuery; - using ByUsernameRows = QVector; - using ByUsernameDatas = QVector; + using ByUsernameRows = QVector; + using ByUsernameDatas = QVector; ByUsernameRows _byUsernameFiltered; ByUsernameDatas d_byUsernameFiltered; - }; diff --git a/Telegram/SourceFiles/boxes/sticker_set_box.cpp b/Telegram/SourceFiles/boxes/sticker_set_box.cpp index 087f8a5d0..8ceeb2ab6 100644 --- a/Telegram/SourceFiles/boxes/sticker_set_box.cpp +++ b/Telegram/SourceFiles/boxes/sticker_set_box.cpp @@ -1,39 +1,43 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/sticker_set_box.h" +#include "apiwrap.h" +#include "auth_session.h" +#include "boxes/confirm_box.h" +#include "chat_helpers/stickers.h" +#include "dialogs/dialogs_layout.h" #include "lang/lang_keys.h" #include "mainwidget.h" #include "mainwindow.h" -#include "chat_helpers/stickers.h" -#include "boxes/confirm_box.h" -#include "apiwrap.h" +#include "messenger.h" #include "storage/localstorage.h" -#include "dialogs/dialogs_layout.h" #include "styles/style_boxes.h" #include "styles/style_chat_helpers.h" #include "ui/widgets/buttons.h" #include "ui/widgets/scroll_area.h" -#include "auth_session.h" -#include "messenger.h" +#include +#include namespace { @@ -41,9 +45,8 @@ constexpr auto kStickersPanelPerRow = Stickers::kPanelPerRow; } // namespace -StickerSetBox::StickerSetBox(QWidget*, const MTPInputStickerSet &set) -: _set(set) { -} +StickerSetBox::StickerSetBox(QWidget *, const MTPInputStickerSet &set) + : _set(set) {} void StickerSetBox::prepare() { setTitle(langFactory(lng_contacts_loading)); @@ -56,10 +59,10 @@ void StickerSetBox::prepare() { onUpdateButtons(); connect(_inner, SIGNAL(updateButtons()), this, SLOT(onUpdateButtons())); - connect(_inner, SIGNAL(installed(uint64)), this, SLOT(onInstalled(uint64))); + connect(_inner, SIGNAL(installed(quint64)), this, SLOT(onInstalled(quint64))); } -void StickerSetBox::onInstalled(uint64 setId) { +void StickerSetBox::onInstalled(quint64 setId) { emit installed(setId); closeBox(); } @@ -102,10 +105,14 @@ void StickerSetBox::resizeEvent(QResizeEvent *e) { _inner->resize(width(), _inner->height()); } -StickerSetBox::Inner::Inner(QWidget *parent, const MTPInputStickerSet &set) : TWidget(parent) -, _input(set) { +StickerSetBox::Inner::Inner(QWidget *parent, const MTPInputStickerSet &set) + : TWidget(parent) + , _input(set) { switch (set.type()) { - case mtpc_inputStickerSetID: _setId = set.c_inputStickerSetID().vid.v; _setAccess = set.c_inputStickerSetID().vaccess_hash.v; break; + case mtpc_inputStickerSetID: + _setId = set.c_inputStickerSetID().vid.v; + _setAccess = set.c_inputStickerSetID().vaccess_hash.v; + break; case mtpc_inputStickerSetShortName: _setShortName = qs(set.c_inputStickerSetShortName().vshort_name); break; } MTP::send(MTPmessages_GetStickerSet(_input), rpcDone(&Inner::gotSet), rpcFail(&Inner::failedSet)); @@ -168,7 +175,9 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) { auto &sets = Global::RefStickerSets(); auto it = sets.find(_setId); if (it != sets.cend()) { - auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded | MTPDstickerSet_ClientFlag::f_unread | MTPDstickerSet_ClientFlag::f_special); + auto clientFlags = + it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded | + MTPDstickerSet_ClientFlag::f_unread | MTPDstickerSet_ClientFlag::f_special); _setFlags |= clientFlags; it->flags = _setFlags; it->stickers = _pack; @@ -180,8 +189,9 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) { if (_pack.isEmpty()) { Ui::show(Box(lang(lng_stickers_not_found))); } else { - int32 rows = _pack.size() / kStickersPanelPerRow + ((_pack.size() % kStickersPanelPerRow) ? 1 : 0); - resize(st::stickersPadding.left() + kStickersPanelPerRow * st::stickersSize.width(), st::stickersPadding.top() + rows * st::stickersSize.height() + st::stickersPadding.bottom()); + qint32 rows = _pack.size() / kStickersPanelPerRow + ((_pack.size() % kStickersPanelPerRow) ? 1 : 0); + resize(st::stickersPadding.left() + kStickersPanelPerRow * st::stickersSize.width(), + st::stickersPadding.top() + rows * st::stickersSize.height() + st::stickersPadding.bottom()); } _loaded = true; @@ -214,7 +224,8 @@ void StickerSetBox::Inner::installDone(const MTPmessages_StickerSetInstallResult _setFlags |= MTPDstickerSet::Flag::f_installed; auto it = sets.find(_setId); if (it == sets.cend()) { - it = sets.insert(_setId, Stickers::Set(_setId, _setAccess, _setTitle, _setShortName, _setCount, _setHash, _setFlags)); + it = sets.insert(_setId, + Stickers::Set(_setId, _setAccess, _setTitle, _setShortName, _setCount, _setHash, _setFlags)); } else { it->flags = _setFlags; } @@ -315,15 +326,17 @@ void StickerSetBox::Inner::setSelected(int selected) { } } -void StickerSetBox::Inner::startOverAnimation(int index, float64 from, float64 to) { +void StickerSetBox::Inner::startOverAnimation(int index, double from, double to) { if (index >= 0 && index < _packOvers.size()) { - _packOvers[index].start([this, index] { - int row = index / kStickersPanelPerRow; - int column = index % kStickersPanelPerRow; - int left = st::stickersPadding.left() + column * st::stickersSize.width(); - int top = st::stickersPadding.top() + row * st::stickersSize.height(); - rtlupdate(left, top, st::stickersSize.width(), st::stickersSize.height()); - }, from, to, st::emojiPanDuration); + _packOvers[index].start( + [this, index] { + int row = index / kStickersPanelPerRow; + int column = index % kStickersPanelPerRow; + int left = st::stickersPadding.left() + column * st::stickersSize.width(); + int top = st::stickersPadding.top() + row * st::stickersSize.height(); + rtlupdate(left, top, st::stickersSize.width(), st::stickersSize.height()); + }, + from, to, st::emojiPanDuration); } } @@ -335,13 +348,17 @@ void StickerSetBox::Inner::onPreview() { } } -int32 StickerSetBox::Inner::stickerFromGlobalPos(const QPoint &p) const { +qint32 StickerSetBox::Inner::stickerFromGlobalPos(const QPoint &p) const { QPoint l(mapFromGlobal(p)); if (rtl()) l.setX(width() - l.x()); - int32 row = (l.y() >= st::stickersPadding.top()) ? qFloor((l.y() - st::stickersPadding.top()) / st::stickersSize.height()) : -1; - int32 col = (l.x() >= st::stickersPadding.left()) ? qFloor((l.x() - st::stickersPadding.left()) / st::stickersSize.width()) : -1; + qint32 row = (l.y() >= st::stickersPadding.top()) ? + std::floor((l.y() - st::stickersPadding.top()) / st::stickersSize.height()) : + -1; + qint32 col = (l.x() >= st::stickersPadding.left()) ? + std::floor((l.x() - st::stickersPadding.left()) / st::stickersSize.width()) : + -1; if (row >= 0 && col >= 0 && col < kStickersPanelPerRow) { - int32 result = row * kStickersPanelPerRow + col; + qint32 result = row * kStickersPanelPerRow + col; return (result < _pack.size()) ? result : -1; } return -1; @@ -354,17 +371,18 @@ void StickerSetBox::Inner::paintEvent(QPaintEvent *e) { if (_pack.isEmpty()) return; auto ms = getms(); - int32 rows = _pack.size() / kStickersPanelPerRow + ((_pack.size() % kStickersPanelPerRow) ? 1 : 0); - int32 from = qFloor(e->rect().top() / st::stickersSize.height()), to = qFloor(e->rect().bottom() / st::stickersSize.height()) + 1; + qint32 from = std::floor(e->rect().top() / st::stickersSize.height()), + to = std::floor(e->rect().bottom() / st::stickersSize.height()) + 1; - for (int32 i = from; i < to; ++i) { - for (int32 j = 0; j < kStickersPanelPerRow; ++j) { - int32 index = i * kStickersPanelPerRow + j; + for (qint32 i = from; i < to; ++i) { + for (qint32 j = 0; j < kStickersPanelPerRow; ++j) { + qint32 index = i * kStickersPanelPerRow + j; if (index >= _pack.size()) break; Assert(index < _packOvers.size()); DocumentData *doc = _pack.at(index); - QPoint pos(st::stickersPadding.left() + j * st::stickersSize.width(), st::stickersPadding.top() + i * st::stickersSize.height()); + QPoint pos(st::stickersPadding.left() + j * st::stickersSize.width(), + st::stickersPadding.top() + i * st::stickersSize.height()); if (auto over = _packOvers[index].current(ms, (index == _selected) ? 1. : 0.)) { p.setOpacity(over); @@ -372,7 +390,6 @@ void StickerSetBox::Inner::paintEvent(QPaintEvent *e) { if (rtl()) tl.setX(width() - tl.x() - st::stickersSize.width()); App::roundRect(p, QRect(tl, st::stickersSize), st::emojiPanHover, StickerHoverCorners); p.setOpacity(1); - } bool goodThumb = !doc->thumb->isNull() && ((doc->thumb->width() >= 128) || (doc->thumb->height() >= 128)); if (goodThumb) { @@ -386,9 +403,11 @@ void StickerSetBox::Inner::paintEvent(QPaintEvent *e) { } } - float64 coef = qMin((st::stickersSize.width() - st::buttonRadius * 2) / float64(doc->dimensions.width()), (st::stickersSize.height() - st::buttonRadius * 2) / float64(doc->dimensions.height())); + double coef = + std::min((st::stickersSize.width() - st::buttonRadius * 2) / double(doc->dimensions.width()), + (st::stickersSize.height() - st::buttonRadius * 2) / double(doc->dimensions.height())); if (coef > 1) coef = 1; - int32 w = qRound(coef * doc->dimensions.width()), h = qRound(coef * doc->dimensions.height()); + qint32 w = std::round(coef * doc->dimensions.width()), h = std::round(coef * doc->dimensions.height()); if (w < 1) w = 1; if (h < 1) h = 1; QPoint ppos = pos + QPoint((st::stickersSize.width() - w) / 2, (st::stickersSize.height() - h) / 2); @@ -410,10 +429,12 @@ bool StickerSetBox::Inner::loaded() const { return _loaded && !_pack.isEmpty(); } -int32 StickerSetBox::Inner::notInstalled() const { +qint32 StickerSetBox::Inner::notInstalled() const { if (!_loaded) return 0; auto it = Global::StickerSets().constFind(_setId); - if (it == Global::StickerSets().cend() || !(it->flags & MTPDstickerSet::Flag::f_installed) || (it->flags & MTPDstickerSet::Flag::f_archived)) return _pack.size(); + if (it == Global::StickerSets().cend() || !(it->flags & MTPDstickerSet::Flag::f_installed) || + (it->flags & MTPDstickerSet::Flag::f_archived)) + return _pack.size(); return 0; } @@ -421,16 +442,16 @@ bool StickerSetBox::Inner::official() const { return _loaded && _setShortName.isEmpty(); } -base::lambda StickerSetBox::Inner::title() const { - auto text = TextWithEntities { _setTitle }; +Fn StickerSetBox::Inner::title() const { + auto text = TextWithEntities{_setTitle}; if (_loaded) { if (_pack.isEmpty()) { - return [] { return TextWithEntities { lang(lng_attach_failed), EntitiesInText() }; }; + return [] { return TextWithEntities{lang(lng_attach_failed), EntitiesInText()}; }; } else { TextUtilities::ParseEntities(text, TextParseMentions); } } else { - return [] { return TextWithEntities { lang(lng_contacts_loading), EntitiesInText() }; }; + return [] { return TextWithEntities{lang(lng_contacts_loading), EntitiesInText()}; }; } return [text] { return text; }; } @@ -445,8 +466,8 @@ void StickerSetBox::Inner::install() { return; } if (_installRequest) return; - _installRequest = MTP::send(MTPmessages_InstallStickerSet(_input, MTP_bool(false)), rpcDone(&Inner::installDone), rpcFail(&Inner::installFail)); + _installRequest = MTP::send(MTPmessages_InstallStickerSet(_input, MTP_bool(false)), rpcDone(&Inner::installDone), + rpcFail(&Inner::installFail)); } -StickerSetBox::Inner::~Inner() { -} +StickerSetBox::Inner::~Inner() {} diff --git a/Telegram/SourceFiles/boxes/sticker_set_box.h b/Telegram/SourceFiles/boxes/sticker_set_box.h index 064f5abab..fa10c676a 100644 --- a/Telegram/SourceFiles/boxes/sticker_set_box.h +++ b/Telegram/SourceFiles/boxes/sticker_set_box.h @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "boxes/abstract_box.h" @@ -33,10 +35,10 @@ class StickerSetBox : public BoxContent, public RPCSender { Q_OBJECT public: - StickerSetBox(QWidget*, const MTPInputStickerSet &set); + StickerSetBox(QWidget *, const MTPInputStickerSet &set); signals: - void installed(uint64 id); + void installed(quint64 id); protected: void prepare() override; @@ -48,7 +50,7 @@ private slots: void onShareStickers(); void onUpdateButtons(); - void onInstalled(uint64 id); + void onInstalled(quint64 id); private: void updateButtons(); @@ -57,7 +59,6 @@ private slots: class Inner; QPointer _inner; - }; // This class is hold in header because it requires Qt preprocessing. @@ -68,9 +69,9 @@ class StickerSetBox::Inner : public TWidget, public RPCSender, private base::Sub Inner(QWidget *parent, const MTPInputStickerSet &set); bool loaded() const; - int32 notInstalled() const; + qint32 notInstalled() const; bool official() const; - base::lambda title() const; + Fn title() const; QString shortName() const; void setVisibleTopBottom(int visibleTop, int visibleBottom) override; @@ -90,12 +91,12 @@ private slots: signals: void updateButtons(); - void installed(uint64 id); + void installed(quint64 id); private: void updateSelected(); void setSelected(int selected); - void startOverAnimation(int index, float64 from, float64 to); + void startOverAnimation(int index, double from, double to); int stickerFromGlobalPos(const QPoint &p) const; void gotSet(const MTPmessages_StickerSet &set); @@ -112,11 +113,11 @@ private slots: StickerPack _pack; StickersByEmojiMap _emoji; bool _loaded = false; - uint64 _setId = 0; - uint64 _setAccess = 0; + quint64 _setId = 0; + quint64 _setAccess = 0; QString _setTitle, _setShortName; - int32 _setCount = 0; - int32 _setHash = 0; + qint32 _setCount = 0; + qint32 _setHash = 0; MTPDstickerSet::Flags _setFlags = 0; int _visibleTop = 0; @@ -129,5 +130,4 @@ private slots: QTimer _previewTimer; int _previewShown = -1; - }; diff --git a/Telegram/SourceFiles/boxes/stickers_box.cpp b/Telegram/SourceFiles/boxes/stickers_box.cpp index 98779482a..6033001ac 100644 --- a/Telegram/SourceFiles/boxes/stickers_box.cpp +++ b/Telegram/SourceFiles/boxes/stickers_box.cpp @@ -1,44 +1,46 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "stickers_box.h" -#include "lang/lang_keys.h" -#include "mainwidget.h" -#include "chat_helpers/stickers.h" +#include "apiwrap.h" +#include "auth_session.h" #include "boxes/confirm_box.h" #include "boxes/sticker_set_box.h" -#include "apiwrap.h" -#include "storage/localstorage.h" +#include "chat_helpers/stickers.h" #include "dialogs/dialogs_layout.h" +#include "lang/lang_keys.h" +#include "mainwidget.h" +#include "messenger.h" +#include "storage/localstorage.h" #include "styles/style_boxes.h" #include "styles/style_chat_helpers.h" -#include "ui/widgets/buttons.h" -#include "ui/widgets/labels.h" -#include "ui/widgets/scroll_area.h" #include "ui/effects/ripple_animation.h" #include "ui/effects/slide_animation.h" +#include "ui/widgets/buttons.h" #include "ui/widgets/discrete_sliders.h" #include "ui/widgets/input_fields.h" -#include "auth_session.h" -#include "messenger.h" +#include "ui/widgets/labels.h" +#include "ui/widgets/scroll_area.h" namespace { @@ -55,7 +57,8 @@ int stickerPacksCount(bool includeArchivedOfficial) { for (auto i = 0, l = order.size(); i < l; ++i) { auto it = sets.constFind(order.at(i)); if (it != sets.cend()) { - if (!(it->flags & MTPDstickerSet::Flag::f_archived) || ((it->flags & MTPDstickerSet::Flag::f_official) && includeArchivedOfficial)) { + if (!(it->flags & MTPDstickerSet::Flag::f_archived) || + ((it->flags & MTPDstickerSet::Flag::f_official) && includeArchivedOfficial)) { ++result; } } @@ -77,10 +80,10 @@ class StickersBox::CounterWidget : public TWidget, private base::Subscriber { QString _text; Dialogs::Layout::UnreadBadgeStyle _st; - }; -StickersBox::CounterWidget::CounterWidget(QWidget *parent) : TWidget(parent) { +StickersBox::CounterWidget::CounterWidget(QWidget *parent) + : TWidget(parent) { setAttribute(Qt::WA_TransparentForMouseEvents); _st.sizeId = Dialogs::Layout::UnreadBadgeInStickersBox; @@ -119,12 +122,11 @@ void StickersBox::CounterWidget::updateCounter() { update(); } -template -StickersBox::Tab::Tab(int index, Args&&... args) -: _index(index) -, _widget(std::forward(args)...) -, _weak(_widget) { -} +template +StickersBox::Tab::Tab(int index, Args &&... args) + : _index(index) + , _widget(std::forward(args)...) + , _weak(_widget) {} object_ptr StickersBox::Tab::takeWidget() { return std::move(_widget); @@ -139,24 +141,24 @@ void StickersBox::Tab::saveScrollTop() { _scrollTop = widget()->getVisibleTop(); } -StickersBox::StickersBox(QWidget*, Section section) -: _tabs(this, st::stickersTabs) -, _unreadBadge(this) -, _section(section) -, _installed(0, this, Section::Installed) -, _featured(1, this, Section::Featured) -, _archived(2, this, Section::Archived) { +StickersBox::StickersBox(QWidget *, Section section) + : _tabs(this, st::stickersTabs) + , _unreadBadge(this) + , _section(section) + , _installed(0, this, Section::Installed) + , _featured(1, this, Section::Featured) + , _archived(2, this, Section::Archived) { _tabs->setRippleTopRoundRadius(st::boxRadius); } -StickersBox::StickersBox(QWidget*, not_null megagroup) -: _section(Section::Installed) -, _installed(0, this, megagroup) -, _megagroupSet(megagroup) { +StickersBox::StickersBox(QWidget *, not_null megagroup) + : _section(Section::Installed) + , _installed(0, this, megagroup) + , _megagroupSet(megagroup) { subscribe(_installed.widget()->scrollToY, [this](int y) { onScrollToY(y); }); } -void StickersBox::getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedStickers &result) { +void StickersBox::getArchivedDone(quint64 offsetId, const MTPmessages_ArchivedStickers &result) { _archivedRequestId = 0; _archivedLoaded = true; if (result.type() != mtpc_messages_archivedStickers) { @@ -243,9 +245,7 @@ void StickersBox::prepare() { preloadArchivedSets(); } setNoContentMargin(true); - _tabs->setSectionActivatedCallback([this] { - switchTab(); - }); + _tabs->setSectionActivatedCallback([this] { switchTab(); }); refreshTabs(); } if (_installed.widget() && _section != Section::Installed) _installed.widget()->hide(); @@ -253,15 +253,18 @@ void StickersBox::prepare() { if (_archived.widget() && _section != Section::Archived) _archived.widget()->hide(); if (_featured.widget()) { - _featured.widget()->setInstallSetCallback([this](uint64 setId) { installSet(setId); }); + _featured.widget()->setInstallSetCallback([this](quint64 setId) { installSet(setId); }); } if (_archived.widget()) { - _archived.widget()->setInstallSetCallback([this](uint64 setId) { installSet(setId); }); + _archived.widget()->setInstallSetCallback([this](quint64 setId) { installSet(setId); }); _archived.widget()->setLoadMoreCallback([this] { loadMoreArchived(); }); } if (_megagroupSet) { - addButton(langFactory(lng_settings_save), [this] { _installed.widget()->saveGroupSet(); closeBox(); }); + addButton(langFactory(lng_settings_save), [this] { + _installed.widget()->saveGroupSet(); + closeBox(); + }); addButton(langFactory(lng_cancel), [this] { closeBox(); }); } else { addButton(langFactory(lng_about_done), [this] { closeBox(); }); @@ -310,8 +313,8 @@ void StickersBox::refreshTabs() { _tabIndices.push_back(Section::Archived); } _tabs->setSections(sections); - if ((_tab == &_archived && !_tabIndices.contains(Section::Archived)) - || (_tab == &_featured && !_tabIndices.contains(Section::Featured))) { + if ((_tab == &_archived && !_tabIndices.contains(Section::Archived)) || + (_tab == &_featured && !_tabIndices.contains(Section::Featured))) { switchTab(); } else if (_tab == &_archived) { _tabs->setActiveSectionFast(_tabIndices.indexOf(Section::Archived)); @@ -326,8 +329,9 @@ void StickersBox::loadMoreArchived() { return; } - uint64 lastId = 0; - for (auto setIt = Global::ArchivedStickerSetsOrder().cend(), e = Global::ArchivedStickerSetsOrder().cbegin(); setIt != e;) { + quint64 lastId = 0; + for (auto setIt = Global::ArchivedStickerSetsOrder().cend(), e = Global::ArchivedStickerSetsOrder().cbegin(); + setIt != e;) { --setIt; auto it = Global::StickerSets().constFind(*setIt); if (it != Global::StickerSets().cend()) { @@ -337,7 +341,9 @@ void StickersBox::loadMoreArchived() { } } } - _archivedRequestId = MTP::send(MTPmessages_GetArchivedStickers(MTP_flags(0), MTP_long(lastId), MTP_int(kArchivedLimitPerPage)), rpcDone(&StickersBox::getArchivedDone, lastId)); + _archivedRequestId = + MTP::send(MTPmessages_GetArchivedStickers(MTP_flags(0), MTP_long(lastId), MTP_int(kArchivedLimitPerPage)), + rpcDone(&StickersBox::getArchivedDone, lastId)); } void StickersBox::paintEvent(QPaintEvent *e) { @@ -441,7 +447,7 @@ QPixmap StickersBox::grabContentCache() { return result; } -void StickersBox::installSet(uint64 setId) { +void StickersBox::installSet(quint64 setId) { auto &sets = Global::RefStickerSets(); auto it = sets.find(setId); if (it == sets.cend()) { @@ -456,7 +462,8 @@ void StickersBox::installSet(uint64 setId) { _archived.widget()->setRemovedSets(_localRemoved); } if (!(it->flags & MTPDstickerSet::Flag::f_installed) || (it->flags & MTPDstickerSet::Flag::f_archived)) { - MTP::send(MTPmessages_InstallStickerSet(Stickers::inputSetId(*it), MTP_boolFalse()), rpcDone(&StickersBox::installDone), rpcFail(&StickersBox::installFail, setId)); + MTP::send(MTPmessages_InstallStickerSet(Stickers::inputSetId(*it), MTP_boolFalse()), + rpcDone(&StickersBox::installDone), rpcFail(&StickersBox::installFail, setId)); Stickers::InstallLocally(setId); } @@ -468,7 +475,7 @@ void StickersBox::installDone(const MTPmessages_StickerSetInstallResult &result) } } -bool StickersBox::installFail(uint64 setId, const RPCError &error) { +bool StickersBox::installFail(quint64 setId, const RPCError &error) { if (MTP::isDefaultHandledError(error)) return false; auto &sets = Global::RefStickerSets(); @@ -485,7 +492,9 @@ bool StickersBox::installFail(uint64 setId, const RPCError &error) { void StickersBox::preloadArchivedSets() { if (!_tabs) return; if (!_archivedRequestId) { - _archivedRequestId = MTP::send(MTPmessages_GetArchivedStickers(MTP_flags(0), MTP_long(0), MTP_int(kArchivedLimitFirstRequest)), rpcDone(&StickersBox::getArchivedDone, 0ULL)); + _archivedRequestId = + MTP::send(MTPmessages_GetArchivedStickers(MTP_flags(0), MTP_long(0), MTP_int(kArchivedLimitFirstRequest)), + rpcDone(&StickersBox::getArchivedDone, Q_UINT64_C(0))); } } @@ -568,49 +577,57 @@ void StickersBox::setInnerFocus() { StickersBox::~StickersBox() = default; -StickersBox::Inner::Row::Row(uint64 id, DocumentData *sticker, int32 count, const QString &title, int titleWidth, bool installed, bool official, bool unread, bool archived, bool removed, int32 pixw, int32 pixh) : id(id) -, sticker(sticker) -, count(count) -, title(title) -, titleWidth(titleWidth) -, installed(installed) -, official(official) -, unread(unread) -, archived(archived) -, removed(removed) -, pixw(pixw) -, pixh(pixh) { -} +StickersBox::Inner::Row::Row(quint64 id, DocumentData *sticker, qint32 count, const QString &title, int titleWidth, + bool installed, bool official, bool unread, bool archived, bool removed, qint32 pixw, + qint32 pixh) + : id(id) + , sticker(sticker) + , count(count) + , title(title) + , titleWidth(titleWidth) + , installed(installed) + , official(official) + , unread(unread) + , archived(archived) + , removed(removed) + , pixw(pixw) + , pixh(pixh) {} StickersBox::Inner::Row::~Row() = default; -StickersBox::Inner::Inner(QWidget *parent, StickersBox::Section section) : TWidget(parent) -, _section(section) -, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) -, _a_shifting(animation(this, &Inner::step_shifting)) -, _itemsTop(st::membersMarginTop) -, _addText(lang(lng_stickers_featured_add).toUpper()) -, _addWidth(st::stickersTrendingAdd.font->width(_addText)) -, _undoText(lang(lng_stickers_return).toUpper()) -, _undoWidth(st::stickersUndoRemove.font->width(_undoText)) { +StickersBox::Inner::Inner(QWidget *parent, StickersBox::Section section) + : TWidget(parent) + , _section(section) + , _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) + , _a_shifting(animation(this, &Inner::step_shifting)) + , _itemsTop(st::membersMarginTop) + , _addText(lang(lng_stickers_featured_add).toUpper()) + , _addWidth(st::stickersTrendingAdd.font->width(_addText)) + , _undoText(lang(lng_stickers_return).toUpper()) + , _undoWidth(st::stickersUndoRemove.font->width(_undoText)) { setup(); } -StickersBox::Inner::Inner(QWidget *parent, not_null megagroup) : TWidget(parent) -, _section(StickersBox::Section::Installed) -, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) -, _a_shifting(animation(this, &Inner::step_shifting)) -, _itemsTop(st::membersMarginTop) -, _megagroupSet(megagroup) -, _megagroupSetInput(_megagroupSet->mgInfo->stickerSet) -, _megagroupSetField(this, st::groupStickersField, [] { return qsl("stickerset"); }, QString(), true) -, _megagroupDivider(this) -, _megagroupSubTitle(this, lang(lng_stickers_group_from_your), Ui::FlatLabel::InitType::Simple, st::boxTitle) { +StickersBox::Inner::Inner(QWidget *parent, not_null megagroup) + : TWidget(parent) + , _section(StickersBox::Section::Installed) + , _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) + , _a_shifting(animation(this, &Inner::step_shifting)) + , _itemsTop(st::membersMarginTop) + , _megagroupSet(megagroup) + , _megagroupSetInput(_megagroupSet->mgInfo->stickerSet) + , _megagroupSetField(this, st::groupStickersField, [] { return qsl("stickerset"); }, QString(), true) + , _megagroupDivider(this) + , _megagroupSubTitle(this, lang(lng_stickers_group_from_your), Ui::FlatLabel::InitType::Simple, st::boxTitle) { _megagroupSetField->setLinkPlaceholder(Messenger::Instance().createInternalLink(qsl("addstickers/"))); _megagroupSetField->setPlaceholderHidden(false); _megagroupSetAddressChangedTimer.setCallback([this] { handleMegagroupSetAddressChange(); }); - connect(_megagroupSetField, &Ui::MaskedInputField::changed, this, [this] { _megagroupSetAddressChangedTimer.callOnce(kHandleMegagroupSetAddressChangeTimeout); }); - connect(_megagroupSetField, &Ui::MaskedInputField::submitted, this, [this] { _megagroupSetAddressChangedTimer.cancel(); handleMegagroupSetAddressChange(); }); + connect(_megagroupSetField, &Ui::MaskedInputField::changed, this, + [this] { _megagroupSetAddressChangedTimer.callOnce(kHandleMegagroupSetAddressChangeTimeout); }); + connect(_megagroupSetField, &Ui::MaskedInputField::submitted, this, [this] { + _megagroupSetAddressChangedTimer.cancel(); + handleMegagroupSetAddressChange(); + }); setup(); } @@ -654,11 +671,11 @@ void StickersBox::Inner::paintEvent(QPaintEvent *e) { } else { p.translate(0, _itemsTop); - int32 yFrom = clip.y() - _itemsTop, yTo = clip.y() + clip.height() - _itemsTop; - int32 from = floorclamp(yFrom - _rowHeight, _rowHeight, 0, _rows.size()); - int32 to = ceilclamp(yTo + _rowHeight, _rowHeight, 0, _rows.size()); + qint32 yFrom = clip.y() - _itemsTop, yTo = clip.y() + clip.height() - _itemsTop; + qint32 from = floorclamp(yFrom - _rowHeight, _rowHeight, 0, _rows.size()); + qint32 to = ceilclamp(yTo + _rowHeight, _rowHeight, 0, _rows.size()); p.translate(0, from * _rowHeight); - for (int32 i = from; i < to; ++i) { + for (qint32 i = from; i < to; ++i) { if (i != _above) { paintRow(p, _rows[i].get(), i, ms); } @@ -679,12 +696,14 @@ void StickersBox::Inner::updateControlsGeometry() { if (_megagroupSet) { auto top = st::groupStickersFieldPadding.top(); auto fieldLeft = st::boxLayerTitlePosition.x(); - _megagroupSetField->setGeometryToLeft(fieldLeft, top, width() - fieldLeft - st::groupStickersFieldPadding.right(), _megagroupSetField->height()); + _megagroupSetField->setGeometryToLeft( + fieldLeft, top, width() - fieldLeft - st::groupStickersFieldPadding.right(), _megagroupSetField->height()); top += _megagroupSetField->height() + st::groupStickersFieldPadding.bottom(); if (_megagroupSelectedRemove) { _megagroupSelectedShadow->setGeometryToLeft(0, top, width(), st::lineWidth); top += st::lineWidth; - _megagroupSelectedRemove->moveToRight(st::groupStickersRemovePosition.x(), top + st::groupStickersRemovePosition.y()); + _megagroupSelectedRemove->moveToRight(st::groupStickersRemovePosition.x(), + top + st::groupStickersRemovePosition.y()); top += _rowHeight; } _megagroupDivider->setGeometryToLeft(0, top, width(), _megagroupDivider->height()); @@ -710,7 +729,7 @@ QRect StickersBox::Inner::relativeButtonRect(bool removeButton) const { } void StickersBox::Inner::paintRow(Painter &p, Row *set, int index, TimeMs ms) { - auto xadd = 0, yadd = qRound(set->yadd.current()); + int xadd = 0, yadd = std::round(set->yadd.current()); if (xadd || yadd) p.translate(xadd, yadd); if (_megagroupSet) { @@ -732,7 +751,10 @@ void StickersBox::Inner::paintRow(Painter &p, Row *set, int index, TimeMs ms) { current = reachedOpacity; } } - auto row = myrtlrect(st::contactsPadding.left() / 2, st::contactsPadding.top() / 2, width() - (st::contactsPadding.left() / 2) - _scrollbar - st::contactsPadding.left() / 2, _rowHeight - ((st::contactsPadding.top() + st::contactsPadding.bottom()) / 2)); + auto row = + myrtlrect(st::contactsPadding.left() / 2, st::contactsPadding.top() / 2, + width() - (st::contactsPadding.left() / 2) - _scrollbar - st::contactsPadding.left() / 2, + _rowHeight - ((st::contactsPadding.top() + st::contactsPadding.bottom()) / 2)); p.setOpacity(current); Ui::Shadow::paint(p, row, width(), st::boxRoundShadow); p.setOpacity(1); @@ -758,14 +780,16 @@ void StickersBox::Inner::paintRow(Painter &p, Row *set, int index, TimeMs ms) { if (!_megagroupSet && _section == Section::Installed) { stickerx += st::stickersReorderIcon.width() + st::stickersReorderSkip; if (!set->isRecentSet()) { - st::stickersReorderIcon.paint(p, st::contactsPadding.left(), (_rowHeight - st::stickersReorderIcon.height()) / 2, width()); + st::stickersReorderIcon.paint(p, st::contactsPadding.left(), + (_rowHeight - st::stickersReorderIcon.height()) / 2, width()); } } if (set->sticker) { set->sticker->thumb->load(); auto pix = set->sticker->thumb->pix(set->pixw, set->pixh); - p.drawPixmapLeft(stickerx + (st::contactsPhotoSize - set->pixw) / 2, st::contactsPadding.top() + (st::contactsPhotoSize - set->pixh) / 2, width(), pix); + p.drawPixmapLeft(stickerx + (st::contactsPhotoSize - set->pixw) / 2, + st::contactsPadding.top() + (st::contactsPhotoSize - set->pixh) / 2, width(), pix); } int namex = stickerx + st::contactsPhotoSize + st::contactsPadding.left(); @@ -784,7 +808,9 @@ void StickersBox::Inner::paintRow(Painter &p, Row *set, int index, TimeMs ms) { { PainterHighQualityEnabler hq(p); - p.drawEllipse(rtlrect(namex + set->titleWidth + st::stickersFeaturedUnreadSkip, namey + st::stickersFeaturedUnreadTop, st::stickersFeaturedUnreadSize, st::stickersFeaturedUnreadSize, width())); + p.drawEllipse(rtlrect(namex + set->titleWidth + st::stickersFeaturedUnreadSkip, + namey + st::stickersFeaturedUnreadTop, st::stickersFeaturedUnreadSize, + st::stickersFeaturedUnreadSize, width())); } } @@ -803,7 +829,8 @@ void StickersBox::Inner::paintFakeButton(Painter &p, Row *set, int index, TimeMs auto rect = relativeButtonRect(removeButton); if (_section != Section::Installed && set->installed && !set->archived && !set->removed) { // Checkbox after installed from Trending or Archived. - int checkx = width() - (st::contactsPadding.right() + st::contactsCheckPosition.x() + (rect.width() + st::stickersFeaturedInstalled.width()) / 2); + int checkx = width() - (st::contactsPadding.right() + st::contactsCheckPosition.x() + + (rect.width() + st::stickersFeaturedInstalled.width()) / 2); int checky = st::contactsPadding.top() + (st::contactsPhotoSize - st::stickersFeaturedInstalled.height()) / 2; st::stickersFeaturedInstalled.paint(p, QPoint(checkx, checky), width()); } else { @@ -892,7 +919,8 @@ void StickersBox::Inner::setActionDown(int newActionDown) { } if (set->ripple) { auto rect = relativeButtonRect(removeButton); - set->ripple->add(mapFromGlobal(QCursor::pos()) - QPoint(myrtlrect(rect).x(), _itemsTop + _actionDown * _rowHeight + rect.y())); + set->ripple->add(mapFromGlobal(QCursor::pos()) - + QPoint(myrtlrect(rect).x(), _itemsTop + _actionDown * _rowHeight + rect.y())); } } } @@ -926,19 +954,20 @@ void StickersBox::Inner::setPressed(int pressed) { update(0, _itemsTop + _pressed * _rowHeight, width(), _rowHeight); auto &set = _rows[_pressed]; auto rippleMask = Ui::RippleAnimation::rectMask(QSize(width(), _rowHeight)); - if (!_rows[_pressed]->ripple) { - _rows[_pressed]->ripple = std::make_unique(st::contactsRipple, std::move(rippleMask), [this, index = _pressed] { - update(0, _itemsTop + index * _rowHeight, width(), _rowHeight); - }); + if (!set->ripple) { + set->ripple = std::make_unique( + st::contactsRipple, std::move(rippleMask), + [this, index = _pressed] { update(0, _itemsTop + index * _rowHeight, width(), _rowHeight); }); } - _rows[_pressed]->ripple->add(mapFromGlobal(QCursor::pos()) - QPoint(0, _itemsTop + _pressed * _rowHeight)); + set->ripple->add(mapFromGlobal(QCursor::pos()) - QPoint(0, _itemsTop + _pressed * _rowHeight)); } } void StickersBox::Inner::ensureRipple(const style::RippleAnimation &st, QImage mask, bool removeButton) { - _rows[_actionDown]->ripple = std::make_unique(st, std::move(mask), [this, index = _actionDown, removeButton] { - update(myrtlrect(relativeButtonRect(removeButton).translated(0, _itemsTop + index * _rowHeight))); - }); + _rows[_actionDown]->ripple = + std::make_unique(st, std::move(mask), [this, index = _actionDown, removeButton] { + update(myrtlrect(relativeButtonRect(removeButton).translated(0, _itemsTop + index * _rowHeight))); + }); } void StickersBox::Inner::mouseMoveEvent(QMouseEvent *e) { @@ -956,15 +985,17 @@ void StickersBox::Inner::onUpdateSelected() { ++firstSetIndex; } if (_dragStart.y() > local.y() && _dragging > 0) { - shift = -floorclamp(_dragStart.y() - local.y() + (_rowHeight / 2), _rowHeight, 0, _dragging - firstSetIndex); - for (int32 from = _dragging, to = _dragging + shift; from > to; --from) { + shift = + -floorclamp(_dragStart.y() - local.y() + (_rowHeight / 2), _rowHeight, 0, _dragging - firstSetIndex); + for (qint32 from = _dragging, to = _dragging + shift; from > to; --from) { qSwap(_rows[from], _rows[from - 1]); _rows[from]->yadd = anim::value(_rows[from]->yadd.current() - _rowHeight, 0); _animStartTimes[from] = ms; } } else if (_dragStart.y() < local.y() && _dragging + 1 < _rows.size()) { - shift = floorclamp(local.y() - _dragStart.y() + (_rowHeight / 2), _rowHeight, 0, _rows.size() - _dragging - 1); - for (int32 from = _dragging, to = _dragging + shift; from < to; ++from) { + shift = + floorclamp(local.y() - _dragStart.y() + (_rowHeight / 2), _rowHeight, 0, _rows.size() - _dragging - 1); + for (qint32 from = _dragging, to = _dragging + shift; from < to; ++from) { qSwap(_rows[from], _rows[from + 1]); _rows[from]->yadd = anim::value(_rows[from]->yadd.current() + _rowHeight, 0); _animStartTimes[from] = ms; @@ -1001,7 +1032,8 @@ void StickersBox::Inner::onUpdateSelected() { selected = floorclamp(local.y() - _itemsTop, _rowHeight, 0, _rows.size() - 1); local.setY(local.y() - _itemsTop - selected * _rowHeight); auto &set = _rows[selected]; - if (!_megagroupSet && (_section == Section::Installed || !set->installed || set->archived || set->removed)) { + if (!_megagroupSet && + (_section == Section::Installed || !set->installed || set->archived || set->removed)) { auto removeButton = (_section == Section::Installed && !set->removed); auto rect = myrtlrect(relativeButtonRect(removeButton)); actionSel = rect.contains(local) ? selected : -1; @@ -1009,7 +1041,8 @@ void StickersBox::Inner::onUpdateSelected() { actionSel = -1; } if (!_megagroupSet && _section == Section::Installed && !set->isRecentSet()) { - auto dragAreaWidth = st::contactsPadding.left() + st::stickersReorderIcon.width() + st::stickersReorderSkip; + auto dragAreaWidth = + st::contactsPadding.left() + st::stickersReorderIcon.width() + st::stickersReorderSkip; auto dragArea = myrtlrect(0, 0, dragAreaWidth, _rowHeight); inDragArea = dragArea.contains(local); } @@ -1017,7 +1050,8 @@ void StickersBox::Inner::onUpdateSelected() { selected = -1; } if (_selected != selected) { - if ((_megagroupSet || _section != Section::Installed) && ((_selected >= 0 || _pressed >= 0) != (selected >= 0 || _pressed >= 0))) { + if ((_megagroupSet || _section != Section::Installed) && + ((_selected >= 0 || _pressed >= 0) != (selected >= 0 || _pressed >= 0))) { if (!inDragArea) { setCursor((selected >= 0 || _pressed >= 0) ? style::cur_pointer : style::cur_default); } @@ -1026,19 +1060,20 @@ void StickersBox::Inner::onUpdateSelected() { } if (_inDragArea != inDragArea) { _inDragArea = inDragArea; - setCursor(_inDragArea ? style::cur_sizeall : (_selected >= 0 || _pressed >= 0) ? style::cur_pointer : style::cur_default); + setCursor(_inDragArea ? style::cur_sizeall : + (_selected >= 0 || _pressed >= 0) ? style::cur_pointer : style::cur_default); } setActionSel(actionSel); emit draggingScrollDelta(0); } } -float64 StickersBox::Inner::aboveShadowOpacity() const { +double StickersBox::Inner::aboveShadowOpacity() const { if (_above < 0) return 0; auto dx = 0; - auto dy = qAbs(_above * _rowHeight + qRound(_rows[_above]->yadd.current()) - _started * _rowHeight); - return qMin((dx + dy) * 2. / _rowHeight, 1.); + auto dy = qAbs(_above * _rowHeight + std::round(_rows[_above]->yadd.current()) - _started * _rowHeight); + return std::min((dx + dy) * 2. / _rowHeight, 1.); } void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) { @@ -1088,8 +1123,11 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) { void StickersBox::Inner::saveGroupSet() { Expects(_megagroupSet != nullptr); - auto oldId = (_megagroupSet->mgInfo->stickerSet.type() == mtpc_inputStickerSetID) ? _megagroupSet->mgInfo->stickerSet.c_inputStickerSetID().vid.v : 0; - auto newId = (_megagroupSetInput.type() == mtpc_inputStickerSetID) ? _megagroupSetInput.c_inputStickerSetID().vid.v : 0; + auto oldId = (_megagroupSet->mgInfo->stickerSet.type() == mtpc_inputStickerSetID) ? + _megagroupSet->mgInfo->stickerSet.c_inputStickerSetID().vid.v : + 0; + auto newId = + (_megagroupSetInput.type() == mtpc_inputStickerSetID) ? _megagroupSetInput.c_inputStickerSetID().vid.v : 0; if (newId != oldId) { Auth().api().setGroupStickerSet(_megagroupSet, _megagroupSetInput); App::main()->onStickersInstalled(Stickers::MegagroupSetId); @@ -1126,7 +1164,7 @@ void StickersBox::Inner::step_shifting(TimeMs ms, bool timer) { if (updateMin < 0) updateMin = i; updateMax = i; if (start + st::stickersRowDuration > ms && ms >= start) { - _rows[i]->yadd.update(float64(ms - start) / st::stickersRowDuration, anim::sineInOut); + _rows[i]->yadd.update(double(ms - start) / st::stickersRowDuration, anim::sineInOut); animating = true; } else { _rows[i]->yadd.finish(); @@ -1138,7 +1176,8 @@ void StickersBox::Inner::step_shifting(TimeMs ms, bool timer) { if (updateMin < 0 || updateMin > _above) updateMin = _above; if (updateMax < _above) updateMin = _above; if (_aboveShadowFadeStart + st::stickersRowDuration > ms && ms > _aboveShadowFadeStart) { - _aboveShadowFadeOpacity.update(float64(ms - _aboveShadowFadeStart) / st::stickersRowDuration, anim::sineInOut); + _aboveShadowFadeOpacity.update(double(ms - _aboveShadowFadeStart) / st::stickersRowDuration, + anim::sineInOut); animating = true; } else { _aboveShadowFadeOpacity.finish(); @@ -1179,13 +1218,14 @@ void StickersBox::Inner::clear() { update(); } -void StickersBox::Inner::setActionSel(int32 actionSel) { +void StickersBox::Inner::setActionSel(qint32 actionSel) { if (actionSel != _actionSel) { if (_actionSel >= 0) update(0, _itemsTop + _actionSel * _rowHeight, width(), _rowHeight); _actionSel = actionSel; if (_actionSel >= 0) update(0, _itemsTop + _actionSel * _rowHeight, width(), _rowHeight); if (_section == Section::Installed) { - setCursor((_actionSel >= 0 && (_actionDown < 0 || _actionDown == _actionSel)) ? style::cur_pointer : style::cur_default); + setCursor((_actionSel >= 0 && (_actionDown < 0 || _actionDown == _actionSel)) ? style::cur_pointer : + style::cur_default); } } } @@ -1200,14 +1240,18 @@ void StickersBox::Inner::handleMegagroupSetAddressChange() { } } } else if (!_megagroupSetRequestId) { - _megagroupSetRequestId = request(MTPmessages_GetStickerSet(MTP_inputStickerSetShortName(MTP_string(text)))).done([this](const MTPmessages_StickerSet &result) { - _megagroupSetRequestId = 0; - auto set = Stickers::FeedSetFull(result); - setMegagroupSelectedSet(MTP_inputStickerSetID(MTP_long(set->id), MTP_long(set->access))); - }).fail([this](const RPCError &error) { - _megagroupSetRequestId = 0; - setMegagroupSelectedSet(MTP_inputStickerSetEmpty()); - }).send(); + _megagroupSetRequestId = + request(MTPmessages_GetStickerSet(MTP_inputStickerSetShortName(MTP_string(text)))) + .done([this](const MTPmessages_StickerSet &result) { + _megagroupSetRequestId = 0; + auto set = Stickers::FeedSetFull(result); + setMegagroupSelectedSet(MTP_inputStickerSetID(MTP_long(set->id), MTP_long(set->access))); + }) + .fail([this](const RPCError &error) { + _megagroupSetRequestId = 0; + setMegagroupSelectedSet(MTP_inputStickerSetEmpty()); + }) + .send(); } else { _megagroupSetAddressChangedTimer.callOnce(kHandleMegagroupSetAddressChangeTimeout); } @@ -1238,7 +1282,7 @@ void StickersBox::Inner::rebuildMegagroupSet() { auto titleWidth = 0; auto title = fillSetTitle(*it, maxNameWidth, &titleWidth); auto count = fillSetCount(*it); - auto sticker = (DocumentData*)nullptr; + auto sticker = (DocumentData *)nullptr; auto pixw = 0, pixh = 0; fillSetCover(*it, &sticker, &pixw, &pixh); auto installed = true, official = false, unread = false, archived = false, removed = false; @@ -1246,15 +1290,14 @@ void StickersBox::Inner::rebuildMegagroupSet() { _megagroupSetField->setText(it->shortName); _megagroupSetField->finishAnimations(); } - _megagroupSelectedSet = std::make_unique(it->id, sticker, count, title, titleWidth, installed, official, unread, archived, removed, pixw, pixh); + _megagroupSelectedSet = std::make_unique(it->id, sticker, count, title, titleWidth, installed, official, + unread, archived, removed, pixw, pixh); _itemsTop += st::lineWidth + _rowHeight; if (!_megagroupSelectedRemove) { _megagroupSelectedRemove.create(this, st::groupStickersRemove); _megagroupSelectedRemove->showFast(); - _megagroupSelectedRemove->setClickedCallback([this] { - setMegagroupSelectedSet(MTP_inputStickerSetEmpty()); - }); + _megagroupSelectedRemove->setClickedCallback([this] { setMegagroupSelectedSet(MTP_inputStickerSetEmpty()); }); _megagroupSelectedShadow.create(this); updateControlsGeometry(); } @@ -1264,7 +1307,8 @@ void StickersBox::Inner::rebuild() { _itemsTop = st::membersMarginTop; if (_megagroupSet) { - _itemsTop += st::groupStickersFieldPadding.top() + _megagroupSetField->height() + st::groupStickersFieldPadding.bottom(); + _itemsTop += + st::groupStickersFieldPadding.top() + _megagroupSetField->height() + st::groupStickersFieldPadding.bottom(); _itemsTop += _megagroupDivider->height() + st::groupStickersSubTitleHeight; rebuildMegagroupSet(); } @@ -1320,7 +1364,7 @@ void StickersBox::Inner::setMinHeight(int newWidth, int minHeight) { void StickersBox::Inner::updateSize(int newWidth) { auto naturalHeight = _itemsTop + int(_rows.size()) * _rowHeight + st::membersMarginBottom; - resize(newWidth ? newWidth : width(), qMax(_minHeight, naturalHeight)); + resize(newWidth ? newWidth : width(), std::max(_minHeight, naturalHeight)); checkLoadMore(); } @@ -1332,7 +1376,7 @@ void StickersBox::Inner::updateRows() { if (it != sets.cend()) { auto &set = it.value(); if (!row->sticker) { - auto sticker = (DocumentData*)nullptr; + auto sticker = (DocumentData *)nullptr; auto pixw = 0, pixh = 0; fillSetCover(set, &sticker, &pixw, &pixh); if (sticker) { @@ -1400,11 +1444,13 @@ void StickersBox::Inner::rebuildAppendSet(const Stickers::Set &set, int maxNameW QString title = fillSetTitle(set, maxNameWidth, &titleWidth); int count = fillSetCount(set); - _rows.push_back(std::make_unique(set.id, sticker, count, title, titleWidth, installed, official, unread, archived, removed, pixw, pixh)); + _rows.push_back(std::make_unique(set.id, sticker, count, title, titleWidth, installed, official, unread, + archived, removed, pixw, pixh)); _animStartTimes.push_back(0); } -void StickersBox::Inner::fillSetCover(const Stickers::Set &set, DocumentData **outSticker, int *outWidth, int *outHeight) const { +void StickersBox::Inner::fillSetCover(const Stickers::Set &set, DocumentData **outSticker, int *outWidth, + int *outHeight) const { if (set.stickers.isEmpty()) { *outSticker = nullptr; *outWidth = *outHeight = 0; @@ -1461,7 +1507,8 @@ QString StickersBox::Inner::fillSetTitle(const Stickers::Set &set, int maxNameWi return result; } -void StickersBox::Inner::fillSetFlags(const Stickers::Set &set, bool *outInstalled, bool *outOfficial, bool *outUnread, bool *outArchived) { +void StickersBox::Inner::fillSetFlags(const Stickers::Set &set, bool *outInstalled, bool *outOfficial, bool *outUnread, + bool *outArchived) { *outInstalled = (set.flags & MTPDstickerSet::Flag::f_installed); *outOfficial = (set.flags & MTPDstickerSet::Flag::f_official); *outArchived = (set.flags & MTPDstickerSet::Flag::f_archived); @@ -1472,8 +1519,7 @@ void StickersBox::Inner::fillSetFlags(const Stickers::Set &set, bool *outInstall } } -template -Stickers::Order StickersBox::Inner::collectSets(Check check) const { +template Stickers::Order StickersBox::Inner::collectSets(Check check) const { Stickers::Order result; result.reserve(_rows.size()); for_const (auto &row, _rows) { @@ -1485,24 +1531,18 @@ Stickers::Order StickersBox::Inner::collectSets(Check check) const { } Stickers::Order StickersBox::Inner::getOrder() const { - return collectSets([](Row *row) { - return !row->archived && !row->removed && !row->isRecentSet(); - }); + return collectSets([](Row *row) { return !row->archived && !row->removed && !row->isRecentSet(); }); } Stickers::Order StickersBox::Inner::getFullOrder() const { - return collectSets([](Row *row) { - return !row->isRecentSet(); - }); + return collectSets([](Row *row) { return !row->isRecentSet(); }); } Stickers::Order StickersBox::Inner::getRemovedSets() const { - return collectSets([](Row *row) { - return row->removed; - }); + return collectSets([](Row *row) { return row->removed; }); } -int StickersBox::Inner::getRowIndex(uint64 setId) const { +int StickersBox::Inner::getRowIndex(quint64 setId) const { for (auto i = 0, count = int(_rows.size()); i != count; ++i) { auto &row = _rows[i]; if (row->id == setId) { diff --git a/Telegram/SourceFiles/boxes/stickers_box.h b/Telegram/SourceFiles/boxes/stickers_box.h index 9323eeb90..aadbcbcec 100644 --- a/Telegram/SourceFiles/boxes/stickers_box.h +++ b/Telegram/SourceFiles/boxes/stickers_box.h @@ -1,27 +1,29 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once -#include "boxes/abstract_box.h" #include "base/timer.h" +#include "boxes/abstract_box.h" #include "mtproto/sender.h" class ConfirmBox; @@ -46,8 +48,8 @@ class StickersBox : public BoxContent, public RPCSender { Featured, Archived, }; - StickersBox(QWidget*, Section section); - StickersBox(QWidget*, not_null megagroup); + StickersBox(QWidget *, Section section); + StickersBox(QWidget *, not_null megagroup); void setInnerFocus() override; @@ -65,8 +67,7 @@ class StickersBox : public BoxContent, public RPCSender { public: Tab() = default; - template - Tab(int index, Args&&... args); + template Tab(int index, Args &&... args); object_ptr takeWidget(); void returnWidget(object_ptr widget); @@ -85,10 +86,9 @@ class StickersBox : public BoxContent, public RPCSender { private: int _index = 0; - object_ptr _widget = { nullptr }; + object_ptr _widget = {nullptr}; QPointer _weak; int _scrollTop = 0; - }; void handleStickersUpdated(); @@ -96,25 +96,25 @@ class StickersBox : public BoxContent, public RPCSender { void rebuildList(Tab *tab = nullptr); void updateTabsGeometry(); void switchTab(); - void installSet(uint64 setId); + void installSet(quint64 setId); int getTopSkip() const; void saveChanges(); QPixmap grabContentCache(); void installDone(const MTPmessages_StickerSetInstallResult &result); - bool installFail(uint64 setId, const RPCError &error); + bool installFail(quint64 setId, const RPCError &error); void preloadArchivedSets(); void requestArchivedSets(); void loadMoreArchived(); - void getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedStickers &result); + void getArchivedDone(quint64 offsetId, const MTPmessages_ArchivedStickers &result); - object_ptr _tabs = { nullptr }; + object_ptr _tabs = {nullptr}; QList
_tabIndices; class CounterWidget; - object_ptr _unreadBadge = { nullptr }; + object_ptr _unreadBadge = {nullptr}; Section _section; @@ -126,7 +126,7 @@ class StickersBox : public BoxContent, public RPCSender { ChannelData *_megagroupSet = nullptr; std::unique_ptr _slideAnimation; - object_ptr _titleShadow = { nullptr }; + object_ptr _titleShadow = {nullptr}; mtpRequestId _archivedRequestId = 0; bool _archivedLoaded = false; @@ -135,7 +135,6 @@ class StickersBox : public BoxContent, public RPCSender { Stickers::Order _localOrder; Stickers::Order _localRemoved; - }; int stickerPacksCount(bool includeArchivedOfficial = false); @@ -147,7 +146,7 @@ class StickersBox::Inner : public TWidget, private base::Subscriber, private MTP public: using Section = StickersBox::Section; Inner(QWidget *parent, Section section); - Inner(QWidget *parent, not_null megagroup); + Inner(QWidget *parent, not_null megagroup); base::Observable scrollToY; void setInnerFocus(); @@ -166,10 +165,10 @@ class StickersBox::Inner : public TWidget, private base::Subscriber, private MTP void setFullOrder(const Stickers::Order &order); void setRemovedSets(const Stickers::Order &removed); - void setInstallSetCallback(base::lambda callback) { + void setInstallSetCallback(Fn callback) { _installSetCallback = std::move(callback); } - void setLoadMoreCallback(base::lambda callback) { + void setLoadMoreCallback(Fn callback) { _loadMoreCallback = std::move(callback); } @@ -199,15 +198,16 @@ public slots: private: struct Row { - Row(uint64 id, DocumentData *sticker, int32 count, const QString &title, int titleWidth, bool installed, bool official, bool unread, bool archived, bool removed, int32 pixw, int32 pixh); + Row(quint64 id, DocumentData *sticker, qint32 count, const QString &title, int titleWidth, bool installed, + bool official, bool unread, bool archived, bool removed, qint32 pixw, qint32 pixh); bool isRecentSet() const { return (id == Stickers::CloudRecentSetId); } ~Row(); - uint64 id = 0; + quint64 id = 0; DocumentData *sticker = nullptr; - int32 count = 0; + qint32 count = 0; QString title; int titleWidth = 0; bool installed = false; @@ -215,18 +215,17 @@ public slots: bool unread = false; bool archived = false; bool removed = false; - int32 pixw = 0; - int32 pixh = 0; + qint32 pixw = 0; + qint32 pixh = 0; anim::value yadd; std::unique_ptr ripple; }; - template - Stickers::Order collectSets(Check check) const; + template Stickers::Order collectSets(Check check) const; void checkLoadMore(); void updateScrollbarWidth(); - int getRowIndex(uint64 setId) const; + int getRowIndex(quint64 setId) const; void setRowRemoved(int index, bool removed); void setSelected(int selected); @@ -240,8 +239,8 @@ public slots: void paintRow(Painter &p, Row *set, int index, TimeMs ms); void paintFakeButton(Painter &p, Row *set, int index, TimeMs ms); void clear(); - void setActionSel(int32 actionSel); - float64 aboveShadowOpacity() const; + void setActionSel(qint32 actionSel); + double aboveShadowOpacity() const; void readVisibleSets(); @@ -250,7 +249,8 @@ public slots: void fillSetCover(const Stickers::Set &set, DocumentData **outSticker, int *outWidth, int *outHeight) const; int fillSetCount(const Stickers::Set &set) const; QString fillSetTitle(const Stickers::Set &set, int maxNameWidth, int *outTitleWidth) const; - void fillSetFlags(const Stickers::Set &set, bool *outInstalled, bool *outOfficial, bool *outUnread, bool *outArchived); + void fillSetFlags(const Stickers::Set &set, bool *outInstalled, bool *outOfficial, bool *outUnread, + bool *outArchived); void rebuildMegagroupSet(); void handleMegagroupSetAddressChange(); void setMegagroupSelectedSet(const MTPInputStickerSet &set); @@ -259,7 +259,7 @@ public slots: Section _section; - int32 _rowHeight; + qint32 _rowHeight; std::vector> _rows; QList _animStartTimes; @@ -267,8 +267,8 @@ public slots: anim::value _aboveShadowFadeOpacity; BasicAnimation _a_shifting; - base::lambda _installSetCallback; - base::lambda _loadMoreCallback; + Fn _installSetCallback; + Fn _loadMoreCallback; int _visibleTop = 0; int _visibleBottom = 0; @@ -299,12 +299,11 @@ public slots: ChannelData *_megagroupSet = nullptr; MTPInputStickerSet _megagroupSetInput = MTP_inputStickerSetEmpty(); std::unique_ptr _megagroupSelectedSet; - object_ptr _megagroupSetField = { nullptr }; - object_ptr _megagroupSelectedShadow = { nullptr }; - object_ptr _megagroupSelectedRemove = { nullptr }; - object_ptr _megagroupDivider = { nullptr }; - object_ptr _megagroupSubTitle = { nullptr }; + object_ptr _megagroupSetField = {nullptr}; + object_ptr _megagroupSelectedShadow = {nullptr}; + object_ptr _megagroupSelectedRemove = {nullptr}; + object_ptr _megagroupDivider = {nullptr}; + object_ptr _megagroupSubTitle = {nullptr}; base::Timer _megagroupSetAddressChangedTimer; mtpRequestId _megagroupSetRequestId = 0; - }; diff --git a/Telegram/SourceFiles/boxes/username_box.cpp b/Telegram/SourceFiles/boxes/username_box.cpp index 013ef5b6b..2aa4e45b9 100644 --- a/Telegram/SourceFiles/boxes/username_box.cpp +++ b/Telegram/SourceFiles/boxes/username_box.cpp @@ -1,41 +1,44 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "boxes/username_box.h" -#include "lang/lang_keys.h" #include "application.h" +#include "lang/lang_keys.h" #include "mainwidget.h" #include "mainwindow.h" +#include "messenger.h" +#include "styles/style_boxes.h" +#include "ui/toast/toast.h" #include "ui/widgets/buttons.h" #include "ui/widgets/input_fields.h" -#include "ui/toast/toast.h" -#include "styles/style_boxes.h" -#include "messenger.h" +#include +#include -UsernameBox::UsernameBox(QWidget*) -: _username(this, st::defaultInputField, [] { return qsl("@username"); }, App::self()->username, false) -, _link(this, QString(), st::boxLinkButton) -, _about(st::boxWidth - st::usernamePadding.left()) -, _checkTimer(this) { -} +UsernameBox::UsernameBox(QWidget *) + : _username(this, st::defaultInputField, [] { return qsl("@username"); }, App::self()->username, false) + , _link(this, QString(), st::boxLinkButton) + , _about(st::boxWidth - st::usernamePadding.left()) + , _checkTimer(this) {} void UsernameBox::prepare() { _goodText = App::self()->username.isEmpty() ? QString() : lang(lng_username_available); @@ -50,7 +53,9 @@ void UsernameBox::prepare() { connect(_link, SIGNAL(clicked()), this, SLOT(onLinkClick())); _about.setRichText(st::usernameTextStyle, lang(lng_username_about)); - setDimensions(st::boxWidth, st::usernamePadding.top() + _username->height() + st::usernameSkip + _about.countHeight(st::boxWidth - st::usernamePadding.left()) + 3 * st::usernameTextStyle.lineHeight + st::usernamePadding.bottom()); + setDimensions(st::boxWidth, st::usernamePadding.top() + _username->height() + st::usernameSkip + + _about.countHeight(st::boxWidth - st::usernamePadding.left()) + + 3 * st::usernameTextStyle.lineHeight + st::usernamePadding.bottom()); _checkTimer->setSingleShot(true); connect(_checkTimer, SIGNAL(timeout()), this, SLOT(onCheck())); @@ -70,23 +75,34 @@ void UsernameBox::paintEvent(QPaintEvent *e) { p.setFont(st::boxTextFont); if (!_errorText.isEmpty()) { p.setPen(st::boxTextFgError); - p.drawTextLeft(st::usernamePadding.left(), _username->y() + _username->height() + ((st::usernameSkip - st::boxTextFont->height) / 2), width(), _errorText); + p.drawTextLeft(st::usernamePadding.left(), + _username->y() + _username->height() + ((st::usernameSkip - st::boxTextFont->height) / 2), + width(), _errorText); } else if (!_goodText.isEmpty()) { p.setPen(st::boxTextFgGood); - p.drawTextLeft(st::usernamePadding.left(), _username->y() + _username->height() + ((st::usernameSkip - st::boxTextFont->height) / 2), width(), _goodText); + p.drawTextLeft(st::usernamePadding.left(), + _username->y() + _username->height() + ((st::usernameSkip - st::boxTextFont->height) / 2), + width(), _goodText); } else { p.setPen(st::usernameDefaultFg); - p.drawTextLeft(st::usernamePadding.left(), _username->y() + _username->height() + ((st::usernameSkip - st::boxTextFont->height) / 2), width(), lang(lng_username_choose)); + p.drawTextLeft(st::usernamePadding.left(), + _username->y() + _username->height() + ((st::usernameSkip - st::boxTextFont->height) / 2), + width(), lang(lng_username_choose)); } p.setPen(st::boxTextFg); - int32 availw = st::boxWidth - st::usernamePadding.left(), h = _about.countHeight(availw); - _about.drawLeft(p, st::usernamePadding.left(), _username->y() + _username->height() + st::usernameSkip, availw, width()); + qint32 availw = st::boxWidth - st::usernamePadding.left(), h = _about.countHeight(availw); + _about.drawLeft(p, st::usernamePadding.left(), _username->y() + _username->height() + st::usernameSkip, availw, + width()); - int32 linky = _username->y() + _username->height() + st::usernameSkip + h + st::usernameTextStyle.lineHeight + ((st::usernameTextStyle.lineHeight - st::boxTextFont->height) / 2); + qint32 linky = _username->y() + _username->height() + st::usernameSkip + h + st::usernameTextStyle.lineHeight + + ((st::usernameTextStyle.lineHeight - st::boxTextFont->height) / 2); if (_link->isHidden()) { p.drawTextLeft(st::usernamePadding.left(), linky, width(), lang(lng_username_link_willbe)); p.setPen(st::usernameDefaultFg); - p.drawTextLeft(st::usernamePadding.left(), linky + st::usernameTextStyle.lineHeight + ((st::usernameTextStyle.lineHeight - st::boxTextFont->height) / 2), width(), Messenger::Instance().createInternalLinkFull(qsl("username"))); + p.drawTextLeft(st::usernamePadding.left(), + linky + st::usernameTextStyle.lineHeight + + ((st::usernameTextStyle.lineHeight - st::boxTextFont->height) / 2), + width(), Messenger::Instance().createInternalLinkFull(qsl("username"))); } else { p.drawTextLeft(st::usernamePadding.left(), linky, width(), lang(lng_username_link)); } @@ -98,16 +114,20 @@ void UsernameBox::resizeEvent(QResizeEvent *e) { _username->resize(width() - st::usernamePadding.left() - st::usernamePadding.right(), _username->height()); _username->moveToLeft(st::usernamePadding.left(), st::usernamePadding.top()); - int32 availw = st::boxWidth - st::usernamePadding.left(), h = _about.countHeight(availw); - int32 linky = _username->y() + _username->height() + st::usernameSkip + h + st::usernameTextStyle.lineHeight + ((st::usernameTextStyle.lineHeight - st::boxTextFont->height) / 2); - _link->moveToLeft(st::usernamePadding.left(), linky + st::usernameTextStyle.lineHeight + ((st::usernameTextStyle.lineHeight - st::boxTextFont->height) / 2)); + qint32 availw = st::boxWidth - st::usernamePadding.left(), h = _about.countHeight(availw); + qint32 linky = _username->y() + _username->height() + st::usernameSkip + h + st::usernameTextStyle.lineHeight + + ((st::usernameTextStyle.lineHeight - st::boxTextFont->height) / 2); + _link->moveToLeft(st::usernamePadding.left(), + linky + st::usernameTextStyle.lineHeight + + ((st::usernameTextStyle.lineHeight - st::boxTextFont->height) / 2)); } void UsernameBox::onSave() { if (_saveRequestId) return; _sentUsername = getName(); - _saveRequestId = MTP::send(MTPaccount_UpdateUsername(MTP_string(_sentUsername)), rpcDone(&UsernameBox::onUpdateDone), rpcFail(&UsernameBox::onUpdateFail)); + _saveRequestId = MTP::send(MTPaccount_UpdateUsername(MTP_string(_sentUsername)), + rpcDone(&UsernameBox::onUpdateDone), rpcFail(&UsernameBox::onUpdateFail)); } void UsernameBox::onCheck() { @@ -117,7 +137,8 @@ void UsernameBox::onCheck() { QString name = getName(); if (name.size() >= MinUsernameLength) { _checkUsername = name; - _checkRequestId = MTP::send(MTPaccount_CheckUsername(MTP_string(name)), rpcDone(&UsernameBox::onCheckDone), rpcFail(&UsernameBox::onCheckFail)); + _checkRequestId = MTP::send(MTPaccount_CheckUsername(MTP_string(name)), rpcDone(&UsernameBox::onCheckDone), + rpcFail(&UsernameBox::onCheckFail)); } } @@ -131,10 +152,11 @@ void UsernameBox::onChanged() { } _checkTimer->stop(); } else { - int32 len = name.size(); - for (int32 i = 0; i < len; ++i) { + qint32 len = name.size(); + for (qint32 i = 0; i < len; ++i) { QChar ch = name.at(i); - if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z') && (ch < '0' || ch > '9') && ch != '_' && (ch != '@' || i > 0)) { + if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z') && (ch < '0' || ch > '9') && ch != '_' && + (ch != '@' || i > 0)) { if (_errorText != lang(lng_username_bad_symbols)) { _errorText = lang(lng_username_bad_symbols); update(); @@ -175,7 +197,9 @@ bool UsernameBox::onUpdateFail(const RPCError &error) { _saveRequestId = 0; QString err(error.type()); if (err == qstr("USERNAME_NOT_MODIFIED") || _sentUsername == App::self()->username) { - App::self()->setName(TextUtilities::SingleLine(App::self()->firstName), TextUtilities::SingleLine(App::self()->lastName), TextUtilities::SingleLine(App::self()->nameOrPhone), TextUtilities::SingleLine(_sentUsername)); + App::self()->setName( + TextUtilities::SingleLine(App::self()->firstName), TextUtilities::SingleLine(App::self()->lastName), + TextUtilities::SingleLine(App::self()->nameOrPhone), TextUtilities::SingleLine(_sentUsername)); closeBox(); return true; } else if (err == qstr("USERNAME_INVALID")) { @@ -197,7 +221,8 @@ bool UsernameBox::onUpdateFail(const RPCError &error) { void UsernameBox::onCheckDone(const MTPBool &result) { _checkRequestId = 0; - QString newError = (mtpIsTrue(result) || _checkUsername == App::self()->username) ? QString() : lang(lng_username_occupied); + QString newError = + (mtpIsTrue(result) || _checkUsername == App::self()->username) ? QString() : lang(lng_username_occupied); QString newGood = newError.isEmpty() ? lang(lng_username_available) : QString(); if (_errorText != newError || _goodText != newGood) { _errorText = newError; @@ -231,7 +256,8 @@ QString UsernameBox::getName() const { void UsernameBox::updateLinkText() { QString uname = getName(); - _link->setText(st::boxTextFont->elided(Messenger::Instance().createInternalLinkFull(uname), st::boxWidth - st::usernamePadding.left() - st::usernamePadding.right())); + _link->setText(st::boxTextFont->elided(Messenger::Instance().createInternalLinkFull(uname), + st::boxWidth - st::usernamePadding.left() - st::usernamePadding.right())); if (uname.isEmpty()) { if (!_link->isHidden()) { _link->hide(); @@ -243,4 +269,4 @@ void UsernameBox::updateLinkText() { update(); } } -} \ No newline at end of file +} diff --git a/Telegram/SourceFiles/boxes/username_box.h b/Telegram/SourceFiles/boxes/username_box.h index 7eab1bb2d..c306c4ab7 100644 --- a/Telegram/SourceFiles/boxes/username_box.h +++ b/Telegram/SourceFiles/boxes/username_box.h @@ -1,26 +1,29 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "boxes/abstract_box.h" +#include "ui/text/text.h" namespace Ui { class UsernameInput; @@ -31,7 +34,7 @@ class UsernameBox : public BoxContent, public RPCSender { Q_OBJECT public: - UsernameBox(QWidget*); + UsernameBox(QWidget *); protected: void prepare() override; @@ -67,5 +70,4 @@ private slots: Text _about; object_ptr _checkTimer; - }; diff --git a/Telegram/SourceFiles/calls/calls.style b/Telegram/SourceFiles/calls/calls.style index 533cbbaf7..2b6255613 100644 --- a/Telegram/SourceFiles/calls/calls.style +++ b/Telegram/SourceFiles/calls/calls.style @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// using "basic.style"; using "ui/widgets/widgets.style"; diff --git a/Telegram/SourceFiles/calls/calls_box_controller.cpp b/Telegram/SourceFiles/calls/calls_box_controller.cpp index 380e03ef4..333884645 100644 --- a/Telegram/SourceFiles/calls/calls_box_controller.cpp +++ b/Telegram/SourceFiles/calls/calls_box_controller.cpp @@ -1,32 +1,35 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "calls/calls_box_controller.h" -#include "styles/style_calls.h" -#include "styles/style_boxes.h" +#include "app.h" +#include "calls/calls_instance.h" +#include "history/history_media_types.h" #include "lang/lang_keys.h" #include "observer_peer.h" +#include "styles/style_boxes.h" +#include "styles/style_calls.h" #include "ui/effects/ripple_animation.h" -#include "calls/calls_instance.h" -#include "history/history_media_types.h" namespace Calls { namespace { @@ -52,9 +55,7 @@ class BoxController::Row : public PeerListRow { void addItem(HistoryItem *item) { Expects(canAddItem(item)); _items.push_back(item); - std::sort(_items.begin(), _items.end(), [](HistoryItem *a, HistoryItem *b) { - return (a->id > b->id); - }); + std::sort(_items.begin(), _items.end(), [](HistoryItem *a, HistoryItem *b) { return (a->id > b->id); }); refreshStatus(); } void itemRemoved(HistoryItem *item) { @@ -78,7 +79,7 @@ class BoxController::Row : public PeerListRow { } void paintStatusText(Painter &p, int x, int y, int availableWidth, int outerWidth, bool selected) override; - void addActionRipple(QPoint point, base::lambda updateCallback) override; + void addActionRipple(QPoint point, Fn updateCallback) override; void stopLastActionRipple() override; bool needsVerifiedIcon() const override { @@ -96,18 +97,18 @@ class BoxController::Row : public PeerListRow { void refreshStatus(); static Type ComputeType(HistoryItem *item); - std::vector _items; + std::vector _items; QDate _date; Type _type; std::unique_ptr _actionRipple; - }; -BoxController::Row::Row(HistoryItem *item) : PeerListRow(item->history()->peer, item->id) -, _items(1, item) -, _date(item->date.date()) -, _type(ComputeType(item)) { +BoxController::Row::Row(HistoryItem *item) + : PeerListRow(item->history()->peer, item->id) + , _items(1, item) + , _date(item->date.date()) + , _type(ComputeType(item)) { refreshStatus(); } @@ -131,7 +132,8 @@ void BoxController::Row::paintStatusText(Painter &p, int x, int y, int available void BoxController::Row::paintAction(Painter &p, TimeMs ms, int x, int y, int outerWidth, bool actionSelected) { auto size = actionSize(); if (_actionRipple) { - _actionRipple->paint(p, x + st::callReDial.rippleAreaPosition.x(), y + st::callReDial.rippleAreaPosition.y(), outerWidth, ms); + _actionRipple->paint(p, x + st::callReDial.rippleAreaPosition.x(), y + st::callReDial.rippleAreaPosition.y(), + outerWidth, ms); if (_actionRipple->empty()) { _actionRipple.reset(); } @@ -153,7 +155,9 @@ void BoxController::Row::refreshStatus() { } return lng_call_box_status_date(lt_date, langDayOfMonthFull(_date), lt_time, time); }; - setCustomStatus((_items.size() > 1) ? lng_call_box_status_group(lt_count, QString::number(_items.size()), lt_status, text()) : text()); + setCustomStatus((_items.size() > 1) ? + lng_call_box_status_group(lt_count, QString::number(_items.size()), lt_status, text()) : + text()); } BoxController::Row::Type BoxController::Row::ComputeType(HistoryItem *item) { @@ -161,7 +165,7 @@ BoxController::Row::Type BoxController::Row::ComputeType(HistoryItem *item) { return Type::Out; } else if (auto media = item->getMedia()) { if (media->type() == MediaTypeCall) { - auto reason = static_cast(media)->reason(); + auto reason = static_cast(media)->reason(); if (reason == HistoryCall::FinishReason::Busy || reason == HistoryCall::FinishReason::Missed) { return Type::Missed; } @@ -170,10 +174,12 @@ BoxController::Row::Type BoxController::Row::ComputeType(HistoryItem *item) { return Type::In; } -void BoxController::Row::addActionRipple(QPoint point, base::lambda updateCallback) { +void BoxController::Row::addActionRipple(QPoint point, Fn updateCallback) { if (!_actionRipple) { - auto mask = Ui::RippleAnimation::ellipseMask(QSize(st::callReDial.rippleAreaSize, st::callReDial.rippleAreaSize)); - _actionRipple = std::make_unique(st::callReDial.ripple, std::move(mask), std::move(updateCallback)); + auto mask = + Ui::RippleAnimation::ellipseMask(QSize(st::callReDial.rippleAreaSize, st::callReDial.rippleAreaSize)); + _actionRipple = + std::make_unique(st::callReDial.ripple, std::move(mask), std::move(updateCallback)); } _actionRipple->add(point - st::callReDial.rippleAreaPosition); } @@ -215,41 +221,49 @@ void BoxController::loadMoreRows() { return; } - _loadRequestId = request(MTPmessages_Search(MTP_flags(0), MTP_inputPeerEmpty(), MTP_string(QString()), MTP_inputUserEmpty(), MTP_inputMessagesFilterPhoneCalls(MTP_flags(0)), MTP_int(0), MTP_int(0), MTP_int(_offsetId), MTP_int(0), MTP_int(_offsetId ? kFirstPageCount : kPerPageCount), MTP_int(0), MTP_int(0))).done([this](const MTPmessages_Messages &result) { - _loadRequestId = 0; - - auto handleResult = [this](auto &data) { - App::feedUsers(data.vusers); - App::feedChats(data.vchats); - receivedCalls(data.vmessages.v); - }; - - switch (result.type()) { - case mtpc_messages_messages: handleResult(result.c_messages_messages()); _allLoaded = true; break; - case mtpc_messages_messagesSlice: handleResult(result.c_messages_messagesSlice()); break; - case mtpc_messages_channelMessages: { - LOG(("API Error: received messages.channelMessages! (Calls::BoxController::preloadRows)")); - handleResult(result.c_messages_channelMessages()); - } break; - - default: Unexpected("Type of messages.Messages (Calls::BoxController::preloadRows)"); - } - }).fail([this](const RPCError &error) { - _loadRequestId = 0; - }).send(); + _loadRequestId = + request(MTPmessages_Search(MTP_flags(0), MTP_inputPeerEmpty(), MTP_string(QString()), MTP_inputUserEmpty(), + MTP_inputMessagesFilterPhoneCalls(MTP_flags(0)), MTP_int(0), MTP_int(0), + MTP_int(_offsetId), MTP_int(0), MTP_int(_offsetId ? kFirstPageCount : kPerPageCount), + MTP_int(0), MTP_int(0))) + .done([this](const MTPmessages_Messages &result) { + _loadRequestId = 0; + + auto handleResult = [this](auto &data) { + App::feedUsers(data.vusers); + App::feedChats(data.vchats); + receivedCalls(data.vmessages.v); + }; + + switch (result.type()) { + case mtpc_messages_messages: + handleResult(result.c_messages_messages()); + _allLoaded = true; + break; + case mtpc_messages_messagesSlice: handleResult(result.c_messages_messagesSlice()); break; + case mtpc_messages_channelMessages: { + LOG(("API Error: received messages.channelMessages! (Calls::BoxController::preloadRows)")); + handleResult(result.c_messages_channelMessages()); + } break; + + default: Unexpected("Type of messages.Messages (Calls::BoxController::preloadRows)"); + } + }) + .fail([this](const RPCError &error) { _loadRequestId = 0; }) + .send(); } void BoxController::refreshAbout() { setDescriptionText(delegate()->peerListFullRowsCount() ? QString() : lang(lng_call_box_about)); } -void BoxController::rowClicked(not_null row) { - auto itemsRow = static_cast(row.get()); +void BoxController::rowClicked(not_null row) { + auto itemsRow = static_cast(row.get()); auto itemId = itemsRow->maxItemId(); Ui::showPeerHistoryAsync(row->peer()->id, itemId); } -void BoxController::rowActionClicked(not_null row) { +void BoxController::rowActionClicked(not_null row) { auto user = row->peer()->asUser(); Assert(user != nullptr); @@ -284,9 +298,10 @@ bool BoxController::insertRow(HistoryItem *item, InsertWay way) { return false; } } - (way == InsertWay::Append) ? delegate()->peerListAppendRow(createRow(item)) : delegate()->peerListPrependRow(createRow(item)); + (way == InsertWay::Append) ? delegate()->peerListAppendRow(createRow(item)) : + delegate()->peerListPrependRow(createRow(item)); delegate()->peerListSortRows([](PeerListRow &a, PeerListRow &b) { - return static_cast(a).maxItemId() > static_cast(b).maxItemId(); + return static_cast(a).maxItemId() > static_cast(b).maxItemId(); }); return true; } @@ -295,11 +310,11 @@ BoxController::Row *BoxController::rowForItem(HistoryItem *item) { auto v = delegate(); if (auto fullRowsCount = v->peerListFullRowsCount()) { auto itemId = item->id; - auto lastRow = static_cast(v->peerListRowAt(fullRowsCount - 1).get()); + auto lastRow = static_cast(v->peerListRowAt(fullRowsCount - 1).get()); if (itemId < lastRow->minItemId()) { return lastRow; } - auto firstRow = static_cast(v->peerListRowAt(0).get()); + auto firstRow = static_cast(v->peerListRowAt(0).get()); if (itemId > firstRow->maxItemId()) { return firstRow; } @@ -311,18 +326,18 @@ BoxController::Row *BoxController::rowForItem(HistoryItem *item) { auto right = fullRowsCount; while (left + 1 < right) { auto middle = (right + left) / 2; - auto middleRow = static_cast(v->peerListRowAt(middle).get()); + auto middleRow = static_cast(v->peerListRowAt(middle).get()); if (middleRow->maxItemId() >= itemId) { left = middle; } else { right = middle; } } - auto result = static_cast(v->peerListRowAt(left).get()); + auto result = static_cast(v->peerListRowAt(left).get()); // Check for rowAt(left)->minItemId > itemId > rowAt(left + 1)->maxItemId. // In that case we sometimes need to return rowAt(left + 1), not rowAt(left). if (result->minItemId() > itemId && left + 1 < fullRowsCount) { - auto possibleResult = static_cast(v->peerListRowAt(left + 1).get()); + auto possibleResult = static_cast(v->peerListRowAt(left + 1).get()); Assert(possibleResult->maxItemId() < itemId); if (possibleResult->canAddItem(item)) { return possibleResult; diff --git a/Telegram/SourceFiles/calls/calls_box_controller.h b/Telegram/SourceFiles/calls/calls_box_controller.h index cbaf79d9d..8daec2cf4 100644 --- a/Telegram/SourceFiles/calls/calls_box_controller.h +++ b/Telegram/SourceFiles/calls/calls_box_controller.h @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once #include "boxes/peer_list_box.h" @@ -27,8 +29,8 @@ namespace Calls { class BoxController : public PeerListController, private base::Subscriber, private MTP::Sender { public: void prepare() override; - void rowClicked(not_null row) override; - void rowActionClicked(not_null row) override; + void rowClicked(not_null row) override; + void rowActionClicked(not_null row) override; void loadMoreRows() override; private: @@ -48,7 +50,6 @@ class BoxController : public PeerListController, private base::Subscriber, priva MsgId _offsetId = 0; mtpRequestId _loadRequestId = 0; bool _allLoaded = false; - }; } // namespace Calls diff --git a/Telegram/SourceFiles/calls/calls_call.cpp b/Telegram/SourceFiles/calls/calls_call.cpp index 17eebdd4c..097f8c29b 100644 --- a/Telegram/SourceFiles/calls/calls_call.cpp +++ b/Telegram/SourceFiles/calls/calls_call.cpp @@ -1,35 +1,38 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ -#include "calls/calls_call.h" +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// +#include "calls/calls_call.h" #include "auth_session.h" -#include "mainwidget.h" -#include "lang/lang_keys.h" +#include "base/openssl_help.h" #include "boxes/confirm_box.h" #include "boxes/rate_call_box.h" #include "calls/calls_instance.h" -#include "base/openssl_help.h" -#include "mtproto/connection.h" -#include "media/media_audio_track.h" #include "calls/calls_panel.h" +#include "core/utils.h" +#include "lang/lang_keys.h" +#include "mainwidget.h" +#include "media/media_audio_track.h" +#include "mtproto/connection.h" #ifdef slots #undef slots @@ -59,28 +62,25 @@ void ConvertEndpoint(std::vector &ep, const MTPDphoneConnectio } auto ipv4 = tgvoip::IPv4Address(std::string(mtc.vip.v.constData(), mtc.vip.v.size())); auto ipv6 = tgvoip::IPv6Address(std::string(mtc.vipv6.v.constData(), mtc.vipv6.v.size())); - ep.push_back(Endpoint((int64_t)mtc.vid.v, (uint16_t)mtc.vport.v, ipv4, ipv6, EP_TYPE_UDP_RELAY, (unsigned char*)mtc.vpeer_tag.v.data())); + ep.push_back(Endpoint((int64_t)mtc.vid.v, (uint16_t)mtc.vport.v, ipv4, ipv6, EP_TYPE_UDP_RELAY, + (unsigned char *)mtc.vpeer_tag.v.data())); } constexpr auto kFingerprintDataSize = 256; -uint64 ComputeFingerprint(const std::array &authKey) { +quint64 ComputeFingerprint(const std::array &authKey) { auto hash = openssl::Sha1(authKey); - return (gsl::to_integer(hash[19]) << 56) - | (gsl::to_integer(hash[18]) << 48) - | (gsl::to_integer(hash[17]) << 40) - | (gsl::to_integer(hash[16]) << 32) - | (gsl::to_integer(hash[15]) << 24) - | (gsl::to_integer(hash[14]) << 16) - | (gsl::to_integer(hash[13]) << 8) - | (gsl::to_integer(hash[12])); + return (gsl::to_integer(hash[19]) << 56) | (gsl::to_integer(hash[18]) << 48) | + (gsl::to_integer(hash[17]) << 40) | (gsl::to_integer(hash[16]) << 32) | + (gsl::to_integer(hash[15]) << 24) | (gsl::to_integer(hash[14]) << 16) | + (gsl::to_integer(hash[13]) << 8) | (gsl::to_integer(hash[12])); } } // namespace -Call::Call(not_null delegate, not_null user, Type type) -: _delegate(delegate) -, _user(user) -, _type(type) { +Call::Call(not_null delegate, not_null user, Type type) + : _delegate(delegate) + , _user(user) + , _type(type) { _discardByTimeoutTimer.setCallback([this] { hangup(); }); if (_type == Type::Outgoing) { @@ -137,50 +137,55 @@ void Call::startOutgoing() { Expects(_type == Type::Outgoing); Expects(_state == State::Requesting); - request(MTPphone_RequestCall(_user->inputUser, MTP_int(rand_value()), MTP_bytes(_gaHash), MTP_phoneCallProtocol(MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p | MTPDphoneCallProtocol::Flag::f_udp_reflector), MTP_int(kMinLayer), MTP_int(kMaxLayer)))).done([this](const MTPphone_PhoneCall &result) { - Expects(result.type() == mtpc_phone_phoneCall); - - setState(State::Waiting); - - auto &call = result.c_phone_phoneCall(); - App::feedUsers(call.vusers); - if (call.vphone_call.type() != mtpc_phoneCallWaiting) { - LOG(("Call Error: Expected phoneCallWaiting in response to phone.requestCall()")); - finish(FinishType::Failed); - return; - } - - auto &phoneCall = call.vphone_call; - auto &waitingCall = phoneCall.c_phoneCallWaiting(); - _id = waitingCall.vid.v; - _accessHash = waitingCall.vaccess_hash.v; - if (_finishAfterRequestingCall != FinishType::None) { - if (_finishAfterRequestingCall == FinishType::Failed) { - finish(_finishAfterRequestingCall); - } else { - hangup(); - } - return; - } - - _discardByTimeoutTimer.callOnce(Global::CallReceiveTimeoutMs()); - handleUpdate(phoneCall); - }).fail([this](const RPCError &error) { - handleRequestError(error); - }).send(); + request(MTPphone_RequestCall(_user->inputUser, MTP_int(rand_value()), MTP_bytes(_gaHash), + MTP_phoneCallProtocol(MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p | + MTPDphoneCallProtocol::Flag::f_udp_reflector), + MTP_int(kMinLayer), MTP_int(kMaxLayer)))) + .done([this](const MTPphone_PhoneCall &result) { + Expects(result.type() == mtpc_phone_phoneCall); + + setState(State::Waiting); + + auto &call = result.c_phone_phoneCall(); + App::feedUsers(call.vusers); + if (call.vphone_call.type() != mtpc_phoneCallWaiting) { + LOG(("Call Error: Expected phoneCallWaiting in response to phone.requestCall()")); + finish(FinishType::Failed); + return; + } + + auto &phoneCall = call.vphone_call; + auto &waitingCall = phoneCall.c_phoneCallWaiting(); + _id = waitingCall.vid.v; + _accessHash = waitingCall.vaccess_hash.v; + if (_finishAfterRequestingCall != FinishType::None) { + if (_finishAfterRequestingCall == FinishType::Failed) { + finish(_finishAfterRequestingCall); + } else { + hangup(); + } + return; + } + + _discardByTimeoutTimer.callOnce(Global::CallReceiveTimeoutMs()); + handleUpdate(phoneCall); + }) + .fail([this](const RPCError &error) { handleRequestError(error); }) + .send(); } void Call::startIncoming() { Expects(_type == Type::Incoming); Expects(_state == State::Starting); - request(MTPphone_ReceivedCall(MTP_inputPhoneCall(MTP_long(_id), MTP_long(_accessHash)))).done([this](const MTPBool &result) { - if (_state == State::Starting) { - setState(State::WaitingIncoming); - } - }).fail([this](const RPCError &error) { - handleRequestError(error); - }).send(); + request(MTPphone_ReceivedCall(MTP_inputPhoneCall(MTP_long(_id), MTP_long(_accessHash)))) + .done([this](const MTPBool &result) { + if (_state == State::Starting) { + setState(State::WaitingIncoming); + } + }) + .fail([this](const RPCError &error) { handleRequestError(error); }) + .send(); } void Call::answer() { @@ -198,20 +203,21 @@ void Call::answer() { } else { _answerAfterDhConfigReceived = false; } - request(MTPphone_AcceptCall(MTP_inputPhoneCall(MTP_long(_id), MTP_long(_accessHash)), MTP_bytes(_gb), _protocol)).done([this](const MTPphone_PhoneCall &result) { - Expects(result.type() == mtpc_phone_phoneCall); - auto &call = result.c_phone_phoneCall(); - App::feedUsers(call.vusers); - if (call.vphone_call.type() != mtpc_phoneCallWaiting) { - LOG(("Call Error: Expected phoneCallWaiting in response to phone.acceptCall()")); - finish(FinishType::Failed); - return; - } + request(MTPphone_AcceptCall(MTP_inputPhoneCall(MTP_long(_id), MTP_long(_accessHash)), MTP_bytes(_gb), _protocol)) + .done([this](const MTPphone_PhoneCall &result) { + Expects(result.type() == mtpc_phone_phoneCall); + auto &call = result.c_phone_phoneCall(); + App::feedUsers(call.vusers); + if (call.vphone_call.type() != mtpc_phoneCallWaiting) { + LOG(("Call Error: Expected phoneCallWaiting in response to phone.acceptCall()")); + finish(FinishType::Failed); + return; + } - handleUpdate(call.vphone_call); - }).fail([this](const RPCError &error) { - handleRequestError(error); - }).send(); + handleUpdate(call.vphone_call); + }) + .fail([this](const RPCError &error) { handleRequestError(error); }) + .send(); } void Call::setMute(bool mute) { @@ -233,7 +239,7 @@ void Call::hangup() { auto missed = (_state == State::Ringing || (_state == State::Waiting && _type == Type::Outgoing)); auto declined = isIncomingWaiting(); auto reason = missed ? MTP_phoneCallDiscardReasonMissed() : - declined ? MTP_phoneCallDiscardReasonBusy() : MTP_phoneCallDiscardReasonHangup(); + declined ? MTP_phoneCallDiscardReasonBusy() : MTP_phoneCallDiscardReasonHangup(); finish(FinishType::Ended, reason); } } @@ -252,22 +258,23 @@ void Call::redial() { QString Call::getDebugLog() const { constexpr auto kDebugLimit = 4096; - auto bytes = base::byte_vector(kDebugLimit, gsl::byte {}); - _controller->GetDebugString(reinterpret_cast(bytes.data()), bytes.size()); - auto end = std::find(bytes.begin(), bytes.end(), gsl::byte {}); + auto bytes = base::byte_vector(kDebugLimit, gsl::byte{}); + _controller->GetDebugString(reinterpret_cast(bytes.data()), bytes.size()); + auto end = std::find(bytes.begin(), bytes.end(), gsl::byte{}); auto size = (end - bytes.begin()); - return QString::fromUtf8(reinterpret_cast(bytes.data()), size); + return QString::fromUtf8(reinterpret_cast(bytes.data()), size); } void Call::startWaitingTrack() { _waitingTrack = Media::Audio::Current().createTrack(); - auto trackFileName = Auth().data().getSoundPath((_type == Type::Outgoing) ? qsl("call_outgoing") : qsl("call_incoming")); + auto trackFileName = + Auth().data().getSoundPath((_type == Type::Outgoing) ? qsl("call_outgoing") : qsl("call_incoming")); _waitingTrack->samplePeakEach(kSoundSampleMs); _waitingTrack->fillFromFile(trackFileName); _waitingTrack->playInLoop(); } -float64 Call::getWaitingSoundPeakValue() const { +double Call::getWaitingSoundPeakValue() const { if (_waitingTrack) { auto when = getms() + kSoundSampleMs / 4; return _waitingTrack->getPeakValue(when); @@ -282,7 +289,7 @@ bool Call::isKeyShaForFingerprintReady() const { base::byte_array Call::getKeyShaForFingerprint() const { Expects(isKeyShaForFingerprintReady()); Expects(!_ga.empty()); - auto encryptedChatAuthKey = base::byte_vector(_authKey.size() + _ga.size(), gsl::byte {}); + auto encryptedChatAuthKey = base::byte_vector(_authKey.size() + _ga.size(), gsl::byte{}); base::copy_bytes(gsl::make_span(encryptedChatAuthKey).subspan(0, _authKey.size()), _authKey); base::copy_bytes(gsl::make_span(encryptedChatAuthKey).subspan(_authKey.size(), _ga.size()), _ga); return openssl::Sha256(encryptedChatAuthKey); @@ -292,13 +299,13 @@ bool Call::handleUpdate(const MTPPhoneCall &call) { switch (call.type()) { case mtpc_phoneCallRequested: { auto &data = call.c_phoneCallRequested(); - if (_type != Type::Incoming - || _id != 0 - || peerToUser(_user->id) != data.vadmin_id.v) { + if (_type != Type::Incoming || _id != 0 || peerToUser(_user->id) != data.vadmin_id.v) { Unexpected("phoneCallRequested call inside an existing call handleUpdate()"); } if (Auth().userId() != data.vparticipant_id.v) { - LOG(("Call Error: Wrong call participant_id %1, expected %2.").arg(data.vparticipant_id.v).arg(Auth().userId())); + LOG(("Call Error: Wrong call participant_id %1, expected %2.") + .arg(data.vparticipant_id.v) + .arg(Auth().userId())); finish(FinishType::Failed); return true; } @@ -312,7 +319,8 @@ bool Call::handleUpdate(const MTPPhoneCall &call) { return true; } base::copy_bytes(gsl::make_span(_gaHash), gaHashBytes); - } return true; + } + return true; case mtpc_phoneCallEmpty: { auto &data = call.c_phoneCallEmpty(); @@ -321,7 +329,8 @@ bool Call::handleUpdate(const MTPPhoneCall &call) { } LOG(("Call Error: phoneCallEmpty received.")); finish(FinishType::Failed); - } return true; + } + return true; case mtpc_phoneCallWaiting: { auto &data = call.c_phoneCallWaiting(); @@ -333,7 +342,8 @@ bool Call::handleUpdate(const MTPPhoneCall &call) { setState(State::Ringing); startWaitingTrack(); } - } return true; + } + return true; case mtpc_phoneCall: { auto &data = call.c_phoneCall(); @@ -343,7 +353,8 @@ bool Call::handleUpdate(const MTPPhoneCall &call) { if (_type == Type::Incoming && _state == State::ExchangingKeys) { startConfirmedCall(data); } - } return true; + } + return true; case mtpc_phoneCallDiscarded: { auto &data = call.c_phoneCallDiscarded(); @@ -353,7 +364,8 @@ bool Call::handleUpdate(const MTPPhoneCall &call) { if (data.is_need_debug()) { auto debugLog = _controller ? _controller->GetDebugLog() : std::string(); if (!debugLog.empty()) { - MTP::send(MTPphone_SaveCallDebug(MTP_inputPhoneCall(MTP_long(_id), MTP_long(_accessHash)), MTP_dataJSON(MTP_string(debugLog)))); + MTP::send(MTPphone_SaveCallDebug(MTP_inputPhoneCall(MTP_long(_id), MTP_long(_accessHash)), + MTP_dataJSON(MTP_string(debugLog)))); } } if (data.is_need_rating() && _id && _accessHash) { @@ -369,7 +381,8 @@ bool Call::handleUpdate(const MTPPhoneCall &call) { } else { setState(State::EndedByOtherDevice); } - } return true; + } + return true; case mtpc_phoneCallAccepted: { auto &data = call.c_phoneCallAccepted(); @@ -382,7 +395,8 @@ bool Call::handleUpdate(const MTPPhoneCall &call) { } else if (checkCallFields(data)) { confirmAcceptedCall(data); } - } return true; + } + return true; } Unexpected("phoneCall type inside an existing call handleUpdate()"); @@ -403,20 +417,25 @@ void Call::confirmAcceptedCall(const MTPDphoneCallAccepted &call) { _keyFingerprint = ComputeFingerprint(_authKey); setState(State::ExchangingKeys); - request(MTPphone_ConfirmCall(MTP_inputPhoneCall(MTP_long(_id), MTP_long(_accessHash)), MTP_bytes(_ga), MTP_long(_keyFingerprint), MTP_phoneCallProtocol(MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p | MTPDphoneCallProtocol::Flag::f_udp_reflector), MTP_int(kMinLayer), MTP_int(kMaxLayer)))).done([this](const MTPphone_PhoneCall &result) { - Expects(result.type() == mtpc_phone_phoneCall); - auto &call = result.c_phone_phoneCall(); - App::feedUsers(call.vusers); - if (call.vphone_call.type() != mtpc_phoneCall) { - LOG(("Call Error: Expected phoneCall in response to phone.confirmCall()")); - finish(FinishType::Failed); - return; - } - - createAndStartController(call.vphone_call.c_phoneCall()); - }).fail([this](const RPCError &error) { - handleRequestError(error); - }).send(); + request(MTPphone_ConfirmCall(MTP_inputPhoneCall(MTP_long(_id), MTP_long(_accessHash)), MTP_bytes(_ga), + MTP_long(_keyFingerprint), + MTP_phoneCallProtocol(MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p | + MTPDphoneCallProtocol::Flag::f_udp_reflector), + MTP_int(kMinLayer), MTP_int(kMaxLayer)))) + .done([this](const MTPphone_PhoneCall &result) { + Expects(result.type() == mtpc_phone_phoneCall); + auto &call = result.c_phone_phoneCall(); + App::feedUsers(call.vusers); + if (call.vphone_call.type() != mtpc_phoneCall) { + LOG(("Call Error: Expected phoneCall in response to phone.confirmCall()")); + finish(FinishType::Failed); + return; + } + + createAndStartController(call.vphone_call.c_phoneCall()); + }) + .fail([this](const RPCError &error) { handleRequestError(error); }) + .send(); } void Call::startConfirmedCall(const MTPDphoneCall &call) { @@ -449,7 +468,7 @@ void Call::createAndStartController(const MTPDphoneCall &call) { return; } - voip_config_t config = { 0 }; + voip_config_t config = {0}; config.data_saving = DATA_SAVING_NEVER; config.enableAEC = true; config.enableNS = true; @@ -479,12 +498,12 @@ void Call::createAndStartController(const MTPDphoneCall &call) { if (_mute) { _controller->SetMicMute(_mute); } - _controller->implData = static_cast(this); + _controller->implData = static_cast(this); _controller->SetRemoteEndpoints(endpoints, true); _controller->SetConfig(&config); - _controller->SetEncryptionKey(reinterpret_cast(_authKey.data()), (_type == Type::Outgoing)); + _controller->SetEncryptionKey(reinterpret_cast(_authKey.data()), (_type == Type::Outgoing)); _controller->SetStateCallback([](tgvoip::VoIPController *controller, int state) { - static_cast(controller->implData)->handleControllerStateChange(controller, state); + static_cast(controller->implData)->handleControllerStateChange(controller, state); }); _controller->Start(); _controller->Connect(); @@ -493,7 +512,7 @@ void Call::createAndStartController(const MTPDphoneCall &call) { void Call::handleControllerStateChange(tgvoip::VoIPController *controller, int state) { // NB! Can be called from an arbitrary thread! // Expects(controller == _controller.get()); This can be called from ~VoIPController()! - Expects(controller->implData == static_cast(this)); + Expects(controller->implData == static_cast(this)); switch (state) { case STATE_WAIT_INIT: { @@ -521,8 +540,7 @@ void Call::handleControllerStateChange(tgvoip::VoIPController *controller, int s } } -template -bool Call::checkCallCommonFields(const T &call) { +template bool Call::checkCallCommonFields(const T &call) { auto checkFailed = [this] { finish(FinishType::Failed); return false; @@ -571,43 +589,28 @@ void Call::setState(State state) { _state = state; _stateChanged.notify(state, true); - if (true - && _state != State::Starting - && _state != State::Requesting - && _state != State::Waiting - && _state != State::WaitingIncoming - && _state != State::Ringing) { + if (true && _state != State::Starting && _state != State::Requesting && _state != State::Waiting && + _state != State::WaitingIncoming && _state != State::Ringing) { _waitingTrack.reset(); } - if (false - || _state == State::Ended - || _state == State::EndedByOtherDevice - || _state == State::Failed - || _state == State::Busy) { + if (false || _state == State::Ended || _state == State::EndedByOtherDevice || _state == State::Failed || + _state == State::Busy) { // Destroy controller before destroying Call Panel, // so that the panel hide animation is smooth. destroyController(); } switch (_state) { - case State::Established: - _startTime = getms(true); - break; - case State::ExchangingKeys: - _delegate->playSound(Delegate::Sound::Connecting); - break; + case State::Established: _startTime = getms(true); break; + case State::ExchangingKeys: _delegate->playSound(Delegate::Sound::Connecting); break; case State::Ended: _delegate->playSound(Delegate::Sound::Ended); // [[fallthrough]] - case State::EndedByOtherDevice: - _delegate->callFinished(this); - break; + case State::EndedByOtherDevice: _delegate->callFinished(this); break; case State::Failed: _delegate->playSound(Delegate::Sound::Ended); _delegate->callFailed(this); break; - case State::Busy: - _delegate->playSound(Delegate::Sound::Busy); - break; + case State::Busy: _delegate->playSound(Delegate::Sound::Busy); break; } } } @@ -621,11 +624,8 @@ void Call::finish(FinishType type, const MTPPhoneCallDiscardReason &reason) { _finishAfterRequestingCall = type; return; } - if (_state == State::HangingUp - || _state == State::FailedHangingUp - || _state == State::EndedByOtherDevice - || _state == State::Ended - || _state == State::Failed) { + if (_state == State::HangingUp || _state == State::FailedHangingUp || _state == State::EndedByOtherDevice || + _state == State::Ended || _state == State::Failed) { return; } if (!_id) { @@ -637,14 +637,16 @@ void Call::finish(FinishType type, const MTPPhoneCallDiscardReason &reason) { auto duration = getDurationMs() / 1000; auto connectionId = _controller ? _controller->GetPreferredRelayID() : 0; _finishByTimeoutTimer.call(kHangupTimeoutMs, [this, finalState] { setState(finalState); }); - request(MTPphone_DiscardCall(MTP_inputPhoneCall(MTP_long(_id), MTP_long(_accessHash)), MTP_int(duration), reason, MTP_long(connectionId))).done([this, finalState](const MTPUpdates &result) { - // This could be destroyed by updates, so we set Ended after - // updates being handled, but in a guarded way. - InvokeQueued(this, [this, finalState] { setState(finalState); }); - App::main()->sentUpdatesReceived(result); - }).fail([this, finalState](const RPCError &error) { - setState(finalState); - }).send(); + request(MTPphone_DiscardCall(MTP_inputPhoneCall(MTP_long(_id), MTP_long(_accessHash)), MTP_int(duration), reason, + MTP_long(connectionId))) + .done([this, finalState](const MTPUpdates &result) { + // This could be destroyed by updates, so we set Ended after + // updates being handled, but in a guarded way. + InvokeQueued(this, [this, finalState] { setState(finalState); }); + App::main()->sentUpdatesReceived(result); + }) + .fail([this, finalState](const RPCError &error) { setState(finalState); }) + .send(); } void Call::setStateQueued(State state) { diff --git a/Telegram/SourceFiles/calls/calls_call.h b/Telegram/SourceFiles/calls/calls_call.h index 447463b37..083c4a44b 100644 --- a/Telegram/SourceFiles/calls/calls_call.h +++ b/Telegram/SourceFiles/calls/calls_call.h @@ -1,29 +1,31 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once -#include "base/weak_unique_ptr.h" #include "base/timer.h" -#include "mtproto/sender.h" +#include "base/weak_unique_ptr.h" #include "mtproto/auth_key.h" +#include "mtproto/sender.h" namespace Media { namespace Audio { @@ -38,8 +40,8 @@ class VoIPController; namespace Calls { struct DhConfig { - int32 version = 0; - int32 g = 0; + qint32 version = 0; + qint32 g = 0; std::vector p; }; @@ -48,9 +50,9 @@ class Call : public base::enable_weak_from_this, private MTP::Sender { class Delegate { public: virtual DhConfig getDhConfig() const = 0; - virtual void callFinished(not_null call) = 0; - virtual void callFailed(not_null call) = 0; - virtual void callRedial(not_null call) = 0; + virtual void callFinished(not_null call) = 0; + virtual void callFailed(not_null call) = 0; + virtual void callRedial(not_null call) = 0; enum class Sound { Connecting, @@ -58,7 +60,6 @@ class Call : public base::enable_weak_from_this, private MTP::Sender { Ended, }; virtual void playSound(Sound sound) = 0; - }; static constexpr auto kRandomPowerSize = 256; @@ -69,12 +70,12 @@ class Call : public base::enable_weak_from_this, private MTP::Sender { Incoming, Outgoing, }; - Call(not_null delegate, not_null user, Type type); + Call(not_null delegate, not_null user, Type type); Type type() const { return _type; } - not_null user() const { + not_null user() const { return _user; } bool isIncomingWaiting() const; @@ -115,7 +116,7 @@ class Call : public base::enable_weak_from_this, private MTP::Sender { } TimeMs getDurationMs() const; - float64 getWaitingSoundPeakValue() const; + double getWaitingSoundPeakValue() const; void answer(); void hangup(); @@ -145,8 +146,7 @@ class Call : public base::enable_weak_from_this, private MTP::Sender { void handleControllerStateChange(tgvoip::VoIPController *controller, int state); void createAndStartController(const MTPDphoneCall &call); - template - bool checkCallCommonFields(const T &call); + template bool checkCallCommonFields(const T &call); bool checkCallFields(const MTPDphoneCall &call); bool checkCallFields(const MTPDphoneCallAccepted &call); @@ -157,8 +157,8 @@ class Call : public base::enable_weak_from_this, private MTP::Sender { void setFailedQueued(int error); void destroyController(); - not_null _delegate; - not_null _user; + not_null _delegate; + not_null _user; Type _type = Type::Outgoing; State _state = State::Starting; FinishType _finishAfterRequestingCall = FinishType::None; @@ -179,14 +179,13 @@ class Call : public base::enable_weak_from_this, private MTP::Sender { MTP::AuthKey::Data _authKey; MTPPhoneCallProtocol _protocol; - uint64 _id = 0; - uint64 _accessHash = 0; - uint64 _keyFingerprint = 0; + quint64 _id = 0; + quint64 _accessHash = 0; + quint64 _keyFingerprint = 0; std::unique_ptr _controller; std::unique_ptr _waitingTrack; - }; void UpdateConfig(const std::map &data); diff --git a/Telegram/SourceFiles/calls/calls_emoji_fingerprint.cpp b/Telegram/SourceFiles/calls/calls_emoji_fingerprint.cpp index 334956654..0415cf43c 100644 --- a/Telegram/SourceFiles/calls/calls_emoji_fingerprint.cpp +++ b/Telegram/SourceFiles/calls/calls_emoji_fingerprint.cpp @@ -1,23 +1,25 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "calls/calls_emoji_fingerprint.h" #include "calls/calls_call.h" @@ -26,102 +28,77 @@ namespace Calls { namespace { ushort Data[] = { -0xd83d, 0xde09, 0xd83d, 0xde0d, 0xd83d, 0xde1b, 0xd83d, 0xde2d, 0xd83d, 0xde31, 0xd83d, 0xde21, -0xd83d, 0xde0e, 0xd83d, 0xde34, 0xd83d, 0xde35, 0xd83d, 0xde08, 0xd83d, 0xde2c, 0xd83d, 0xde07, -0xd83d, 0xde0f, 0xd83d, 0xdc6e, 0xd83d, 0xdc77, 0xd83d, 0xdc82, 0xd83d, 0xdc76, 0xd83d, 0xdc68, -0xd83d, 0xdc69, 0xd83d, 0xdc74, 0xd83d, 0xdc75, 0xd83d, 0xde3b, 0xd83d, 0xde3d, 0xd83d, 0xde40, -0xd83d, 0xdc7a, 0xd83d, 0xde48, 0xd83d, 0xde49, 0xd83d, 0xde4a, 0xd83d, 0xdc80, 0xd83d, 0xdc7d, -0xd83d, 0xdca9, 0xd83d, 0xdd25, 0xd83d, 0xdca5, 0xd83d, 0xdca4, 0xd83d, 0xdc42, 0xd83d, 0xdc40, -0xd83d, 0xdc43, 0xd83d, 0xdc45, 0xd83d, 0xdc44, 0xd83d, 0xdc4d, 0xd83d, 0xdc4e, 0xd83d, 0xdc4c, -0xd83d, 0xdc4a, 0x270c, 0x270b, 0xd83d, 0xdc50, 0xd83d, 0xdc46, 0xd83d, 0xdc47, 0xd83d, 0xdc49, -0xd83d, 0xdc48, 0xd83d, 0xde4f, 0xd83d, 0xdc4f, 0xd83d, 0xdcaa, 0xd83d, 0xdeb6, 0xd83c, 0xdfc3, -0xd83d, 0xdc83, 0xd83d, 0xdc6b, 0xd83d, 0xdc6a, 0xd83d, 0xdc6c, 0xd83d, 0xdc6d, 0xd83d, 0xdc85, -0xd83c, 0xdfa9, 0xd83d, 0xdc51, 0xd83d, 0xdc52, 0xd83d, 0xdc5f, 0xd83d, 0xdc5e, 0xd83d, 0xdc60, -0xd83d, 0xdc55, 0xd83d, 0xdc57, 0xd83d, 0xdc56, 0xd83d, 0xdc59, 0xd83d, 0xdc5c, 0xd83d, 0xdc53, -0xd83c, 0xdf80, 0xd83d, 0xdc84, 0xd83d, 0xdc9b, 0xd83d, 0xdc99, 0xd83d, 0xdc9c, 0xd83d, 0xdc9a, -0xd83d, 0xdc8d, 0xd83d, 0xdc8e, 0xd83d, 0xdc36, 0xd83d, 0xdc3a, 0xd83d, 0xdc31, 0xd83d, 0xdc2d, -0xd83d, 0xdc39, 0xd83d, 0xdc30, 0xd83d, 0xdc38, 0xd83d, 0xdc2f, 0xd83d, 0xdc28, 0xd83d, 0xdc3b, -0xd83d, 0xdc37, 0xd83d, 0xdc2e, 0xd83d, 0xdc17, 0xd83d, 0xdc34, 0xd83d, 0xdc11, 0xd83d, 0xdc18, -0xd83d, 0xdc3c, 0xd83d, 0xdc27, 0xd83d, 0xdc25, 0xd83d, 0xdc14, 0xd83d, 0xdc0d, 0xd83d, 0xdc22, -0xd83d, 0xdc1b, 0xd83d, 0xdc1d, 0xd83d, 0xdc1c, 0xd83d, 0xdc1e, 0xd83d, 0xdc0c, 0xd83d, 0xdc19, -0xd83d, 0xdc1a, 0xd83d, 0xdc1f, 0xd83d, 0xdc2c, 0xd83d, 0xdc0b, 0xd83d, 0xdc10, 0xd83d, 0xdc0a, -0xd83d, 0xdc2b, 0xd83c, 0xdf40, 0xd83c, 0xdf39, 0xd83c, 0xdf3b, 0xd83c, 0xdf41, 0xd83c, 0xdf3e, -0xd83c, 0xdf44, 0xd83c, 0xdf35, 0xd83c, 0xdf34, 0xd83c, 0xdf33, 0xd83c, 0xdf1e, 0xd83c, 0xdf1a, -0xd83c, 0xdf19, 0xd83c, 0xdf0e, 0xd83c, 0xdf0b, 0x26a1, 0x2614, 0x2744, 0x26c4, 0xd83c, 0xdf00, -0xd83c, 0xdf08, 0xd83c, 0xdf0a, 0xd83c, 0xdf93, 0xd83c, 0xdf86, 0xd83c, 0xdf83, 0xd83d, 0xdc7b, -0xd83c, 0xdf85, 0xd83c, 0xdf84, 0xd83c, 0xdf81, 0xd83c, 0xdf88, 0xd83d, 0xdd2e, 0xd83c, 0xdfa5, -0xd83d, 0xdcf7, 0xd83d, 0xdcbf, 0xd83d, 0xdcbb, 0x260e, 0xd83d, 0xdce1, 0xd83d, 0xdcfa, 0xd83d, -0xdcfb, 0xd83d, 0xdd09, 0xd83d, 0xdd14, 0x23f3, 0x23f0, 0x231a, 0xd83d, 0xdd12, 0xd83d, 0xdd11, -0xd83d, 0xdd0e, 0xd83d, 0xdca1, 0xd83d, 0xdd26, 0xd83d, 0xdd0c, 0xd83d, 0xdd0b, 0xd83d, 0xdebf, -0xd83d, 0xdebd, 0xd83d, 0xdd27, 0xd83d, 0xdd28, 0xd83d, 0xdeaa, 0xd83d, 0xdeac, 0xd83d, 0xdca3, -0xd83d, 0xdd2b, 0xd83d, 0xdd2a, 0xd83d, 0xdc8a, 0xd83d, 0xdc89, 0xd83d, 0xdcb0, 0xd83d, 0xdcb5, -0xd83d, 0xdcb3, 0x2709, 0xd83d, 0xdceb, 0xd83d, 0xdce6, 0xd83d, 0xdcc5, 0xd83d, 0xdcc1, 0x2702, -0xd83d, 0xdccc, 0xd83d, 0xdcce, 0x2712, 0x270f, 0xd83d, 0xdcd0, 0xd83d, 0xdcda, 0xd83d, 0xdd2c, -0xd83d, 0xdd2d, 0xd83c, 0xdfa8, 0xd83c, 0xdfac, 0xd83c, 0xdfa4, 0xd83c, 0xdfa7, 0xd83c, 0xdfb5, -0xd83c, 0xdfb9, 0xd83c, 0xdfbb, 0xd83c, 0xdfba, 0xd83c, 0xdfb8, 0xd83d, 0xdc7e, 0xd83c, 0xdfae, -0xd83c, 0xdccf, 0xd83c, 0xdfb2, 0xd83c, 0xdfaf, 0xd83c, 0xdfc8, 0xd83c, 0xdfc0, 0x26bd, 0x26be, -0xd83c, 0xdfbe, 0xd83c, 0xdfb1, 0xd83c, 0xdfc9, 0xd83c, 0xdfb3, 0xd83c, 0xdfc1, 0xd83c, 0xdfc7, -0xd83c, 0xdfc6, 0xd83c, 0xdfca, 0xd83c, 0xdfc4, 0x2615, 0xd83c, 0xdf7c, 0xd83c, 0xdf7a, 0xd83c, -0xdf77, 0xd83c, 0xdf74, 0xd83c, 0xdf55, 0xd83c, 0xdf54, 0xd83c, 0xdf5f, 0xd83c, 0xdf57, 0xd83c, -0xdf71, 0xd83c, 0xdf5a, 0xd83c, 0xdf5c, 0xd83c, 0xdf61, 0xd83c, 0xdf73, 0xd83c, 0xdf5e, 0xd83c, -0xdf69, 0xd83c, 0xdf66, 0xd83c, 0xdf82, 0xd83c, 0xdf70, 0xd83c, 0xdf6a, 0xd83c, 0xdf6b, 0xd83c, -0xdf6d, 0xd83c, 0xdf6f, 0xd83c, 0xdf4e, 0xd83c, 0xdf4f, 0xd83c, 0xdf4a, 0xd83c, 0xdf4b, 0xd83c, -0xdf52, 0xd83c, 0xdf47, 0xd83c, 0xdf49, 0xd83c, 0xdf53, 0xd83c, 0xdf51, 0xd83c, 0xdf4c, 0xd83c, -0xdf50, 0xd83c, 0xdf4d, 0xd83c, 0xdf46, 0xd83c, 0xdf45, 0xd83c, 0xdf3d, 0xd83c, 0xdfe1, 0xd83c, -0xdfe5, 0xd83c, 0xdfe6, 0x26ea, 0xd83c, 0xdff0, 0x26fa, 0xd83c, 0xdfed, 0xd83d, 0xddfb, 0xd83d, -0xddfd, 0xd83c, 0xdfa0, 0xd83c, 0xdfa1, 0x26f2, 0xd83c, 0xdfa2, 0xd83d, 0xdea2, 0xd83d, 0xdea4, -0x2693, 0xd83d, 0xde80, 0x2708, 0xd83d, 0xde81, 0xd83d, 0xde82, 0xd83d, 0xde8b, 0xd83d, 0xde8e, -0xd83d, 0xde8c, 0xd83d, 0xde99, 0xd83d, 0xde97, 0xd83d, 0xde95, 0xd83d, 0xde9b, 0xd83d, 0xdea8, -0xd83d, 0xde94, 0xd83d, 0xde92, 0xd83d, 0xde91, 0xd83d, 0xdeb2, 0xd83d, 0xdea0, 0xd83d, 0xde9c, -0xd83d, 0xdea6, 0x26a0, 0xd83d, 0xdea7, 0x26fd, 0xd83c, 0xdfb0, 0xd83d, 0xddff, 0xd83c, 0xdfaa, -0xd83c, 0xdfad, 0xd83c, 0xddef, 0xd83c, 0xddf5, 0xd83c, 0xddf0, 0xd83c, 0xddf7, 0xd83c, 0xdde9, -0xd83c, 0xddea, 0xd83c, 0xdde8, 0xd83c, 0xddf3, 0xd83c, 0xddfa, 0xd83c, 0xddf8, 0xd83c, 0xddeb, -0xd83c, 0xddf7, 0xd83c, 0xddea, 0xd83c, 0xddf8, 0xd83c, 0xddee, 0xd83c, 0xddf9, 0xd83c, 0xddf7, -0xd83c, 0xddfa, 0xd83c, 0xddec, 0xd83c, 0xdde7, 0x0031, 0x20e3, 0x0032, 0x20e3, 0x0033, 0x20e3, -0x0034, 0x20e3, 0x0035, 0x20e3, 0x0036, 0x20e3, 0x0037, 0x20e3, 0x0038, 0x20e3, 0x0039, 0x20e3, -0x0030, 0x20e3, 0xd83d, 0xdd1f, 0x2757, 0x2753, 0x2665, 0x2666, 0xd83d, 0xdcaf, 0xd83d, 0xdd17, -0xd83d, 0xdd31, 0xd83d, 0xdd34, 0xd83d, 0xdd35, 0xd83d, 0xdd36, 0xd83d, 0xdd37 }; + 0xd83d, 0xde09, 0xd83d, 0xde0d, 0xd83d, 0xde1b, 0xd83d, 0xde2d, 0xd83d, 0xde31, 0xd83d, 0xde21, 0xd83d, 0xde0e, + 0xd83d, 0xde34, 0xd83d, 0xde35, 0xd83d, 0xde08, 0xd83d, 0xde2c, 0xd83d, 0xde07, 0xd83d, 0xde0f, 0xd83d, 0xdc6e, + 0xd83d, 0xdc77, 0xd83d, 0xdc82, 0xd83d, 0xdc76, 0xd83d, 0xdc68, 0xd83d, 0xdc69, 0xd83d, 0xdc74, 0xd83d, 0xdc75, + 0xd83d, 0xde3b, 0xd83d, 0xde3d, 0xd83d, 0xde40, 0xd83d, 0xdc7a, 0xd83d, 0xde48, 0xd83d, 0xde49, 0xd83d, 0xde4a, + 0xd83d, 0xdc80, 0xd83d, 0xdc7d, 0xd83d, 0xdca9, 0xd83d, 0xdd25, 0xd83d, 0xdca5, 0xd83d, 0xdca4, 0xd83d, 0xdc42, + 0xd83d, 0xdc40, 0xd83d, 0xdc43, 0xd83d, 0xdc45, 0xd83d, 0xdc44, 0xd83d, 0xdc4d, 0xd83d, 0xdc4e, 0xd83d, 0xdc4c, + 0xd83d, 0xdc4a, 0x270c, 0x270b, 0xd83d, 0xdc50, 0xd83d, 0xdc46, 0xd83d, 0xdc47, 0xd83d, 0xdc49, 0xd83d, 0xdc48, + 0xd83d, 0xde4f, 0xd83d, 0xdc4f, 0xd83d, 0xdcaa, 0xd83d, 0xdeb6, 0xd83c, 0xdfc3, 0xd83d, 0xdc83, 0xd83d, 0xdc6b, + 0xd83d, 0xdc6a, 0xd83d, 0xdc6c, 0xd83d, 0xdc6d, 0xd83d, 0xdc85, 0xd83c, 0xdfa9, 0xd83d, 0xdc51, 0xd83d, 0xdc52, + 0xd83d, 0xdc5f, 0xd83d, 0xdc5e, 0xd83d, 0xdc60, 0xd83d, 0xdc55, 0xd83d, 0xdc57, 0xd83d, 0xdc56, 0xd83d, 0xdc59, + 0xd83d, 0xdc5c, 0xd83d, 0xdc53, 0xd83c, 0xdf80, 0xd83d, 0xdc84, 0xd83d, 0xdc9b, 0xd83d, 0xdc99, 0xd83d, 0xdc9c, + 0xd83d, 0xdc9a, 0xd83d, 0xdc8d, 0xd83d, 0xdc8e, 0xd83d, 0xdc36, 0xd83d, 0xdc3a, 0xd83d, 0xdc31, 0xd83d, 0xdc2d, + 0xd83d, 0xdc39, 0xd83d, 0xdc30, 0xd83d, 0xdc38, 0xd83d, 0xdc2f, 0xd83d, 0xdc28, 0xd83d, 0xdc3b, 0xd83d, 0xdc37, + 0xd83d, 0xdc2e, 0xd83d, 0xdc17, 0xd83d, 0xdc34, 0xd83d, 0xdc11, 0xd83d, 0xdc18, 0xd83d, 0xdc3c, 0xd83d, 0xdc27, + 0xd83d, 0xdc25, 0xd83d, 0xdc14, 0xd83d, 0xdc0d, 0xd83d, 0xdc22, 0xd83d, 0xdc1b, 0xd83d, 0xdc1d, 0xd83d, 0xdc1c, + 0xd83d, 0xdc1e, 0xd83d, 0xdc0c, 0xd83d, 0xdc19, 0xd83d, 0xdc1a, 0xd83d, 0xdc1f, 0xd83d, 0xdc2c, 0xd83d, 0xdc0b, + 0xd83d, 0xdc10, 0xd83d, 0xdc0a, 0xd83d, 0xdc2b, 0xd83c, 0xdf40, 0xd83c, 0xdf39, 0xd83c, 0xdf3b, 0xd83c, 0xdf41, + 0xd83c, 0xdf3e, 0xd83c, 0xdf44, 0xd83c, 0xdf35, 0xd83c, 0xdf34, 0xd83c, 0xdf33, 0xd83c, 0xdf1e, 0xd83c, 0xdf1a, + 0xd83c, 0xdf19, 0xd83c, 0xdf0e, 0xd83c, 0xdf0b, 0x26a1, 0x2614, 0x2744, 0x26c4, 0xd83c, 0xdf00, 0xd83c, 0xdf08, + 0xd83c, 0xdf0a, 0xd83c, 0xdf93, 0xd83c, 0xdf86, 0xd83c, 0xdf83, 0xd83d, 0xdc7b, 0xd83c, 0xdf85, 0xd83c, 0xdf84, + 0xd83c, 0xdf81, 0xd83c, 0xdf88, 0xd83d, 0xdd2e, 0xd83c, 0xdfa5, 0xd83d, 0xdcf7, 0xd83d, 0xdcbf, 0xd83d, 0xdcbb, + 0x260e, 0xd83d, 0xdce1, 0xd83d, 0xdcfa, 0xd83d, 0xdcfb, 0xd83d, 0xdd09, 0xd83d, 0xdd14, 0x23f3, 0x23f0, 0x231a, + 0xd83d, 0xdd12, 0xd83d, 0xdd11, 0xd83d, 0xdd0e, 0xd83d, 0xdca1, 0xd83d, 0xdd26, 0xd83d, 0xdd0c, 0xd83d, 0xdd0b, + 0xd83d, 0xdebf, 0xd83d, 0xdebd, 0xd83d, 0xdd27, 0xd83d, 0xdd28, 0xd83d, 0xdeaa, 0xd83d, 0xdeac, 0xd83d, 0xdca3, + 0xd83d, 0xdd2b, 0xd83d, 0xdd2a, 0xd83d, 0xdc8a, 0xd83d, 0xdc89, 0xd83d, 0xdcb0, 0xd83d, 0xdcb5, 0xd83d, 0xdcb3, + 0x2709, 0xd83d, 0xdceb, 0xd83d, 0xdce6, 0xd83d, 0xdcc5, 0xd83d, 0xdcc1, 0x2702, 0xd83d, 0xdccc, 0xd83d, 0xdcce, + 0x2712, 0x270f, 0xd83d, 0xdcd0, 0xd83d, 0xdcda, 0xd83d, 0xdd2c, 0xd83d, 0xdd2d, 0xd83c, 0xdfa8, 0xd83c, 0xdfac, + 0xd83c, 0xdfa4, 0xd83c, 0xdfa7, 0xd83c, 0xdfb5, 0xd83c, 0xdfb9, 0xd83c, 0xdfbb, 0xd83c, 0xdfba, 0xd83c, 0xdfb8, + 0xd83d, 0xdc7e, 0xd83c, 0xdfae, 0xd83c, 0xdccf, 0xd83c, 0xdfb2, 0xd83c, 0xdfaf, 0xd83c, 0xdfc8, 0xd83c, 0xdfc0, + 0x26bd, 0x26be, 0xd83c, 0xdfbe, 0xd83c, 0xdfb1, 0xd83c, 0xdfc9, 0xd83c, 0xdfb3, 0xd83c, 0xdfc1, 0xd83c, 0xdfc7, + 0xd83c, 0xdfc6, 0xd83c, 0xdfca, 0xd83c, 0xdfc4, 0x2615, 0xd83c, 0xdf7c, 0xd83c, 0xdf7a, 0xd83c, 0xdf77, 0xd83c, + 0xdf74, 0xd83c, 0xdf55, 0xd83c, 0xdf54, 0xd83c, 0xdf5f, 0xd83c, 0xdf57, 0xd83c, 0xdf71, 0xd83c, 0xdf5a, 0xd83c, + 0xdf5c, 0xd83c, 0xdf61, 0xd83c, 0xdf73, 0xd83c, 0xdf5e, 0xd83c, 0xdf69, 0xd83c, 0xdf66, 0xd83c, 0xdf82, 0xd83c, + 0xdf70, 0xd83c, 0xdf6a, 0xd83c, 0xdf6b, 0xd83c, 0xdf6d, 0xd83c, 0xdf6f, 0xd83c, 0xdf4e, 0xd83c, 0xdf4f, 0xd83c, + 0xdf4a, 0xd83c, 0xdf4b, 0xd83c, 0xdf52, 0xd83c, 0xdf47, 0xd83c, 0xdf49, 0xd83c, 0xdf53, 0xd83c, 0xdf51, 0xd83c, + 0xdf4c, 0xd83c, 0xdf50, 0xd83c, 0xdf4d, 0xd83c, 0xdf46, 0xd83c, 0xdf45, 0xd83c, 0xdf3d, 0xd83c, 0xdfe1, 0xd83c, + 0xdfe5, 0xd83c, 0xdfe6, 0x26ea, 0xd83c, 0xdff0, 0x26fa, 0xd83c, 0xdfed, 0xd83d, 0xddfb, 0xd83d, 0xddfd, 0xd83c, + 0xdfa0, 0xd83c, 0xdfa1, 0x26f2, 0xd83c, 0xdfa2, 0xd83d, 0xdea2, 0xd83d, 0xdea4, 0x2693, 0xd83d, 0xde80, 0x2708, + 0xd83d, 0xde81, 0xd83d, 0xde82, 0xd83d, 0xde8b, 0xd83d, 0xde8e, 0xd83d, 0xde8c, 0xd83d, 0xde99, 0xd83d, 0xde97, + 0xd83d, 0xde95, 0xd83d, 0xde9b, 0xd83d, 0xdea8, 0xd83d, 0xde94, 0xd83d, 0xde92, 0xd83d, 0xde91, 0xd83d, 0xdeb2, + 0xd83d, 0xdea0, 0xd83d, 0xde9c, 0xd83d, 0xdea6, 0x26a0, 0xd83d, 0xdea7, 0x26fd, 0xd83c, 0xdfb0, 0xd83d, 0xddff, + 0xd83c, 0xdfaa, 0xd83c, 0xdfad, 0xd83c, 0xddef, 0xd83c, 0xddf5, 0xd83c, 0xddf0, 0xd83c, 0xddf7, 0xd83c, 0xdde9, + 0xd83c, 0xddea, 0xd83c, 0xdde8, 0xd83c, 0xddf3, 0xd83c, 0xddfa, 0xd83c, 0xddf8, 0xd83c, 0xddeb, 0xd83c, 0xddf7, + 0xd83c, 0xddea, 0xd83c, 0xddf8, 0xd83c, 0xddee, 0xd83c, 0xddf9, 0xd83c, 0xddf7, 0xd83c, 0xddfa, 0xd83c, 0xddec, + 0xd83c, 0xdde7, 0x0031, 0x20e3, 0x0032, 0x20e3, 0x0033, 0x20e3, 0x0034, 0x20e3, 0x0035, 0x20e3, 0x0036, 0x20e3, + 0x0037, 0x20e3, 0x0038, 0x20e3, 0x0039, 0x20e3, 0x0030, 0x20e3, 0xd83d, 0xdd1f, 0x2757, 0x2753, 0x2665, 0x2666, + 0xd83d, 0xdcaf, 0xd83d, 0xdd17, 0xd83d, 0xdd31, 0xd83d, 0xdd34, 0xd83d, 0xdd35, 0xd83d, 0xdd36, 0xd83d, 0xdd37}; ushort Offsets[] = { -0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, -24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, -48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, -72, 74, 76, 78, 80, 82, 84, 86, 87, 88, 90, 92, -94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, -118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, -142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, -166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, -190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, -214, 216, 218, 220, 222, 224, 226, 228, 230, 232, 234, 236, -238, 240, 242, 244, 246, 248, 250, 252, 254, 256, 258, 259, -260, 261, 262, 264, 266, 268, 270, 272, 274, 276, 278, 280, -282, 284, 286, 288, 290, 292, 294, 295, 297, 299, 301, 303, -305, 306, 307, 308, 310, 312, 314, 316, 318, 320, 322, 324, -326, 328, 330, 332, 334, 336, 338, 340, 342, 344, 346, 348, -350, 351, 353, 355, 357, 359, 360, 362, 364, 365, 366, 368, -370, 372, 374, 376, 378, 380, 382, 384, 386, 388, 390, 392, -394, 396, 398, 400, 402, 404, 406, 407, 408, 410, 412, 414, -416, 418, 420, 422, 424, 426, 427, 429, 431, 433, 435, 437, -439, 441, 443, 445, 447, 449, 451, 453, 455, 457, 459, 461, -463, 465, 467, 469, 471, 473, 475, 477, 479, 481, 483, 485, -487, 489, 491, 493, 495, 497, 499, 501, 503, 505, 507, 508, -510, 511, 513, 515, 517, 519, 521, 522, 524, 526, 528, 529, -531, 532, 534, 536, 538, 540, 542, 544, 546, 548, 550, 552, -554, 556, 558, 560, 562, 564, 566, 567, 569, 570, 572, 574, -576, 578, 582, 586, 590, 594, 598, 602, 606, 610, 614, 618, -620, 622, 624, 626, 628, 630, 632, 634, 636, 638, 640, 641, -642, 643, 644, 646, 648, 650, 652, 654, 656, 658 }; + 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, + 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 87, 88, + 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, + 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, + 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, + 228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248, 250, 252, 254, 256, 258, 259, 260, 261, 262, 264, 266, 268, + 270, 272, 274, 276, 278, 280, 282, 284, 286, 288, 290, 292, 294, 295, 297, 299, 301, 303, 305, 306, 307, 308, 310, + 312, 314, 316, 318, 320, 322, 324, 326, 328, 330, 332, 334, 336, 338, 340, 342, 344, 346, 348, 350, 351, 353, 355, + 357, 359, 360, 362, 364, 365, 366, 368, 370, 372, 374, 376, 378, 380, 382, 384, 386, 388, 390, 392, 394, 396, 398, + 400, 402, 404, 406, 407, 408, 410, 412, 414, 416, 418, 420, 422, 424, 426, 427, 429, 431, 433, 435, 437, 439, 441, + 443, 445, 447, 449, 451, 453, 455, 457, 459, 461, 463, 465, 467, 469, 471, 473, 475, 477, 479, 481, 483, 485, 487, + 489, 491, 493, 495, 497, 499, 501, 503, 505, 507, 508, 510, 511, 513, 515, 517, 519, 521, 522, 524, 526, 528, 529, + 531, 532, 534, 536, 538, 540, 542, 544, 546, 548, 550, 552, 554, 556, 558, 560, 562, 564, 566, 567, 569, 570, 572, + 574, 576, 578, 582, 586, 590, 594, 598, 602, 606, 610, 614, 618, 620, 622, 624, 626, 628, 630, 632, 634, 636, 638, + 640, 641, 642, 643, 644, 646, 648, 650, 652, 654, 656, 658}; -uint64 ComputeEmojiIndex(base::const_byte_span bytes) { +quint64 ComputeEmojiIndex(base::const_byte_span bytes) { Expects(bytes.size() == 8); - return ((gsl::to_integer(bytes[0]) & 0x7F) << 56) - | (gsl::to_integer(bytes[1]) << 48) - | (gsl::to_integer(bytes[2]) << 40) - | (gsl::to_integer(bytes[3]) << 32) - | (gsl::to_integer(bytes[4]) << 24) - | (gsl::to_integer(bytes[5]) << 16) - | (gsl::to_integer(bytes[6]) << 8) - | (gsl::to_integer(bytes[7])); + return ((gsl::to_integer(bytes[0]) & 0x7F) << 56) | (gsl::to_integer(bytes[1]) << 48) | + (gsl::to_integer(bytes[2]) << 40) | (gsl::to_integer(bytes[3]) << 32) | + (gsl::to_integer(bytes[4]) << 24) | (gsl::to_integer(bytes[5]) << 16) | + (gsl::to_integer(bytes[6]) << 8) | (gsl::to_integer(bytes[7])); } } // namespace @@ -151,7 +128,6 @@ std::vector ComputeEmojiFingerprint(not_null call) { } } return result; - } } // namespace Calls diff --git a/Telegram/SourceFiles/calls/calls_emoji_fingerprint.h b/Telegram/SourceFiles/calls/calls_emoji_fingerprint.h index 9fe4c7279..c3729cb05 100644 --- a/Telegram/SourceFiles/calls/calls_emoji_fingerprint.h +++ b/Telegram/SourceFiles/calls/calls_emoji_fingerprint.h @@ -1,25 +1,31 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once +#include "settings.h" +#include +#include + namespace Calls { class Call; diff --git a/Telegram/SourceFiles/calls/calls_instance.cpp b/Telegram/SourceFiles/calls/calls_instance.cpp index 9bb9447f8..ec2de9a72 100644 --- a/Telegram/SourceFiles/calls/calls_instance.cpp +++ b/Telegram/SourceFiles/calls/calls_instance.cpp @@ -1,36 +1,45 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// + #include "calls/calls_instance.h" +#include +#include +#include +#include -#include "mtproto/connection.h" -#include "messenger.h" -#include "auth_session.h" #include "apiwrap.h" -#include "lang/lang_keys.h" +#include "auth_session.h" #include "boxes/confirm_box.h" #include "calls/calls_call.h" #include "calls/calls_panel.h" +#include "lang/lang_keys.h" #include "media/media_audio_track.h" +#include "messenger.h" +#include "mtproto/connection.h" +#include "app.h" #include "boxes/rate_call_box.h" + namespace Calls { namespace { @@ -40,7 +49,7 @@ constexpr auto kServerConfigUpdateTimeoutMs = 24 * 3600 * TimeMs(1000); Instance::Instance() = default; -void Instance::startOutgoingCall(not_null user) { +void Instance::startOutgoingCall(not_null user) { if (alreadyInCall()) { // Already in a call. _currentCallPanel->showAndActivate(); return; @@ -54,15 +63,15 @@ void Instance::startOutgoingCall(not_null user) { createCall(user, Call::Type::Outgoing); } -void Instance::callFinished(not_null call) { +void Instance::callFinished(not_null call) { destroyCall(call); } -void Instance::callFailed(not_null call) { +void Instance::callFailed(not_null call) { destroyCall(call); } -void Instance::callRedial(not_null call) { +void Instance::callRedial(not_null call) { if (_currentCall.get() == call) { refreshDhConfig(); } @@ -96,7 +105,7 @@ void Instance::playSound(Sound sound) { } } -void Instance::destroyCall(not_null call) { +void Instance::destroyCall(not_null call) { if (_currentCall.get() == call) { destroyCurrentPanel(); _currentCall.reset(); @@ -110,15 +119,16 @@ void Instance::destroyCall(not_null call) { } void Instance::destroyCurrentPanel() { - _pendingPanels.erase(std::remove_if(_pendingPanels.begin(), _pendingPanels.end(), [](auto &&panel) { - return !panel; - }), _pendingPanels.end()); + _pendingPanels.erase( + std::remove_if(_pendingPanels.begin(), _pendingPanels.end(), [](auto &&panel) { return !panel; }), + _pendingPanels.end()); _pendingPanels.push_back(_currentCallPanel.release()); _pendingPanels.back()->hideAndDestroy(); // Always queues the destruction. } -void Instance::createCall(not_null user, Call::Type type) { - auto call = std::make_unique(getCallDelegate(), user, type);; +void Instance::createCall(not_null user, Call::Type type) { + auto call = std::make_unique(getCallDelegate(), user, type); + ; if (_currentCall) { _currentCallPanel->replaceCall(call.get()); std::swap(_currentCall, call); @@ -134,49 +144,52 @@ void Instance::createCall(not_null user, Call::Type type) { void Instance::refreshDhConfig() { Expects(_currentCall != nullptr); - request(MTPmessages_GetDhConfig(MTP_int(_dhConfig.version), MTP_int(Call::kRandomPowerSize))).done([this, call = base::make_weak_unique(_currentCall)](const MTPmessages_DhConfig &result) { - auto random = base::const_byte_span(); - switch (result.type()) { - case mtpc_messages_dhConfig: { - auto &config = result.c_messages_dhConfig(); - if (!MTP::IsPrimeAndGood(bytesFromMTP(config.vp), config.vg.v)) { - LOG(("API Error: bad p/g received in dhConfig.")); - callFailed(call.get()); - return; - } - _dhConfig.g = config.vg.v; - _dhConfig.p = byteVectorFromMTP(config.vp); - random = bytesFromMTP(config.vrandom); - } break; - - case mtpc_messages_dhConfigNotModified: { - auto &config = result.c_messages_dhConfigNotModified(); - random = bytesFromMTP(config.vrandom); - if (!_dhConfig.g || _dhConfig.p.empty()) { - LOG(("API Error: dhConfigNotModified on zero version.")); - callFailed(call.get()); - return; - } - } break; - - default: Unexpected("Type in messages.getDhConfig"); - } - - if (random.size() != Call::kRandomPowerSize) { - LOG(("API Error: dhConfig random bytes wrong size: %1").arg(random.size())); - callFailed(call.get()); - return; - } - if (call) { - call->start(random); - } - }).fail([this, call = base::make_weak_unique(_currentCall)](const RPCError &error) { - if (!call) { - DEBUG_LOG(("API Warning: call was destroyed before got dhConfig.")); - return; - } - callFailed(call.get()); - }).send(); + request(MTPmessages_GetDhConfig(MTP_int(_dhConfig.version), MTP_int(Call::kRandomPowerSize))) + .done([this, call = base::make_weak_unique(_currentCall)](const MTPmessages_DhConfig &result) { + auto random = base::const_byte_span(); + switch (result.type()) { + case mtpc_messages_dhConfig: { + auto &config = result.c_messages_dhConfig(); + if (!MTP::IsPrimeAndGood(bytesFromMTP(config.vp), config.vg.v)) { + LOG(("API Error: bad p/g received in dhConfig.")); + callFailed(call.get()); + return; + } + _dhConfig.g = config.vg.v; + _dhConfig.p = byteVectorFromMTP(config.vp); + random = bytesFromMTP(config.vrandom); + } break; + + case mtpc_messages_dhConfigNotModified: { + auto &config = result.c_messages_dhConfigNotModified(); + random = bytesFromMTP(config.vrandom); + if (!_dhConfig.g || _dhConfig.p.empty()) { + LOG(("API Error: dhConfigNotModified on zero version.")); + callFailed(call.get()); + return; + } + } break; + + default: Unexpected("Type in messages.getDhConfig"); + } + + if (random.size() != Call::kRandomPowerSize) { + LOG(("API Error: dhConfig random bytes wrong size: %1").arg(random.size())); + callFailed(call.get()); + return; + } + if (call) { + call->start(random); + } + }) + .fail([this, call = base::make_weak_unique(_currentCall)](const RPCError &error) { + if (!call) { + DEBUG_LOG(("API Warning: call was destroyed before got dhConfig.")); + return; + } + callFailed(call.get()); + }) + .send(); } void Instance::refreshServerConfig() { @@ -186,67 +199,72 @@ void Instance::refreshServerConfig() { if (_lastServerConfigUpdateTime && (getms(true) - _lastServerConfigUpdateTime) < kServerConfigUpdateTimeoutMs) { return; } - _serverConfigRequestId = request(MTPphone_GetCallConfig()).done([this](const MTPDataJSON &result) { - _serverConfigRequestId = 0; - _lastServerConfigUpdateTime = getms(true); - - auto configUpdate = std::map(); - auto bytes = bytesFromMTP(result.c_dataJSON().vdata); - auto error = QJsonParseError { 0, QJsonParseError::NoError }; - auto document = QJsonDocument::fromJson(QByteArray::fromRawData(reinterpret_cast(bytes.data()), bytes.size()), &error); - if (error.error != QJsonParseError::NoError) { - LOG(("API Error: Failed to parse call config JSON, error: %1").arg(error.errorString())); - return; - } else if (!document.isObject()) { - LOG(("API Error: Not an object received in call config JSON.")); - return; - } - - auto parseValue = [](QJsonValueRef data) -> std::string { - switch (data.type()) { - case QJsonValue::String: return data.toString().toStdString(); - case QJsonValue::Double: return QString::number(data.toDouble(), 'f').toStdString(); - case QJsonValue::Bool: return data.toBool() ? "true" : "false"; - case QJsonValue::Null: { - LOG(("API Warning: null field in call config JSON.")); - } return "null"; - case QJsonValue::Undefined: { - LOG(("API Warning: undefined field in call config JSON.")); - } return "undefined"; - case QJsonValue::Object: - case QJsonValue::Array: { - LOG(("API Warning: complex field in call config JSON.")); - QJsonDocument serializer; - if (data.isArray()) { - serializer.setArray(data.toArray()); - } else { - serializer.setObject(data.toObject()); - } - auto byteArray = serializer.toJson(QJsonDocument::Compact); - return std::string(byteArray.constData(), byteArray.size()); - } break; - } - Unexpected("Type in Json parse."); - }; - - auto object = document.object(); - for (auto i = object.begin(), e = object.end(); i != e; ++i) { - auto key = i.key().toStdString(); - auto value = parseValue(i.value()); - configUpdate[key] = value; - } - - UpdateConfig(configUpdate); - }).fail([this](const RPCError &error) { - _serverConfigRequestId = 0; - }).send(); + _serverConfigRequestId = + request(MTPphone_GetCallConfig()) + .done([this](const MTPDataJSON &result) { + _serverConfigRequestId = 0; + _lastServerConfigUpdateTime = getms(true); + + auto configUpdate = std::map(); + auto bytes = bytesFromMTP(result.c_dataJSON().vdata); + auto error = QJsonParseError{0, QJsonParseError::NoError}; + auto document = QJsonDocument::fromJson( + QByteArray::fromRawData(reinterpret_cast(bytes.data()), bytes.size()), &error); + if (error.error != QJsonParseError::NoError) { + LOG(("API Error: Failed to parse call config JSON, error: %1").arg(error.errorString())); + return; + } else if (!document.isObject()) { + LOG(("API Error: Not an object received in call config JSON.")); + return; + } + + auto parseValue = [](QJsonValueRef data) -> std::string { + switch (data.type()) { + case QJsonValue::String: return data.toString().toStdString(); + case QJsonValue::Double: return QString::number(data.toDouble(), 'f').toStdString(); + case QJsonValue::Bool: return data.toBool() ? "true" : "false"; + case QJsonValue::Null: { + LOG(("API Warning: null field in call config JSON.")); + } + return "null"; + case QJsonValue::Undefined: { + LOG(("API Warning: undefined field in call config JSON.")); + } + return "undefined"; + case QJsonValue::Object: + case QJsonValue::Array: { + LOG(("API Warning: complex field in call config JSON.")); + QJsonDocument serializer; + if (data.isArray()) { + serializer.setArray(data.toArray()); + } else { + serializer.setObject(data.toObject()); + } + auto byteArray = serializer.toJson(QJsonDocument::Compact); + return std::string(byteArray.constData(), byteArray.size()); + } break; + } + Unexpected("Type in Json parse."); + }; + + auto object = document.object(); + for (auto i = object.begin(), e = object.end(); i != e; ++i) { + auto key = i.key().toStdString(); + auto value = parseValue(i.value()); + configUpdate[key] = value; + } + + UpdateConfig(configUpdate); + }) + .fail([this](const RPCError &error) { _serverConfigRequestId = 0; }) + .send(); } -void Instance::handleUpdate(const MTPDupdatePhoneCall& update) { +void Instance::handleUpdate(const MTPDupdatePhoneCall &update) { handleCallUpdate(update.vphone_call); } -void Instance::showInfoPanel(not_null call) { +void Instance::showInfoPanel(not_null call) { if (_currentCall.get() == call) { _currentCallPanel->showAndActivate(); } @@ -274,7 +292,9 @@ void Instance::handleCallUpdate(const MTPPhoneCall &call) { LOG(("API Error: Self found in phoneCallRequested.")); } if (alreadyInCall() || !user || user->isSelf()) { - request(MTPphone_DiscardCall(MTP_inputPhoneCall(phoneCall.vid, phoneCall.vaccess_hash), MTP_int(0), MTP_phoneCallDiscardReasonBusy(), MTP_long(0))).send(); + request(MTPphone_DiscardCall(MTP_inputPhoneCall(phoneCall.vid, phoneCall.vaccess_hash), MTP_int(0), + MTP_phoneCallDiscardReasonBusy(), MTP_long(0))) + .send(); } else if (phoneCall.vdate.v + (Global::CallRingTimeoutMs() / 1000) < unixtime()) { LOG(("Ignoring too old call.")); } else { diff --git a/Telegram/SourceFiles/calls/calls_instance.h b/Telegram/SourceFiles/calls/calls_instance.h index 89c8c7163..447dd3058 100644 --- a/Telegram/SourceFiles/calls/calls_instance.h +++ b/Telegram/SourceFiles/calls/calls_instance.h @@ -1,27 +1,29 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #pragma once -#include "mtproto/sender.h" #include "calls/calls_call.h" +#include "mtproto/sender.h" namespace Media { namespace Audio { @@ -37,11 +39,11 @@ class Instance : private MTP::Sender, private Call::Delegate, private base::Subs public: Instance(); - void startOutgoingCall(not_null user); + void startOutgoingCall(not_null user); void handleUpdate(const MTPDupdatePhoneCall &update); - void showInfoPanel(not_null call); + void showInfoPanel(not_null call); - base::Observable ¤tCallChanged() { + base::Observable ¤tCallChanged() { return _currentCallChanged; } @@ -54,19 +56,19 @@ class Instance : private MTP::Sender, private Call::Delegate, private base::Subs ~Instance(); private: - not_null getCallDelegate() { - return static_cast(this); + not_null getCallDelegate() { + return static_cast(this); } DhConfig getDhConfig() const override { return _dhConfig; } - void callFinished(not_null call) override; - void callFailed(not_null call) override; - void callRedial(not_null call) override; + void callFinished(not_null call) override; + void callFailed(not_null call) override; + void callRedial(not_null call) override; using Sound = Call::Delegate::Sound; void playSound(Sound sound) override; - void createCall(not_null user, Call::Type type); - void destroyCall(not_null call); + void createCall(not_null user, Call::Type type); + void destroyCall(not_null call); void destroyCurrentPanel(); void refreshDhConfig(); @@ -82,14 +84,13 @@ class Instance : private MTP::Sender, private Call::Delegate, private base::Subs std::unique_ptr _currentCall; std::unique_ptr _currentCallPanel; - base::Observable _currentCallChanged; + base::Observable _currentCallChanged; base::Observable _newServiceMessage; std::vector> _pendingPanels; std::unique_ptr _callConnectingTrack; std::unique_ptr _callEndedTrack; std::unique_ptr _callBusyTrack; - }; Instance &Current(); diff --git a/Telegram/SourceFiles/calls/calls_panel.cpp b/Telegram/SourceFiles/calls/calls_panel.cpp index 2a7aa37a9..09aac0753 100644 --- a/Telegram/SourceFiles/calls/calls_panel.cpp +++ b/Telegram/SourceFiles/calls/calls_panel.cpp @@ -1,42 +1,47 @@ -/* -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. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org -*/ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka 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. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// #include "calls/calls_panel.h" +#include +#include "apiwrap.h" +#include "app.h" +#include "auth_session.h" +#include "base/task_queue.h" #include "calls/calls_emoji_fingerprint.h" +#include "lang/lang_keys.h" +#include "mainwindow.h" +#include "messenger.h" +#include "observer_peer.h" +#include "platform/platform_specific.h" #include "styles/style_calls.h" #include "styles/style_history.h" +#include "ui/effects/ripple_animation.h" +#include "ui/effects/widget_fade_wrap.h" #include "ui/widgets/buttons.h" #include "ui/widgets/labels.h" #include "ui/widgets/shadow.h" -#include "ui/effects/ripple_animation.h" -#include "ui/effects/widget_fade_wrap.h" -#include "messenger.h" -#include "mainwindow.h" -#include "lang/lang_keys.h" -#include "auth_session.h" -#include "apiwrap.h" -#include "observer_peer.h" -#include "platform/platform_specific.h" -#include "base/task_queue.h" #include "window/main_window.h" +#include namespace Calls { namespace { @@ -49,8 +54,8 @@ class Panel::Button : public Ui::RippleButton { public: Button(QWidget *parent, const style::CallButton &stFrom, const style::CallButton *stTo = nullptr); - void setProgress(float64 progress); - void setOuterValue(float64 value); + void setProgress(double progress); + void setOuterValue(double value); protected: void paintEvent(QPaintEvent *e) override; @@ -61,25 +66,25 @@ class Panel::Button : public Ui::RippleButton { QPoint prepareRippleStartPosition() const override; private: - QPoint iconPosition(not_null st) const; + QPoint iconPosition(not_null st) const; void mixIconMasks(); - not_null _stFrom; + not_null _stFrom; const style::CallButton *_stTo = nullptr; - float64 _progress = 0.; + double _progress = 0.; QImage _bgMask, _bg; QPixmap _bgFrom, _bgTo; QImage _iconMixedMask, _iconFrom, _iconTo, _iconMixed; - float64 _outerValue = 0.; + double _outerValue = 0.; Animation _outerAnimation; - }; -Panel::Button::Button(QWidget *parent, const style::CallButton &stFrom, const style::CallButton *stTo) : Ui::RippleButton(parent, stFrom.button.ripple) -, _stFrom(&stFrom) -, _stTo(stTo) { +Panel::Button::Button(QWidget *parent, const style::CallButton &stFrom, const style::CallButton *stTo) + : Ui::RippleButton(parent, stFrom.button.ripple) + , _stFrom(&stFrom) + , _stTo(stTo) { resize(_stFrom->button.width, _stFrom->button.height); _bgMask = prepareRippleMask(); @@ -100,32 +105,38 @@ Panel::Button::Button(QWidget *parent, const style::CallButton &stFrom, const st _iconFrom.fill(Qt::black); { Painter p(&_iconFrom); - p.drawImage((_stFrom->button.rippleAreaSize - _stFrom->button.icon.width()) / 2, (_stFrom->button.rippleAreaSize - _stFrom->button.icon.height()) / 2, _stFrom->button.icon.instance(Qt::white)); + p.drawImage((_stFrom->button.rippleAreaSize - _stFrom->button.icon.width()) / 2, + (_stFrom->button.rippleAreaSize - _stFrom->button.icon.height()) / 2, + _stFrom->button.icon.instance(Qt::white)); } _iconTo = QImage(_bgMask.size(), QImage::Format_ARGB32_Premultiplied); _iconTo.setDevicePixelRatio(cRetinaFactor()); _iconTo.fill(Qt::black); { Painter p(&_iconTo); - p.drawImage((_stTo->button.rippleAreaSize - _stTo->button.icon.width()) / 2, (_stTo->button.rippleAreaSize - _stTo->button.icon.height()) / 2, _stTo->button.icon.instance(Qt::white)); + p.drawImage((_stTo->button.rippleAreaSize - _stTo->button.icon.width()) / 2, + (_stTo->button.rippleAreaSize - _stTo->button.icon.height()) / 2, + _stTo->button.icon.instance(Qt::white)); } _iconMixed = QImage(_bgMask.size(), QImage::Format_ARGB32_Premultiplied); _iconMixed.setDevicePixelRatio(cRetinaFactor()); } } -void Panel::Button::setOuterValue(float64 value) { +void Panel::Button::setOuterValue(double value) { if (_outerValue != value) { - _outerAnimation.start([this] { - if (_progress == 0. || _progress == 1.) { - update(); - } - }, _outerValue, value, Call::kSoundSampleMs); + _outerAnimation.start( + [this] { + if (_progress == 0. || _progress == 1.) { + update(); + } + }, + _outerValue, value, Call::kSoundSampleMs); _outerValue = value; } } -void Panel::Button::setProgress(float64 progress) { +void Panel::Button::setProgress(double progress) { _progress = progress; update(); } @@ -140,9 +151,13 @@ void Panel::Button::paintEvent(QPaintEvent *e) { auto outerValue = _outerAnimation.current(ms, _outerValue); if (outerValue > 0.) { - auto outerRadius = paintFrom ? _stFrom->outerRadius : paintTo ? _stTo->outerRadius : (_stFrom->outerRadius * (1. - _progress) + _stTo->outerRadius * _progress); + auto outerRadius = paintFrom ? + _stFrom->outerRadius : + paintTo ? _stTo->outerRadius : + (_stFrom->outerRadius * (1. - _progress) + _stTo->outerRadius * _progress); auto outerPixels = outerValue * outerRadius; - auto outerRect = QRectF(myrtlrect(bgPosition.x(), bgPosition.y(), _stFrom->button.rippleAreaSize, _stFrom->button.rippleAreaSize)); + auto outerRect = QRectF( + myrtlrect(bgPosition.x(), bgPosition.y(), _stFrom->button.rippleAreaSize, _stFrom->button.rippleAreaSize)); outerRect = outerRect.marginsAdded(QMarginsF(outerPixels, outerPixels, outerPixels, outerPixels)); PainterHighQualityEnabler hq(p); @@ -175,7 +190,8 @@ void Panel::Button::paintEvent(QPaintEvent *e) { } else { rippleColorInterpolated = anim::color(_stFrom->button.ripple.color, _stTo->button.ripple.color, _progress); } - paintRipple(p, _stFrom->button.rippleAreaPosition.x(), _stFrom->button.rippleAreaPosition.y(), ms, rippleColorOverride); + paintRipple(p, _stFrom->button.rippleAreaPosition.x(), _stFrom->button.rippleAreaPosition.y(), ms, + rippleColorOverride); auto positionFrom = iconPosition(_stFrom); if (paintFrom) { @@ -192,7 +208,7 @@ void Panel::Button::paintEvent(QPaintEvent *e) { } } -QPoint Panel::Button::iconPosition(not_null st) const { +QPoint Panel::Button::iconPosition(not_null st) const { auto result = st->button.iconPosition; if (result.x() < 0) { result.setX((width() - st->button.icon.width()) / 2); @@ -208,7 +224,7 @@ void Panel::Button::mixIconMasks() { Painter p(&_iconMixedMask); PainterHighQualityEnabler hq(p); - auto paintIconMask = [this, &p](const QImage &mask, float64 angle) { + auto paintIconMask = [this, &p](const QImage &mask, double angle) { auto skipFrom = _stFrom->button.rippleAreaSize / 2; p.translate(skipFrom, skipFrom); p.rotate(angle); @@ -240,15 +256,15 @@ QImage Panel::Button::prepareRippleMask() const { return Ui::RippleAnimation::ellipseMask(QSize(_stFrom->button.rippleAreaSize, _stFrom->button.rippleAreaSize)); } -Panel::Panel(not_null call) -: _call(call) -, _user(call->user()) -, _answerHangupRedial(this, st::callAnswer, &st::callHangup) -, _decline(this, object_ptr