Compare commits

...

341 Commits

Author SHA1 Message Date
dependabot[bot]
6efc473859
Bump actions/download-artifact from 1 to 4.1.7 in /.github/workflows (#191)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 1 to 4.1.7.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v1...v4.1.7)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-06 10:51:26 +03:00
Gres
e1ec86f298 Update deepl translation 2023-09-02 21:09:27 +03:00
Gres
29ee5dda90 Update deepl translation 2023-05-19 23:30:44 +03:00
Gres
b8cd2dff54 Update project state 2023-05-05 21:50:57 +03:00
Gres
fb3f32f050 Update deepl translation 2023-04-08 22:09:35 +03:00
Gres
41f1f56fe5 Update deepl translation 2023-02-12 14:17:17 +03:00
Gres
5be5def820 Update deepl translation 2023-02-06 23:40:07 +03:00
Gres
12997389ff Add Hebrew translation 2023-01-28 12:29:12 +03:00
Gres
ab15cc8c79 Update Yandex translator 2023-01-28 12:29:12 +03:00
Gres
6cb9199a6c Fix repeated 'check for updates warning' 2023-01-28 12:29:12 +03:00
Gres
57b1cf8865 Add note about the app translaion 2023-01-03 21:51:56 +03:00
Gres
d328026356 Update correction resource names 2022-10-24 13:07:58 +03:00
Gres
8d4bcb8605 Update translation script 2022-10-14 21:20:42 +03:00
Gres
5a2c52e4c5 Update deepl supported languages 2022-10-07 21:09:43 +03:00
Gres
8c918e14a4 Update readme 2022-08-14 12:29:45 +03:00
Gres
936aaa90ff Update version file 2022-08-14 12:07:35 +03:00
Gres
efa9fab49f Update version file 2022-07-30 13:27:46 +03:00
Gres
cad1e83d44 Bump version 2022-07-30 13:10:43 +03:00
Gres
7be070744b Use single tesseract library
Link with it during compilation.
Bump to 5.2.0.
2022-07-29 23:09:56 +03:00
Gres
cb203b912e Improve image preprocessing 2022-07-29 23:05:49 +03:00
Gres
5f53aaec23 Rescent gcc fix 2022-07-03 22:34:16 +03:00
Gres
b71c67dd1b Respect "use user substitutions" option 2022-07-03 22:34:02 +03:00
Gres
5df1f52a68 Update version file 2022-05-22 15:06:14 +03:00
Gres
59d7f1d4f5 Update changelog 2022-05-22 14:53:33 +03:00
Gres
bf5d4efc6b Bump version 2022-05-22 14:37:50 +03:00
Gres
6cb853d804 Yet another typo 2022-05-18 23:13:51 +03:00
Gres
ac24d909d1 Typo in gcc version 2022-05-18 23:00:58 +03:00
Gres
9b6657318b Bump gcc version 2022-05-18 22:44:53 +03:00
Gres
ccfbf843dc Add info about Linux crash workaround 2022-05-18 22:44:21 +03:00
Gres
00e3f90430 Add workaround for tesseract crash on Linux 2022-05-18 22:44:21 +03:00
Gres
60f115acd1 Set proper flags for tesseract builds 2022-05-18 22:43:20 +03:00
Gres
1f6fff0050 Improve result window placement on screen borders
See #74
2022-05-04 19:36:56 +03:00
Gres
030c99d0fe Typo 2022-04-07 23:18:38 +03:00
Gres
a4a3f44806 Fixed avx support detection 2022-04-07 22:56:22 +03:00
Gres
ce9c47c3ea Update tesseract version 2022-04-03 12:19:50 +03:00
Gres
07b520d10b Change msvc version 2022-03-27 22:04:59 +03:00
Gres
260a10bea3 Close result widgets with escape button
For #86
2022-03-27 11:37:32 +03:00
Gres
4f195f5629 Fix multi-monitor result and editor positions
Fixes #90
2022-03-26 16:19:33 +03:00
Gres
7d84bd2f7b Fixed translators order persistence
fixes #91
2022-03-24 20:39:39 +03:00
Gres
a4e09d88c6 Update version file 2022-02-05 22:18:19 +03:00
Gres
ad39d98858 Disable sourceforge upload 2022-02-05 22:14:56 +03:00
Gres
2369015824 Bump version 2022-02-05 21:49:32 +03:00
Gres
156cd7c926 Make cache dependant on script changes 2022-02-05 21:49:32 +03:00
Gres
ff041facd8 Add file to store cached tesseract version in ci 2022-02-05 21:49:32 +03:00
Gres
5581f385ae Added joint script to make a release 2022-02-05 21:49:32 +03:00
Gres
958b86044e Use rescent linuxdeployqt for appimage 2022-02-05 21:49:32 +03:00
Gres
032a14380f Remove outdated file 2022-02-05 21:49:32 +03:00
Gres
c03a3d2fc2 Update translations 2022-02-05 21:49:32 +03:00
Gres
d5eb9f1855 Add some info to readme.
Add link to readme to the app.
2022-02-05 21:49:32 +03:00
Gres
7a8e8e510c Use more rescent library versions
Tesseract 5.0.1 causes "free: invalid pointer" error
2022-02-05 21:48:23 +03:00
Gres
45a36f3222 Change CI ubuntu version 2022-01-30 13:34:48 +03:00
Gres
155c3577c3 Auto select all translators if translation is enabled and no one is selected 2022-01-30 13:34:48 +03:00
Gres
0e72af3770 Auto select tesseract versions depending on cpu info 2022-01-30 13:34:48 +03:00
Gres
fdfa43c093 Fix multi-monitor configurations with primary not right/bottom 2022-01-30 13:34:48 +03:00
Gres
af15301bf1 Fix some special key mappings for global shortcuts 2022-01-12 19:06:51 +03:00
Gres
26c034e75a Change shortcut editor
Remove global shortcuts when blocking actions to not trigger it when editing
2022-01-12 19:06:51 +03:00
Gres
75bfd798c8 Add ISO code for Filipino language. Required for translation 2022-01-12 19:00:28 +03:00
Gres
59a10af57e Change tesseract github url 2021-11-22 11:37:51 +03:00
Gres
2ce8e0edc3 Update version file 2021-04-19 23:21:29 +03:00
Gres
1fa62d8370 Bump version 2021-04-19 22:52:02 +03:00
Gres
70f75ae63d Fix incorrect win/linux button coloring 2021-04-19 22:52:02 +03:00
Gres
39d1d6e237 Fix saving packed file instead of unpacked
Fixes #51
2021-04-19 22:52:02 +03:00
Gres
3f71c10964 Update version file 2021-04-17 17:36:49 +03:00
Gres
e4db31de10 Bump version 2021-04-17 11:54:58 +03:00
Gres
d5dfa5786b Disable os dependant test 2021-04-15 22:06:23 +03:00
Gres
1a153ff5c3 Order user substitutions 2021-04-15 21:49:24 +03:00
Gres
e8f4f01d9c Preview result font color and size 2021-04-15 21:32:32 +03:00
Gres
718bb7314b Show settings page info and error 2021-04-15 21:08:16 +03:00
Gres
3f2dcbbeb0 Auto check for updates when opening updates page
If page is empty
2021-04-13 20:55:47 +03:00
Gres
413cae80c4 Updates refactoring
Install updates immediately after click
Separate loader and installer logic
2021-04-08 23:11:21 +03:00
Gres
9706ab1c12 Renamed "about" help tab 2021-04-04 16:11:20 +03:00
Gres
d9bff84acd Fixed appimage binary detection for autostart 2021-04-04 16:09:16 +03:00
Gres
c715ed136a Add proper names for vertical languages 2021-03-22 22:28:47 +03:00
Gres
5b591fa476 Explicitly set page segmentation mode to auto 2021-03-21 23:05:32 +03:00
Gres
efee1088f7 Update version file 2021-02-07 12:29:02 +03:00
Gres
3aa76f6074 Bump version 2021-02-07 12:12:32 +03:00
Gres
bf3c3ad893 Typo 2021-02-07 12:06:49 +03:00
Gres
30894d7689 Fix translated text after manual edit 2021-01-31 17:46:17 +03:00
Gres
65b61dec56 Update version file 2021-01-24 21:13:31 +03:00
Gres
8273b245ef Bump version 2021-01-24 20:53:08 +03:00
Gres
49983a772a Update lib versions
Also disable webp support (some issues with it at github actions)
2021-01-24 15:50:42 +03:00
Gres
a76ee0f25a Remove set-env from ci file 2021-01-24 15:49:13 +03:00
Gres
abdf15aaaf Explicit portable mode paths 2021-01-10 16:14:09 +03:00
Gres
75a04beffa Handle empty and same text translation 2021-01-05 17:03:11 +03:00
Gres
d46c72fafb Update google translation script
Related to #37
2020-12-06 22:40:03 +03:00
Gres
6936914976 Remove outdated info about versions 2020-07-27 20:44:02 +03:00
Gres
eba1b84184 Update version file 2020-07-18 15:07:35 +03:00
Gres
99fbdf7d90 Update changelog 2020-07-18 13:48:43 +03:00
Gres
53d9470ccd Bundle vc_redist 2010 installer
Need for ssl

Fix wrong file commited
2020-07-18 13:40:31 +03:00
Gres
9c383badc9 Bundle vc_redist 2010 installer
Need for ssl
2020-07-18 13:39:00 +03:00
Gres
64869f6128 Add license info 2020-07-18 13:13:25 +03:00
Gres
74e2be5b8d Remove redundant arch flag from hunspell build 2020-07-18 12:59:44 +03:00
Gres
aba0a8b316 Add changelog link to about page 2020-07-18 12:59:16 +03:00
Gres
ac1c598953 Build hunspell via self-generated CMake file on linux too 2020-07-18 12:28:43 +03:00
Gres
0920ed1f40 Bundle multiple tesseract versions
Load them via C api and allow user to select which one to use.
2020-07-18 12:26:59 +03:00
Gres
bd99d04416 Install missing packages on ubuntu 2020-07-16 20:59:23 +03:00
Gres
6c62b5506e Change qt version 2020-07-14 22:51:24 +03:00
Gres
d8db4684fa Add explicit locale header 2020-07-14 22:51:00 +03:00
Gres
b67935ef57 Add workaround for non ascii path to binary on Windows 2020-07-13 22:40:34 +03:00
Gres
63876a3215 Add some error messages about wrong parameters 2020-07-12 15:39:28 +03:00
Gres
698c9e4e70 Remove obsolete options 2020-07-12 15:39:02 +03:00
Gres
092c5e65ca Select first item of source languages if none is selected 2020-07-12 15:28:40 +03:00
Gres
19f814261c Change hunspell->correction in updates 2020-07-12 15:12:56 +03:00
Gres
94776f06b3 Update translation script 2020-05-24 20:49:19 +03:00
Gres
614e1e5a02 Disable stale lock file 2020-05-22 21:37:29 +03:00
Gres
bbc635e500 Change models initialization order 2020-05-22 21:35:55 +03:00
Gres
644278890b Add option description about gui reset 2020-05-19 20:16:12 +03:00
Gres
a84013cb5c Publish update info 2020-05-09 14:37:37 +03:00
Gres
82be88bdf7 Update version 2020-05-09 14:05:34 +03:00
Gres
30ac4433f3 Add faq link 2020-05-09 13:58:04 +03:00
Gres
d7953024ff Update in-app help message 2020-05-09 13:48:40 +03:00
Gres
0a8ec0086b Update translators error message 2020-05-09 13:30:06 +03:00
Gres
ed81d9c406 Reset fatal error state 2020-05-09 13:30:06 +03:00
Gres
56e502c3c9 Add error message for empty source language 2020-05-09 13:30:06 +03:00
Gres
79b3092411 Update shortcuts error message 2020-05-09 13:30:06 +03:00
Gres
36700db5d1 Do not show translation via tray if not requested 2020-05-09 13:30:06 +03:00
Gres
3a4ee296af Add build from source info 2020-05-09 13:30:06 +03:00
Gres
b3bf0b6b69 Added versions info 2020-05-09 13:30:06 +03:00
Gres
ddbb180a0f Add setup information 2020-05-09 13:30:06 +03:00
Gres
4fb3af6cbf Fix representer actions when show result as tooltip 2020-05-09 11:58:40 +03:00
Gres
c5b57d1d7a Update readme 2020-05-07 12:59:54 +03:00
Gres
5c7e0260a9 Update readme 2020-05-07 12:58:19 +03:00
Gres
1d185c9402 Apply editor settings when handling key presses 2020-05-04 21:22:11 +03:00
Gres
283624a564 Create release archives with compatible tesseract version 2020-05-03 11:51:09 +03:00
Gres
d5480e6f0a Bundle nss libs into appimage 2020-05-03 10:38:16 +03:00
Gres
f71e886ccc Add tesseract alternative builds 2020-05-02 19:35:13 +03:00
Gres
51356f2624 Add tesseract build dependancy 2020-05-02 19:23:13 +03:00
Gres
55c97694fd Rename artifacts 2020-05-02 19:20:45 +03:00
Gres
5ee59598d3 Add alternative tesseract builds 2020-05-02 18:53:11 +03:00
Gres
65d17394c5 Set more compatible tesseract build 2020-05-02 17:47:05 +03:00
Gres
aa801fecb4 Update help message 2020-05-02 11:21:05 +03:00
Gres
1497538a9a Add issue templates 2020-05-01 16:22:41 +03:00
Gres
b1655775bd Add some trace messages 2020-05-01 15:20:48 +03:00
Gres
63a008d067 Write log while still can 2020-05-01 15:20:48 +03:00
Gres
1ce2f86b3d Create new task in result editor
To prevent concurrent access
2020-05-01 14:10:54 +03:00
Gres
409ad6d3c2 Clear processing queue after settings update 2020-05-01 14:05:23 +03:00
Gres
5afd8e7e7f Add short help text 2020-05-01 13:14:48 +03:00
Gres
e1ec939862 Improve dependency cache validation 2020-05-01 12:51:22 +03:00
Gres
96c678bf33 Add compatibility flags to tesseract build 2020-05-01 12:45:21 +03:00
Gres
16904f2531 Add mutex in log handler 2020-04-28 21:49:47 +03:00
Gres
05b1c57d7d Add title for translator window 2020-04-28 21:43:36 +03:00
Gres
94afaf9497 Print md5 of binary in ci 2020-04-26 16:30:59 +03:00
Gres
16ffc3307b Fix incorrect trace option state 2020-04-26 14:06:01 +03:00
Gres
b73cbde790 Redirect stderr to log file
To log side libraries output
2020-04-25 19:46:49 +03:00
Gres
5556d7aae2 Add more trace messages 2020-04-24 19:22:38 +03:00
Gres
3e1ab494d9 Add warning for incorrect captured data 2020-04-23 22:14:45 +03:00
Gres
6c70b0f21a Add trace messages 2020-04-23 22:14:01 +03:00
Gres
3d50c17b81 Add app version hashes 2020-04-20 21:25:12 +03:00
Gres
74d4a6eca4 Set default updates sorting 2020-04-20 20:46:29 +03:00
Gres
1764cf80e4 Add resources mirror links 2020-04-20 20:46:29 +03:00
Gres
38b9086cac Add tesseract language names 2020-04-20 20:46:29 +03:00
Gres
9de8db88a9 Fix group 2020-04-20 20:46:29 +03:00
Gres
5d4ad56b1e Add updates file to project 2020-04-20 20:46:29 +03:00
Gres
a1c4d8bbd9 Add updater tests 2020-04-20 20:46:29 +03:00
Gres
c26d9a0924 Place downloadable resources in one dir 2020-04-20 20:46:29 +03:00
Gres
7b1d7b9eeb Add resources mirror creation tool 2020-04-20 20:46:29 +03:00
Gres
9b2009ed6c Change trace file name 2020-04-20 20:46:29 +03:00
Gres
351847a3ef Change sourceforge deploy path 2020-04-20 20:46:29 +03:00
Gres
68efe4c8cb Deploy to sourceforge 2020-04-20 20:46:29 +03:00
Gres
a27f97f2cb Add ability to build debug version 2020-04-20 20:46:29 +03:00
Gres
1a44e17739 Use absolute paths in portable mode 2020-04-20 20:46:29 +03:00
Gres
351ac398b4 Add updater application dir variable 2020-04-20 20:46:29 +03:00
Gres
f51521f8e2 Update versions file 2020-04-20 20:46:29 +03:00
Gres
461f1f433d Do not set downloaded file time
Because actually downloaded file can be newer than stated in updates.json
2020-04-20 20:46:29 +03:00
Gres
055ba92667 Add ci hunspell build 2020-04-20 20:46:29 +03:00
Gres
250feb9bc5 Sort update components 2020-04-20 20:46:29 +03:00
Gres
0b0b0cb09c Add note about visible translation window instead of silently showing and hiding it
Toggling visibility looks terrible on Windows
2020-04-20 20:46:29 +03:00
Gres
962234418b Update translators 2020-04-20 20:46:29 +03:00
Gres
c63abf4809 Fix error message 2020-04-20 20:46:29 +03:00
Gres
04de7388b1 Bundle ssl lib 2020-04-20 20:46:29 +03:00
Gres
2f796d33c9 Allow serialport dependency 2020-04-20 20:46:29 +03:00
Gres
858649e57b Remove old CI file 2020-04-20 20:46:29 +03:00
Gres
633b9c6561 Remove outdates translations deployment 2020-04-20 20:46:29 +03:00
Gres
dce3c798a2 Add ability to set substitution for any language 2020-04-20 20:46:29 +03:00
Gres
da51f79708 Allow special characters in substitutions 2020-04-20 20:46:29 +03:00
Gres
bcf83acf4e Add redirect support 2020-04-20 20:46:29 +03:00
Gres
48a01a3992 Add auto correction with hunspell 2020-04-20 20:46:29 +03:00
Gres
23cdc3e57c Fix update download error show 2020-04-20 20:46:29 +03:00
Gres
3c39faaaad Silence warnings 2020-04-20 20:46:29 +03:00
Gres
8957f2407d Add translation 2020-04-20 20:46:29 +03:00
Gres
7227fc9844 Change messages text 2020-04-20 20:46:29 +03:00
Gres
7c87371fe5 Add task debug print 2020-04-20 20:46:29 +03:00
Gres
8bd89db060 Collect updater errors and signal only on final failure 2020-04-20 20:46:29 +03:00
Gres
a865381b65 Enable trace if env variable is set 2020-04-20 20:46:29 +03:00
Gres
0c3893ddf8 Add support of zip archived components 2020-04-20 20:46:29 +03:00
Gres
7bc5030ed5 Cleanup 2020-04-20 20:46:29 +03:00
Gres
5be05c46d8 Change action order in context menu 2020-04-20 20:46:29 +03:00
Gres
eff7552d07 Replace one-use methods with lambdas 2020-04-20 20:46:29 +03:00
Gres
1ba4f6be4d Check for supported actions in setter 2020-04-20 20:46:29 +03:00
Gres
b2e0694dfa Disable edition updates via delegate 2020-04-20 20:46:29 +03:00
Gres
69819dee7f Add ability to select all updates and reset action from menu 2020-04-20 20:46:29 +03:00
Gres
576d9d5662 Add support of multiple update urls 2020-04-20 20:46:29 +03:00
Gres
d931015d6b Remove unused tesseract engines after some time 2020-04-20 20:46:29 +03:00
Gres
5397521c79 Hide result before capture 2020-04-20 20:46:29 +03:00
Gres
b9ff1eaca3 Add items to run new capture to result menu 2020-04-20 20:46:29 +03:00
Gres
ae8801d837 Change widgets that show paths 2020-04-20 20:46:29 +03:00
Gres
071eadc088 Fix last update check date handling 2020-04-20 20:46:29 +03:00
Gres
56bacbfc7e Warn if version might be outdated 2020-04-20 20:46:29 +03:00
Gres
ee899c1b23 Add ability to select updates via context menu 2020-04-20 20:46:29 +03:00
Gres
0ef82187d6 Add size to update info 2020-04-20 20:46:29 +03:00
Gres
7e73804348 Shuffle update urls 2020-04-20 20:46:29 +03:00
Gres
b2f5cc93f2 Show used translator name 2020-04-20 20:46:29 +03:00
Gres
77a1f4a00b Change cursor on selected area 2020-04-20 20:46:29 +03:00
Gres
8d2e726715 Add ability to capture multiple areas 2020-04-20 20:46:29 +03:00
Gres
5f4ef955e1 Add support of multiple component urls 2020-04-20 20:46:29 +03:00
Gres
35cbdb17e8 Move update download handling to separate method 2020-04-20 20:46:29 +03:00
Gres
0df0f2ef20 Added baidu translator 2020-04-20 20:46:29 +03:00
Gres
bbe7d0a729 Add ability to move result widget with middle button 2020-04-20 20:46:29 +03:00
Gres
013370e51e Write trace to file for debugging 2020-04-20 20:46:29 +03:00
Gres
58f6283fe3 Move about info to settings 2020-04-20 20:46:29 +03:00
Gres
ca99f570f7 Change url escaping 2020-04-20 20:46:29 +03:00
Gres
45e12265c1 Show update download progress 2020-04-20 20:46:29 +03:00
Gres
8aa10754e2 Add methods to convert between component/index 2020-04-20 20:46:29 +03:00
Gres
9144ea262d Update translator 2020-04-20 20:46:29 +03:00
Gres
040d0ff540 Change user agent string 2020-04-20 20:46:29 +03:00
Gres
a85dafa18d Ensure page is visible during translation
Because some translator sites require it
2020-04-20 20:46:29 +03:00
Gres
6f7270f229 Preserve translators order in settings 2020-04-20 20:46:29 +03:00
Gres
2f1779ee9b Add ability to show debug page from translator window
Also always enable chromium debug mode
2020-04-20 20:46:29 +03:00
Gres
4dd2d2ddb6 Add ability to show translator from menu and close it 2020-04-20 20:46:29 +03:00
Gres
9ea8974108 Hide previous results before capturing new 2020-04-20 20:46:29 +03:00
Gres
ff19f87b44 Improve support of empty input data 2020-04-20 20:46:29 +03:00
Gres
e36fbbf3b0 Change about message 2020-04-20 20:46:29 +03:00
Gres
15d4bcb36e Change help and area tooltip drawing 2020-04-20 20:46:29 +03:00
Gres
0738a88eb7 Add ability to lock capture areas and capture them by hotkey 2020-04-20 20:46:29 +03:00
Gres
aac286df9d Fix corrector work with empty corrections 2020-04-20 20:46:29 +03:00
Gres
43597f05f2 Update readme 2020-04-20 20:46:29 +03:00
Gres
e70f5c21a5 Add ability to change result font and background colors 2020-04-20 20:46:29 +03:00
Gres
ac1267c88d Show current languages for capture area 2020-04-20 20:46:29 +03:00
Gres
1ff3fb1f1b Add ability to edit results 2020-04-20 20:46:29 +03:00
Gres
c9b2677bec Remove unneeded variable 2020-04-20 20:46:29 +03:00
Gres
9e72e67ee7 Check if translated before copy to clipboard 2020-04-20 20:46:28 +03:00
Gres
258073c785 Move common model to separate class 2020-04-20 20:46:28 +03:00
Gres
87987f4a71 Move updater setup to separate function 2020-04-20 20:46:28 +03:00
Gres
c2a1dab1c7 Show results with errors 2020-04-20 20:46:28 +03:00
Gres
4ca17dca30 Update supported translation languages 2020-04-20 20:46:28 +03:00
Gres
2da5363448 Move interaction with last result to representer 2020-04-20 20:46:28 +03:00
Gres
d55ccd82b9 Compact capture editor 2020-04-20 20:46:28 +03:00
Gres
a92a5a1cc6 Test before build 2020-04-20 20:46:28 +03:00
Gres
9d9f082b57 Add test 2020-04-20 20:46:28 +03:00
Gres
7ed6742f51 Add ability to swap languages in customization menu 2020-04-20 20:46:28 +03:00
Gres
897db5b6c4 Compile translation into binary 2020-04-20 20:46:28 +03:00
Gres
d760ea3f13 Remove translators from distribution bundle 2020-04-20 20:46:28 +03:00
Gres
872b047d70 Show translated/recognized text on top if there is no space below 2020-04-20 20:46:28 +03:00
Gres
4b5fb132f7 Place editor respecting available space 2020-04-20 20:46:28 +03:00
Gres
e1c2defd71 Add ability to edit selected rect 2020-04-20 20:46:28 +03:00
Gres
cc815f4245 Changed language codes to singleton 2020-04-20 20:46:28 +03:00
Gres
aee380fcd5 Move task creation to separate class 2020-04-20 20:46:28 +03:00
Gres
6336d3545a Change overlay drawing 2020-04-20 20:46:28 +03:00
Gres
295353332f Move available translations getter to translator class 2020-04-20 20:46:28 +03:00
Gres
10f5e5e387 Add default translation state to help 2020-04-20 20:46:28 +03:00
Gres
12b8d332c8 Cleanup 2020-04-20 20:46:28 +03:00
Gres
ce83cfff54 Change default result font family 2020-04-20 20:46:28 +03:00
Gres
4edb231c4e Move service classes to separate namespace 2020-04-20 20:46:28 +03:00
Gres
2874177bc4 Use one capture widget for all screens instead of one per screen 2020-04-20 20:46:28 +03:00
Gres
178c954124 Prevent capture stuck 2020-04-20 20:46:28 +03:00
Gres
668c8f1183 Add capture help message 2020-04-20 20:46:28 +03:00
Gres
71b74bb286 Rename capture overlay 2020-04-20 20:46:28 +03:00
Gres
d7cb1e3f56 Add translation search path in resources 2020-04-20 20:46:28 +03:00
Gres
1757b2b89f Recreate page on webengine render error/crash 2020-04-20 20:46:28 +03:00
Gres
705bae636d Use only one settings instance 2020-04-20 20:46:28 +03:00
Gres
0da289e16f Update translation scripts 2020-04-20 20:46:28 +03:00
Gres
2bf5515b0b Convert both translation languages ids to codes 2020-04-20 20:45:26 +03:00
Gres
04abe4b0d4 Change cache key to separate win32/64 builds 2020-04-20 20:45:26 +03:00
Gres
0fcdff9be2 Added ability to toggle autorun 2020-04-20 20:45:26 +03:00
Gres
1f478bc48a Added ability to show/hide captured image and recognized text 2020-04-20 20:45:26 +03:00
Gres
69f7d10c3a Added ability to change result font 2020-04-20 20:45:26 +03:00
Gres
124d32857f Keep only available languages in correction selector 2020-04-20 20:45:26 +03:00
Gres
8b84fef929 Update only last check date when needed 2020-04-20 20:45:26 +03:00
Gres
b81bdc69eb Use langauge names for updates 2020-04-20 20:45:26 +03:00
Gres
cc00f0a54d Use localized language names 2020-04-20 20:45:26 +03:00
Gres
fa75537487 Print localized update name 2020-04-20 20:45:26 +03:00
Gres
1582bdf294 Added auto update checker 2020-04-20 20:45:26 +03:00
Gres
71bb96fe2f Refactoring 2020-04-20 20:45:26 +03:00
Gres
148bf249f8 Change updated file time if available 2020-04-20 20:45:26 +03:00
Gres
ced4fdd834 Load substitutions in legacy format 2020-04-20 20:45:26 +03:00
Gres
afe2cc1a2c Added ability to only check for updates without installing
For built in components
2020-04-20 20:45:26 +03:00
Gres
3847c8d61b Inform about updates 2020-04-20 20:45:26 +03:00
Gres
493262876f Added portable mode 2020-04-20 20:45:26 +03:00
Gres
83232bfc76 Add ability to apply settings without closing dialog 2020-04-20 20:45:26 +03:00
Gres
032895830c Removed outdated tooltips 2020-04-20 20:45:26 +03:00
Gres
d7b671a73d Tessdata and translators path and constant and point to default app writable location 2020-04-20 20:45:26 +03:00
Gres
bff2598285 Prevent setting names edition 2020-04-20 20:45:26 +03:00
Gres
40824e60de Add resource downloader/updater 2020-04-20 20:45:26 +03:00
Gres
c5889e1374 typo 2020-04-20 20:44:37 +03:00
Gres
bfe84af681 Check for empty path 2020-04-20 20:44:37 +03:00
Gres
9da8c516b6 Show translator script errors 2020-04-20 20:44:37 +03:00
Gres
835714d76d Change preferred ocr resolution 2020-04-20 20:44:37 +03:00
Gres
e7fe13c5f0 Change leptonica/qt conversion functions 2020-04-20 20:44:37 +03:00
Gres
cc4b0573d8 Show corrected text in result with uncorrected in tooltip 2020-04-20 20:44:37 +03:00
Gres
deb1bee2c7 Refactor scaling 2020-04-20 20:44:37 +03:00
Gres
4005f94766 Use version from .pro file 2020-04-20 20:44:37 +03:00
Gres
d90fd735e6 Cleanup settings 2020-04-20 20:44:37 +03:00
Gres
4316d1607a Add dependencies build cache 2020-04-20 20:44:37 +03:00
Gres
a4df962ca8 Ignore empty tasks 2020-04-20 20:44:37 +03:00
Gres
d945081dab Write corrected text to separate property 2020-04-20 20:44:37 +03:00
Gres
ab23b6ba6c Add message on program start 2020-04-20 20:44:37 +03:00
Gres
8a65cddc6f Allow edit user substitutions 2020-04-20 20:44:37 +03:00
Gres
a197edd62b Fix correction infinite loop 2020-04-20 20:44:37 +03:00
Gres
6d820ad229 Save selected source and target languages 2020-04-20 20:44:37 +03:00
Gres
7cba01ef20 Prevent excess update 2020-04-20 20:44:37 +03:00
Gres
cdce150db5 Remove property 2020-04-20 20:44:37 +03:00
Gres
546f4782d1 Add proxy handling 2020-04-20 20:44:37 +03:00
Gres
aee289eaef Clamp for concrete enum values 2020-04-20 20:44:37 +03:00
Gres
86d5ee3aa6 Show current page's url and load images option 2020-04-20 20:44:37 +03:00
Gres
fd45105dc7 Reformat readme 2020-04-20 20:44:37 +03:00
Gres
4d6f5857c0 Cleanup 2020-04-20 20:44:37 +03:00
Gres
ad107834eb Handle doTranslation option 2020-04-20 20:44:37 +03:00
Gres
fbbfdb9921 Disable attempt to install rescent gcc 2020-04-20 20:44:37 +03:00
Gres
d3b2b1f328 Install additional package 2020-04-20 20:44:37 +03:00
Gres
0b6511434a Disable osx build 2020-04-20 20:44:37 +03:00
Gres
8804be6436 Force rescent compiler on linux 2020-04-20 20:44:37 +03:00
Gres
cc93067587 Install rescent gcc on linux 2020-04-20 20:44:37 +03:00
Gres
8b4f6742c6 Disable pkg-config for leptonica search 2020-04-20 20:44:37 +03:00
Gres
630a4e8ec9 Change pkgconfig search path 2020-04-20 20:44:37 +03:00
Gres
863fe2fe92 Set leptonica path via cmake parameter 2020-04-20 20:44:37 +03:00
Gres
a371b5bed4 Merge env via python 2020-04-20 20:44:37 +03:00
Gres
40f37f648d Misprint 2020-04-20 20:44:37 +03:00
Gres
a2a24f6648 Convert paths 2020-04-20 20:44:37 +03:00
Gres
8387662e83 Adjust ci 2020-04-20 20:44:37 +03:00
Gres
f2b7ac1821 Add build and ci scripts 2020-04-20 20:44:37 +03:00
Gres
81f370f5c7 Remove outdated files 2020-04-20 20:44:37 +03:00
Gres
4c526f65df Refactor. WIP 2020-04-20 20:44:37 +03:00
Gres
623a4b6086 Update .gitignore 2020-04-20 20:44:37 +03:00
Gres
5a980b4365 foreach => for 2020-04-20 20:44:37 +03:00
Gres
9356f4cb1f Update build paths and flags 2020-04-20 20:44:37 +03:00
Gres
7a2d512a81 Move style file 2020-04-20 20:44:37 +03:00
Gres
d198c88625 Rename sources and put them to src dir 2020-04-20 20:44:37 +03:00
Gres
12cb3bf4ab Adjust to rescent tesseract version 2020-04-20 20:44:37 +03:00
Gres
f15fb29ac1 Typo 2020-04-20 20:44:37 +03:00
Gres
2ae8b4e4a7 Update bing script 2020-03-23 20:50:23 +03:00
Gres
eb796471cf Update readme 2020-02-20 20:50:53 +03:00
Landgraf132
393cec503d Incorrect screen capture on ubuntu 19.10 (#20)
Added support Qt version 5.12.4 (relevant for ubuntu 19.10)
2020-01-07 17:27:46 +03:00
Gres
fa89460466 Added papago translation script 2019-09-17 23:07:49 +03:00
Gres
d44c8ef060 Updated bing translator 2019-08-11 21:37:00 +03:00
Gres
0b3396e1f4 Added deepl translation script 2019-02-10 16:43:08 +03:00
Gres
1e3411bd58 Added google api translation script 2018-12-24 20:26:47 +03:00
Gres
49c5659334 Updated google translation 2018-11-29 19:22:51 +03:00
Gres
a69213c956 Updated bing translation 2018-10-17 19:33:35 +03:00
Gres
4109968fed Fixed possible wrong index usage 2018-10-17 19:32:55 +03:00
Gres
bab4d633db Translation fix 2018-10-17 19:29:19 +03:00
Gres
6a315c75c5 Updated readme. Closes #3. 2018-04-13 21:41:26 +03:00
218 changed files with 50543 additions and 11875 deletions

View File

@ -1,45 +0,0 @@
image: Visual Studio 2015
environment:
ARCH: x86
sf_secret:
secure: 8QOHSPQLI/lmjgOhyGOsMA5MxOdeSnlFWWKjntqEfBMfW/XCuiEk5tHNjZiiAw8N
sf_api:
secure: S4qrbAdLq3Hw5yozC7XAavTGzpPPh8MleX+r8kaueBtPZUeJGt+8EoqaPw0P1PzV
clone_depth: 10
platform:
- x64
init:
- if /i %APPVEYOR_REPO_TAG% == true set WITH_TESSDATA=1
cache:
- installed -> scripts\win\prepare.bat
install:
- cinst winscp
- nuget install secure-file -ExcludeVersion
- call "scripts\win\prepare.bat"
build_script:
- call "scripts\win\build.bat"
artifacts:
- path: 'screen-translator-*.exe'
name: installer
deploy:
- provider: GitHub
description: "Version $(APPVEYOR_REPO_TAG_NAME)"
auth_token:
secure: NnyUV44yNAx8ea1L46dVhE4kQxUGd5M1O+yVk+9ncsNHWtw/9JoCnDqNybnxTccP
artifact: installer
force_update: true
on:
appveyor_repo_tag: true
after_deploy:
- secure-file\tools\secure-file -decrypt scripts\win\sf_key.av -secret %sf_secret% -out scripts\win\sf_key
- call "scripts\win\deploy_sf.bat"

16
.clang-format Normal file
View File

@ -0,0 +1,16 @@
---
BasedOnStyle: Google
AccessModifierOffset: '-2'
AllowShortCaseLabelsOnASingleLine: 'true'
AllowShortFunctionsOnASingleLine: InlineOnly
AllowShortIfStatementsOnASingleLine: 'false'
BreakBeforeBraces: Linux
BreakConstructorInitializers: BeforeComma
ConstructorInitializerAllOnOneLineOrOnePerLine: 'false'
ConstructorInitializerIndentWidth: '2'
Standard: Cpp11
TabWidth: '2'
UseTab: Never
IncludeBlocks: Preserve
...

37
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,37 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: 'bug'
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Logs**
Application log file recorded during an error.
To start recording a log file, open the settings window,
enable the 'write trace file' option and apply the settings.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. windows 10, ubuntu 18.04]
- Desktop environment (linux only): [e.g. KDE, Gnome]
- App version (release archive name): [e.g. 3.0.0-win32, 3.0.0-compatible-win64]
**Additional context**
Add any other context about the problem here.

View File

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: 'enhancement'
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

100
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,100 @@
name: App build
on: [push]
jobs:
release:
name: Create release
if: contains(github.ref, '/tags/')
runs-on: ubuntu-18.04
steps:
- name: Create release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
draft: false
prerelease: false
- name: Store release url
run: echo "${{ steps.create_release.outputs.upload_url }}" > ./release_upload_url
- name: Upload release url
uses: actions/upload-artifact@v1
with:
path: ./release_upload_url
name: release_upload_url
build:
name: Build ${{ matrix.config.name }}${{ matrix.config.tag }}
runs-on: ${{ matrix.config.os }}
env:
OS: ${{ matrix.config.name }}
MSVC_VERSION: C:/Program Files/Microsoft Visual Studio/2022/Enterprise
strategy:
matrix:
config:
- { name: "win64", os: windows-latest }
- { name: "win32", os: windows-latest }
- { name: "linux", os: ubuntu-18.04 }
# - { name: "macos", os: macos-latest }
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 10
- name: Setup python
uses: actions/setup-python@v1
with:
python-version: "3.x"
- name: Install system libs
if: runner.os == 'Linux'
run: |
sudo apt-get install libgl1-mesa-dev libxkbcommon-x11-0 libxcb-*
echo "QMAKE_FLAGS=QMAKE_CXX=g++-10 QMAKE_CC=gcc-10 QMAKE_LINK=g++-10" >> $GITHUB_ENV
- name: Cache dependencies
uses: actions/cache@v2
with:
path: deps
key: ${{ env.OS }}-${{ hashFiles('./share/ci/*.py') }}
- name: Make a release
shell: bash
run: |
python ./share/ci/release.py
echo "artifact=`python ./share/ci/release.py artifact_name`" >> $GITHUB_ENV
- name: Upload build artifact
if: env.artifact != ''
uses: actions/upload-artifact@v1
with:
name: ${{ env.artifact }}
path: ./${{ env.artifact }}
- name: Download release url
if: contains(github.ref, '/tags/')
uses: actions/download-artifact@v4.1.7
with:
name: release_upload_url
path: ./
- name: Set release env
if: contains(github.ref, '/tags/')
shell: bash
run: echo "upload_url=`cat ./release_upload_url`" >> $GITHUB_ENV
- name: Upload release artifacts
if: contains(github.ref, '/tags/')
uses: actions/upload-release-asset@v1.0.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ env.upload_url }}
asset_path: ./${{ env.artifact }}
asset_name: ${{ env.artifact }}
asset_content_type: application/zip

1
.gitignore vendored
View File

@ -8,3 +8,4 @@
distr/content/ distr/content/
*.tar.gz *.tar.gz
__pycache__

View File

@ -1,20 +0,0 @@
language: cpp
compiler:
- gcc
- clang
sudo: required
dist: trusty
install: ./scripts/install_deps.sh
script: cd scripts && ./make_all.sh
branches:
only:
- master
- develop
- /release.*/
- /.*travis/
os:
- linux
notifications:
email:
on_success: change
on_failure: change

View File

@ -1,204 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtlocalpeer.h"
#include <QCoreApplication>
#include <QDataStream>
#include <QTime>
#if defined(Q_OS_WIN)
#include <QLibrary>
#include <qt_windows.h>
typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*);
static PProcessIdToSessionId pProcessIdToSessionId = 0;
#endif
#if defined(Q_OS_UNIX)
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#endif
namespace QtLP_Private {
#include "qtlockedfile.cpp"
#if defined(Q_OS_WIN)
#include "qtlockedfile_win.cpp"
#else
#include "qtlockedfile_unix.cpp"
#endif
}
const char* QtLocalPeer::ack = "ack";
QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId)
: QObject(parent), id(appId)
{
QString prefix = id;
if (id.isEmpty()) {
id = QCoreApplication::applicationFilePath();
#if defined(Q_OS_WIN)
id = id.toLower();
#endif
prefix = id.section(QLatin1Char('/'), -1);
}
prefix.remove(QRegExp("[^a-zA-Z]"));
prefix.truncate(6);
QByteArray idc = id.toUtf8();
quint16 idNum = qChecksum(idc.constData(), idc.size());
socketName = QLatin1String("qtsingleapp-") + prefix
+ QLatin1Char('-') + QString::number(idNum, 16);
#if defined(Q_OS_WIN)
if (!pProcessIdToSessionId) {
QLibrary lib("kernel32");
pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
}
if (pProcessIdToSessionId) {
DWORD sessionId = 0;
pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
socketName += QLatin1Char('-') + QString::number(sessionId, 16);
}
#else
socketName += QLatin1Char('-') + QString::number(::getuid(), 16);
#endif
server = new QLocalServer(this);
QString lockName = QDir(QDir::tempPath()).absolutePath()
+ QLatin1Char('/') + socketName
+ QLatin1String("-lockfile");
lockFile.setFileName(lockName);
lockFile.open(QIODevice::ReadWrite);
}
bool QtLocalPeer::isClient()
{
if (lockFile.isLocked())
return false;
if (!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false))
return true;
bool res = server->listen(socketName);
#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0))
// ### Workaround
if (!res && server->serverError() == QAbstractSocket::AddressInUseError) {
QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName);
res = server->listen(socketName);
}
#endif
if (!res)
qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString()));
QObject::connect(server, SIGNAL(newConnection()), SLOT(receiveConnection()));
return false;
}
bool QtLocalPeer::sendMessage(const QString &message, int timeout)
{
if (!isClient())
return false;
QLocalSocket socket;
bool connOk = false;
for(int i = 0; i < 2; i++) {
// Try twice, in case the other instance is just starting up
socket.connectToServer(socketName);
connOk = socket.waitForConnected(timeout/2);
if (connOk || i)
break;
int ms = 250;
#if defined(Q_OS_WIN)
Sleep(DWORD(ms));
#else
struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
nanosleep(&ts, NULL);
#endif
}
if (!connOk)
return false;
QByteArray uMsg(message.toUtf8());
QDataStream ds(&socket);
ds.writeBytes(uMsg.constData(), uMsg.size());
bool res = socket.waitForBytesWritten(timeout);
if (res) {
res &= socket.waitForReadyRead(timeout); // wait for ack
if (res)
res &= (socket.read(qstrlen(ack)) == ack);
}
return res;
}
void QtLocalPeer::receiveConnection()
{
QLocalSocket* socket = server->nextPendingConnection();
if (!socket)
return;
while (socket->bytesAvailable() < (int)sizeof(quint32))
socket->waitForReadyRead();
QDataStream ds(socket);
QByteArray uMsg;
quint32 remaining;
ds >> remaining;
uMsg.resize(remaining);
int got = 0;
char* uMsgBuf = uMsg.data();
do {
got = ds.readRawData(uMsgBuf, remaining);
remaining -= got;
uMsgBuf += got;
} while (remaining && got >= 0 && socket->waitForReadyRead(2000));
if (got < 0) {
qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData());
delete socket;
return;
}
QString message(QString::fromUtf8(uMsg));
socket->write(ack, qstrlen(ack));
socket->waitForBytesWritten(1000);
socket->waitForDisconnected(1000); // make sure client reads ack
delete socket;
emit messageReceived(message); //### (might take a long time to return)
}

View File

@ -1,77 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTLOCALPEER_H
#define QTLOCALPEER_H
#include <QLocalServer>
#include <QLocalSocket>
#include <QDir>
#include "qtlockedfile.h"
class QtLocalPeer : public QObject
{
Q_OBJECT
public:
QtLocalPeer(QObject *parent = 0, const QString &appId = QString());
bool isClient();
bool sendMessage(const QString &message, int timeout);
QString applicationId() const
{ return id; }
Q_SIGNALS:
void messageReceived(const QString &message);
protected Q_SLOTS:
void receiveConnection();
protected:
QString id;
QString socketName;
QLocalServer* server;
QtLP_Private::QtLockedFile lockFile;
private:
static const char* ack;
};
#endif // QTLOCALPEER_H

View File

@ -1,193 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtlockedfile.h"
/*!
\class QtLockedFile
\brief The QtLockedFile class extends QFile with advisory locking
functions.
A file may be locked in read or write mode. Multiple instances of
\e QtLockedFile, created in multiple processes running on the same
machine, may have a file locked in read mode. Exactly one instance
may have it locked in write mode. A read and a write lock cannot
exist simultaneously on the same file.
The file locks are advisory. This means that nothing prevents
another process from manipulating a locked file using QFile or
file system functions offered by the OS. Serialization is only
guaranteed if all processes that access the file use
QLockedFile. Also, while holding a lock on a file, a process
must not open the same file again (through any API), or locks
can be unexpectedly lost.
The lock provided by an instance of \e QtLockedFile is released
whenever the program terminates. This is true even when the
program crashes and no destructors are called.
*/
/*! \enum QtLockedFile::LockMode
This enum describes the available lock modes.
\value ReadLock A read lock.
\value WriteLock A write lock.
\value NoLock Neither a read lock nor a write lock.
*/
/*!
Constructs an unlocked \e QtLockedFile object. This constructor
behaves in the same way as \e QFile::QFile().
\sa QFile::QFile()
*/
QtLockedFile::QtLockedFile()
: QFile()
{
#ifdef Q_OS_WIN
wmutex = 0;
rmutex = 0;
#endif
m_lock_mode = NoLock;
}
/*!
Constructs an unlocked QtLockedFile object with file \a name. This
constructor behaves in the same way as \e QFile::QFile(const
QString&).
\sa QFile::QFile()
*/
QtLockedFile::QtLockedFile(const QString &name)
: QFile(name)
{
#ifdef Q_OS_WIN
wmutex = 0;
rmutex = 0;
#endif
m_lock_mode = NoLock;
}
/*!
Opens the file in OpenMode \a mode.
This is identical to QFile::open(), with the one exception that the
Truncate mode flag is disallowed. Truncation would conflict with the
advisory file locking, since the file would be modified before the
write lock is obtained. If truncation is required, use resize(0)
after obtaining the write lock.
Returns true if successful; otherwise false.
\sa QFile::open(), QFile::resize()
*/
bool QtLockedFile::open(OpenMode mode)
{
if (mode & QIODevice::Truncate) {
qWarning("QtLockedFile::open(): Truncate mode not allowed.");
return false;
}
return QFile::open(mode);
}
/*!
Returns \e true if this object has a in read or write lock;
otherwise returns \e false.
\sa lockMode()
*/
bool QtLockedFile::isLocked() const
{
return m_lock_mode != NoLock;
}
/*!
Returns the type of lock currently held by this object, or \e
QtLockedFile::NoLock.
\sa isLocked()
*/
QtLockedFile::LockMode QtLockedFile::lockMode() const
{
return m_lock_mode;
}
/*!
\fn bool QtLockedFile::lock(LockMode mode, bool block = true)
Obtains a lock of type \a mode. The file must be opened before it
can be locked.
If \a block is true, this function will block until the lock is
aquired. If \a block is false, this function returns \e false
immediately if the lock cannot be aquired.
If this object already has a lock of type \a mode, this function
returns \e true immediately. If this object has a lock of a
different type than \a mode, the lock is first released and then a
new lock is obtained.
This function returns \e true if, after it executes, the file is
locked by this object, and \e false otherwise.
\sa unlock(), isLocked(), lockMode()
*/
/*!
\fn bool QtLockedFile::unlock()
Releases a lock.
If the object has no lock, this function returns immediately.
This function returns \e true if, after it executes, the file is
not locked by this object, and \e false otherwise.
\sa lock(), isLocked(), lockMode()
*/
/*!
\fn QtLockedFile::~QtLockedFile()
Destroys the \e QtLockedFile object. If any locks were held, they
are released.
*/

View File

@ -1,97 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTLOCKEDFILE_H
#define QTLOCKEDFILE_H
#include <QFile>
#ifdef Q_OS_WIN
#include <QVector>
#endif
#if defined(Q_OS_WIN)
# if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT)
# define QT_QTLOCKEDFILE_EXPORT
# elif defined(QT_QTLOCKEDFILE_IMPORT)
# if defined(QT_QTLOCKEDFILE_EXPORT)
# undef QT_QTLOCKEDFILE_EXPORT
# endif
# define QT_QTLOCKEDFILE_EXPORT __declspec(dllimport)
# elif defined(QT_QTLOCKEDFILE_EXPORT)
# undef QT_QTLOCKEDFILE_EXPORT
# define QT_QTLOCKEDFILE_EXPORT __declspec(dllexport)
# endif
#else
# define QT_QTLOCKEDFILE_EXPORT
#endif
namespace QtLP_Private {
class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile
{
public:
enum LockMode { NoLock = 0, ReadLock, WriteLock };
QtLockedFile();
QtLockedFile(const QString &name);
~QtLockedFile();
bool open(OpenMode mode);
bool lock(LockMode mode, bool block = true);
bool unlock();
bool isLocked() const;
LockMode lockMode() const;
private:
#ifdef Q_OS_WIN
Qt::HANDLE wmutex;
Qt::HANDLE rmutex;
QVector<Qt::HANDLE> rmutexes;
QString mutexname;
Qt::HANDLE getMutexHandle(int idx, bool doCreate);
bool waitMutex(Qt::HANDLE mutex, bool doBlock);
#endif
LockMode m_lock_mode;
};
}
#endif

View File

@ -1,115 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include "qtlockedfile.h"
bool QtLockedFile::lock(LockMode mode, bool block)
{
if (!isOpen()) {
qWarning("QtLockedFile::lock(): file is not opened");
return false;
}
if (mode == NoLock)
return unlock();
if (mode == m_lock_mode)
return true;
if (m_lock_mode != NoLock)
unlock();
struct flock fl;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK;
int cmd = block ? F_SETLKW : F_SETLK;
int ret = fcntl(handle(), cmd, &fl);
if (ret == -1) {
if (errno != EINTR && errno != EAGAIN)
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
return false;
}
m_lock_mode = mode;
return true;
}
bool QtLockedFile::unlock()
{
if (!isOpen()) {
qWarning("QtLockedFile::unlock(): file is not opened");
return false;
}
if (!isLocked())
return true;
struct flock fl;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = F_UNLCK;
int ret = fcntl(handle(), F_SETLKW, &fl);
if (ret == -1) {
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
return false;
}
m_lock_mode = NoLock;
return true;
}
QtLockedFile::~QtLockedFile()
{
if (isOpen())
unlock();
}

View File

@ -1,211 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtlockedfile.h"
#include <qt_windows.h>
#include <QFileInfo>
#define MUTEX_PREFIX "QtLockedFile mutex "
// Maximum number of concurrent read locks. Must not be greater than MAXIMUM_WAIT_OBJECTS
#define MAX_READERS MAXIMUM_WAIT_OBJECTS
#if QT_VERSION >= 0x050000
#define QT_WA(unicode, ansi) unicode
#endif
Qt::HANDLE QtLockedFile::getMutexHandle(int idx, bool doCreate)
{
if (mutexname.isEmpty()) {
QFileInfo fi(*this);
mutexname = QString::fromLatin1(MUTEX_PREFIX)
+ fi.absoluteFilePath().toLower();
}
QString mname(mutexname);
if (idx >= 0)
mname += QString::number(idx);
Qt::HANDLE mutex;
if (doCreate) {
QT_WA( { mutex = CreateMutexW(NULL, FALSE, (TCHAR*)mname.utf16()); },
{ mutex = CreateMutexA(NULL, FALSE, mname.toLocal8Bit().constData()); } );
if (!mutex) {
qErrnoWarning("QtLockedFile::lock(): CreateMutex failed");
return 0;
}
}
else {
QT_WA( { mutex = OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, (TCHAR*)mname.utf16()); },
{ mutex = OpenMutexA(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, mname.toLocal8Bit().constData()); } );
if (!mutex) {
if (GetLastError() != ERROR_FILE_NOT_FOUND)
qErrnoWarning("QtLockedFile::lock(): OpenMutex failed");
return 0;
}
}
return mutex;
}
bool QtLockedFile::waitMutex(Qt::HANDLE mutex, bool doBlock)
{
Q_ASSERT(mutex);
DWORD res = WaitForSingleObject(mutex, doBlock ? INFINITE : 0);
switch (res) {
case WAIT_OBJECT_0:
case WAIT_ABANDONED:
return true;
break;
case WAIT_TIMEOUT:
break;
default:
qErrnoWarning("QtLockedFile::lock(): WaitForSingleObject failed");
}
return false;
}
bool QtLockedFile::lock(LockMode mode, bool block)
{
if (!isOpen()) {
qWarning("QtLockedFile::lock(): file is not opened");
return false;
}
if (mode == NoLock)
return unlock();
if (mode == m_lock_mode)
return true;
if (m_lock_mode != NoLock)
unlock();
if (!wmutex && !(wmutex = getMutexHandle(-1, true)))
return false;
if (!waitMutex(wmutex, block))
return false;
if (mode == ReadLock) {
int idx = 0;
for (; idx < MAX_READERS; idx++) {
rmutex = getMutexHandle(idx, false);
if (!rmutex || waitMutex(rmutex, false))
break;
CloseHandle(rmutex);
}
bool ok = true;
if (idx >= MAX_READERS) {
qWarning("QtLockedFile::lock(): too many readers");
rmutex = 0;
ok = false;
}
else if (!rmutex) {
rmutex = getMutexHandle(idx, true);
if (!rmutex || !waitMutex(rmutex, false))
ok = false;
}
if (!ok && rmutex) {
CloseHandle(rmutex);
rmutex = 0;
}
ReleaseMutex(wmutex);
if (!ok)
return false;
}
else {
Q_ASSERT(rmutexes.isEmpty());
for (int i = 0; i < MAX_READERS; i++) {
Qt::HANDLE mutex = getMutexHandle(i, false);
if (mutex)
rmutexes.append(mutex);
}
if (rmutexes.size()) {
DWORD res = WaitForMultipleObjects(rmutexes.size(), rmutexes.constData(),
TRUE, block ? INFINITE : 0);
if (res != WAIT_OBJECT_0 && res != WAIT_ABANDONED) {
if (res != WAIT_TIMEOUT)
qErrnoWarning("QtLockedFile::lock(): WaitForMultipleObjects failed");
m_lock_mode = WriteLock; // trick unlock() to clean up - semiyucky
unlock();
return false;
}
}
}
m_lock_mode = mode;
return true;
}
bool QtLockedFile::unlock()
{
if (!isOpen()) {
qWarning("QtLockedFile::unlock(): file is not opened");
return false;
}
if (!isLocked())
return true;
if (m_lock_mode == ReadLock) {
ReleaseMutex(rmutex);
CloseHandle(rmutex);
rmutex = 0;
}
else {
foreach(Qt::HANDLE mutex, rmutexes) {
ReleaseMutex(mutex);
CloseHandle(mutex);
}
rmutexes.clear();
ReleaseMutex(wmutex);
}
m_lock_mode = QtLockedFile::NoLock;
return true;
}
QtLockedFile::~QtLockedFile()
{
if (isOpen())
unlock();
if (wmutex)
CloseHandle(wmutex);
}

View File

@ -1,347 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtsingleapplication.h"
#include "qtlocalpeer.h"
#include <QWidget>
/*!
\class QtSingleApplication qtsingleapplication.h
\brief The QtSingleApplication class provides an API to detect and
communicate with running instances of an application.
This class allows you to create applications where only one
instance should be running at a time. I.e., if the user tries to
launch another instance, the already running instance will be
activated instead. Another usecase is a client-server system,
where the first started instance will assume the role of server,
and the later instances will act as clients of that server.
By default, the full path of the executable file is used to
determine whether two processes are instances of the same
application. You can also provide an explicit identifier string
that will be compared instead.
The application should create the QtSingleApplication object early
in the startup phase, and call isRunning() to find out if another
instance of this application is already running. If isRunning()
returns false, it means that no other instance is running, and
this instance has assumed the role as the running instance. In
this case, the application should continue with the initialization
of the application user interface before entering the event loop
with exec(), as normal.
The messageReceived() signal will be emitted when the running
application receives messages from another instance of the same
application. When a message is received it might be helpful to the
user to raise the application so that it becomes visible. To
facilitate this, QtSingleApplication provides the
setActivationWindow() function and the activateWindow() slot.
If isRunning() returns true, another instance is already
running. It may be alerted to the fact that another instance has
started by using the sendMessage() function. Also data such as
startup parameters (e.g. the name of the file the user wanted this
new instance to open) can be passed to the running instance with
this function. Then, the application should terminate (or enter
client mode).
If isRunning() returns true, but sendMessage() fails, that is an
indication that the running instance is frozen.
Here's an example that shows how to convert an existing
application to use QtSingleApplication. It is very simple and does
not make use of all QtSingleApplication's functionality (see the
examples for that).
\code
// Original
int main(int argc, char **argv)
{
QApplication app(argc, argv);
MyMainWidget mmw;
mmw.show();
return app.exec();
}
// Single instance
int main(int argc, char **argv)
{
QtSingleApplication app(argc, argv);
if (app.isRunning())
return !app.sendMessage(someDataString);
MyMainWidget mmw;
app.setActivationWindow(&mmw);
mmw.show();
return app.exec();
}
\endcode
Once this QtSingleApplication instance is destroyed (normally when
the process exits or crashes), when the user next attempts to run the
application this instance will not, of course, be encountered. The
next instance to call isRunning() or sendMessage() will assume the
role as the new running instance.
For console (non-GUI) applications, QtSingleCoreApplication may be
used instead of this class, to avoid the dependency on the QtGui
library.
\sa QtSingleCoreApplication
*/
void QtSingleApplication::sysInit(const QString &appId)
{
actWin = 0;
peer = new QtLocalPeer(this, appId);
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
}
/*!
Creates a QtSingleApplication object. The application identifier
will be QCoreApplication::applicationFilePath(). \a argc, \a
argv, and \a GUIenabled are passed on to the QAppliation constructor.
If you are creating a console application (i.e. setting \a
GUIenabled to false), you may consider using
QtSingleCoreApplication instead.
*/
QtSingleApplication::QtSingleApplication(int &argc, char **argv, bool GUIenabled)
: QApplication(argc, argv, GUIenabled)
{
sysInit();
}
/*!
Creates a QtSingleApplication object with the application
identifier \a appId. \a argc and \a argv are passed on to the
QAppliation constructor.
*/
QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv)
: QApplication(argc, argv)
{
sysInit(appId);
}
#if QT_VERSION < 0x050000
/*!
Creates a QtSingleApplication object. The application identifier
will be QCoreApplication::applicationFilePath(). \a argc, \a
argv, and \a type are passed on to the QAppliation constructor.
*/
QtSingleApplication::QtSingleApplication(int &argc, char **argv, Type type)
: QApplication(argc, argv, type)
{
sysInit();
}
# if defined(Q_WS_X11)
/*!
Special constructor for X11, ref. the documentation of
QApplication's corresponding constructor. The application identifier
will be QCoreApplication::applicationFilePath(). \a dpy, \a visual,
and \a cmap are passed on to the QApplication constructor.
*/
QtSingleApplication::QtSingleApplication(Display* dpy, Qt::HANDLE visual, Qt::HANDLE cmap)
: QApplication(dpy, visual, cmap)
{
sysInit();
}
/*!
Special constructor for X11, ref. the documentation of
QApplication's corresponding constructor. The application identifier
will be QCoreApplication::applicationFilePath(). \a dpy, \a argc, \a
argv, \a visual, and \a cmap are passed on to the QApplication
constructor.
*/
QtSingleApplication::QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
: QApplication(dpy, argc, argv, visual, cmap)
{
sysInit();
}
/*!
Special constructor for X11, ref. the documentation of
QApplication's corresponding constructor. The application identifier
will be \a appId. \a dpy, \a argc, \a
argv, \a visual, and \a cmap are passed on to the QApplication
constructor.
*/
QtSingleApplication::QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
: QApplication(dpy, argc, argv, visual, cmap)
{
sysInit(appId);
}
# endif // Q_WS_X11
#endif // QT_VERSION < 0x050000
/*!
Returns true if another instance of this application is running;
otherwise false.
This function does not find instances of this application that are
being run by a different user (on Windows: that are running in
another session).
\sa sendMessage()
*/
bool QtSingleApplication::isRunning()
{
return peer->isClient();
}
/*!
Tries to send the text \a message to the currently running
instance. The QtSingleApplication object in the running instance
will emit the messageReceived() signal when it receives the
message.
This function returns true if the message has been sent to, and
processed by, the current instance. If there is no instance
currently running, or if the running instance fails to process the
message within \a timeout milliseconds, this function return false.
\sa isRunning(), messageReceived()
*/
bool QtSingleApplication::sendMessage(const QString &message, int timeout)
{
return peer->sendMessage(message, timeout);
}
/*!
Returns the application identifier. Two processes with the same
identifier will be regarded as instances of the same application.
*/
QString QtSingleApplication::id() const
{
return peer->applicationId();
}
/*!
Sets the activation window of this application to \a aw. The
activation window is the widget that will be activated by
activateWindow(). This is typically the application's main window.
If \a activateOnMessage is true (the default), the window will be
activated automatically every time a message is received, just prior
to the messageReceived() signal being emitted.
\sa activateWindow(), messageReceived()
*/
void QtSingleApplication::setActivationWindow(QWidget* aw, bool activateOnMessage)
{
actWin = aw;
if (activateOnMessage)
connect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow()));
else
disconnect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow()));
}
/*!
Returns the applications activation window if one has been set by
calling setActivationWindow(), otherwise returns 0.
\sa setActivationWindow()
*/
QWidget* QtSingleApplication::activationWindow() const
{
return actWin;
}
/*!
De-minimizes, raises, and activates this application's activation window.
This function does nothing if no activation window has been set.
This is a convenience function to show the user that this
application instance has been activated when he has tried to start
another instance.
This function should typically be called in response to the
messageReceived() signal. By default, that will happen
automatically, if an activation window has been set.
\sa setActivationWindow(), messageReceived(), initialize()
*/
void QtSingleApplication::activateWindow()
{
if (actWin) {
actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized);
actWin->raise();
actWin->activateWindow();
}
}
/*!
\fn void QtSingleApplication::messageReceived(const QString& message)
This signal is emitted when the current instance receives a \a
message from another instance of this application.
\sa sendMessage(), setActivationWindow(), activateWindow()
*/
/*!
\fn void QtSingleApplication::initialize(bool dummy = true)
\obsolete
*/

View File

@ -1,105 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTSINGLEAPPLICATION_H
#define QTSINGLEAPPLICATION_H
#include <QApplication>
class QtLocalPeer;
#if defined(Q_OS_WIN)
# if !defined(QT_QTSINGLEAPPLICATION_EXPORT) && !defined(QT_QTSINGLEAPPLICATION_IMPORT)
# define QT_QTSINGLEAPPLICATION_EXPORT
# elif defined(QT_QTSINGLEAPPLICATION_IMPORT)
# if defined(QT_QTSINGLEAPPLICATION_EXPORT)
# undef QT_QTSINGLEAPPLICATION_EXPORT
# endif
# define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllimport)
# elif defined(QT_QTSINGLEAPPLICATION_EXPORT)
# undef QT_QTSINGLEAPPLICATION_EXPORT
# define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllexport)
# endif
#else
# define QT_QTSINGLEAPPLICATION_EXPORT
#endif
class QT_QTSINGLEAPPLICATION_EXPORT QtSingleApplication : public QApplication
{
Q_OBJECT
public:
QtSingleApplication(int &argc, char **argv, bool GUIenabled = true);
QtSingleApplication(const QString &id, int &argc, char **argv);
#if QT_VERSION < 0x050000
QtSingleApplication(int &argc, char **argv, Type type);
# if defined(Q_WS_X11)
QtSingleApplication(Display* dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap= 0);
QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
# endif // Q_WS_X11
#endif // QT_VERSION < 0x050000
bool isRunning();
QString id() const;
void setActivationWindow(QWidget* aw, bool activateOnMessage = true);
QWidget* activationWindow() const;
// Obsolete:
void initialize(bool dummy = true)
{ isRunning(); Q_UNUSED(dummy) }
public Q_SLOTS:
bool sendMessage(const QString &message, int timeout = 5000);
void activateWindow();
Q_SIGNALS:
void messageReceived(const QString &message);
private:
void sysInit(const QString &appId = QString());
QtLocalPeer *peer;
QWidget *actWin;
};
#endif // QTSINGLEAPPLICATION_H

View File

@ -1,17 +0,0 @@
#include(../common.pri)
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
QT *= network
greaterThan(QT_MAJOR_VERSION, 4): QT *= widgets
qtsingleapplication-uselib:!qtsingleapplication-buildlib {
LIBS += -L$$QTSINGLEAPPLICATION_LIBDIR -l$$QTSINGLEAPPLICATION_LIBNAME
} else {
SOURCES += $$PWD/qtsingleapplication.cpp $$PWD/qtlocalpeer.cpp
HEADERS += $$PWD/qtsingleapplication.h $$PWD/qtlocalpeer.h
}
win32 {
contains(TEMPLATE, lib):contains(CONFIG, shared):DEFINES += QT_QTSINGLEAPPLICATION_EXPORT
else:qtsingleapplication-uselib:DEFINES += QT_QTSINGLEAPPLICATION_IMPORT
}

View File

@ -1,149 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtsinglecoreapplication.h"
#include "qtlocalpeer.h"
/*!
\class QtSingleCoreApplication qtsinglecoreapplication.h
\brief A variant of the QtSingleApplication class for non-GUI applications.
This class is a variant of QtSingleApplication suited for use in
console (non-GUI) applications. It is an extension of
QCoreApplication (instead of QApplication). It does not require
the QtGui library.
The API and usage is identical to QtSingleApplication, except that
functions relating to the "activation window" are not present, for
obvious reasons. Please refer to the QtSingleApplication
documentation for explanation of the usage.
A QtSingleCoreApplication instance can communicate to a
QtSingleApplication instance if they share the same application
id. Hence, this class can be used to create a light-weight
command-line tool that sends commands to a GUI application.
\sa QtSingleApplication
*/
/*!
Creates a QtSingleCoreApplication object. The application identifier
will be QCoreApplication::applicationFilePath(). \a argc and \a
argv are passed on to the QCoreAppliation constructor.
*/
QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv)
: QCoreApplication(argc, argv)
{
peer = new QtLocalPeer(this);
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
}
/*!
Creates a QtSingleCoreApplication object with the application
identifier \a appId. \a argc and \a argv are passed on to the
QCoreAppliation constructor.
*/
QtSingleCoreApplication::QtSingleCoreApplication(const QString &appId, int &argc, char **argv)
: QCoreApplication(argc, argv)
{
peer = new QtLocalPeer(this, appId);
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
}
/*!
Returns true if another instance of this application is running;
otherwise false.
This function does not find instances of this application that are
being run by a different user (on Windows: that are running in
another session).
\sa sendMessage()
*/
bool QtSingleCoreApplication::isRunning()
{
return peer->isClient();
}
/*!
Tries to send the text \a message to the currently running
instance. The QtSingleCoreApplication object in the running instance
will emit the messageReceived() signal when it receives the
message.
This function returns true if the message has been sent to, and
processed by, the current instance. If there is no instance
currently running, or if the running instance fails to process the
message within \a timeout milliseconds, this function return false.
\sa isRunning(), messageReceived()
*/
bool QtSingleCoreApplication::sendMessage(const QString &message, int timeout)
{
return peer->sendMessage(message, timeout);
}
/*!
Returns the application identifier. Two processes with the same
identifier will be regarded as instances of the same application.
*/
QString QtSingleCoreApplication::id() const
{
return peer->applicationId();
}
/*!
\fn void QtSingleCoreApplication::messageReceived(const QString& message)
This signal is emitted when the current instance receives a \a
message from another instance of this application.
\sa sendMessage()
*/

View File

@ -1,71 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTSINGLECOREAPPLICATION_H
#define QTSINGLECOREAPPLICATION_H
#include <QCoreApplication>
class QtLocalPeer;
class QtSingleCoreApplication : public QCoreApplication
{
Q_OBJECT
public:
QtSingleCoreApplication(int &argc, char **argv);
QtSingleCoreApplication(const QString &id, int &argc, char **argv);
bool isRunning();
QString id() const;
public Q_SLOTS:
bool sendMessage(const QString &message, int timeout = 5000);
Q_SIGNALS:
void messageReceived(const QString &message);
private:
QtLocalPeer* peer;
};
#endif // QTSINGLECOREAPPLICATION_H

View File

@ -1,10 +0,0 @@
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
HEADERS += $$PWD/qtsinglecoreapplication.h $$PWD/qtlocalpeer.h
SOURCES += $$PWD/qtsinglecoreapplication.cpp $$PWD/qtlocalpeer.cpp
QT *= network
win32:contains(TEMPLATE, lib):contains(CONFIG, shared) {
DEFINES += QT_QTSINGLECOREAPPLICATION_EXPORT=__declspec(dllexport)
}

View File

@ -1,367 +0,0 @@
#include "GlobalActionHelper.h"
#include <QDebug>
#include <QApplication>
QHash<QPair<quint32, quint32>, QAction *> GlobalActionHelper::actions_;
void GlobalActionHelper::init () {
qApp->installNativeEventFilter (new GlobalActionHelper);
}
bool GlobalActionHelper::makeGlobal (QAction *action) {
QKeySequence hotKey = action->shortcut ();
if (hotKey.isEmpty ()) {
return true;
}
Qt::KeyboardModifiers allMods = Qt::ShiftModifier | Qt::ControlModifier |
Qt::AltModifier | Qt::MetaModifier;
Qt::Key key = hotKey.isEmpty () ?
Qt::Key (0) :
Qt::Key ((hotKey[0] ^ allMods) & hotKey[0]);
Qt::KeyboardModifiers mods = hotKey.isEmpty () ?
Qt::KeyboardModifiers (0) :
Qt::KeyboardModifiers (hotKey[0] & allMods);
const quint32 nativeKey = nativeKeycode (key);
const quint32 nativeMods = nativeModifiers (mods);
const bool res = registerHotKey (nativeKey, nativeMods);
if (res) {
actions_.insert (qMakePair (nativeKey, nativeMods), action);
}
else {
qWarning () << "Failed to register global hotkey:" << hotKey.toString ();
}
return res;
}
bool GlobalActionHelper::removeGlobal (QAction *action) {
QKeySequence hotKey = action->shortcut ();
if (hotKey.isEmpty ()) {
return true;
}
Qt::KeyboardModifiers allMods = Qt::ShiftModifier | Qt::ControlModifier |
Qt::AltModifier | Qt::MetaModifier;
Qt::Key key = hotKey.isEmpty () ?
Qt::Key (0) :
Qt::Key ((hotKey[0] ^ allMods) & hotKey[0]);
Qt::KeyboardModifiers mods = hotKey.isEmpty () ?
Qt::KeyboardModifiers (0) :
Qt::KeyboardModifiers (hotKey[0] & allMods);
const quint32 nativeKey = nativeKeycode (key);
const quint32 nativeMods = nativeModifiers (mods);
if (!actions_.contains (qMakePair (nativeKey, nativeMods))) {
return true;
}
const bool res = unregisterHotKey (nativeKey, nativeMods);
if (res) {
actions_.remove (qMakePair (nativeKey, nativeMods));
}
else {
qWarning () << "Failed to unregister global hotkey:" << hotKey.toString ();
}
return res;
}
void GlobalActionHelper::triggerHotKey (quint32 nativeKey, quint32 nativeMods) {
QAction *action = actions_.value (qMakePair (nativeKey, nativeMods));
if (action && action->isEnabled ()) {
action->activate (QAction::Trigger);
}
}
#if defined(Q_OS_LINUX)
# include <QX11Info>
# include <X11/Xlib.h>
# include <xcb/xcb_event.h>
static bool error = false;
static int customHandler (Display *display, XErrorEvent *event) {
Q_UNUSED (display);
switch (event->error_code) {
case BadAccess:
case BadValue:
case BadWindow:
if (event->request_code == 33 /* X_GrabKey */ ||
event->request_code == 34 /* X_UngrabKey */) {
error = true;
}
default:
return 0;
}
}
bool GlobalActionHelper::registerHotKey (quint32 nativeKey, quint32 nativeMods) {
Display *display = QX11Info::display ();
Window window = QX11Info::appRootWindow ();
Bool owner = True;
int pointer = GrabModeAsync;
int keyboard = GrabModeAsync;
error = false;
int (*handler)(Display *display, XErrorEvent *event) = XSetErrorHandler (customHandler);
XGrabKey (display, nativeKey, nativeMods, window, owner, pointer, keyboard);
// allow numlock
XGrabKey (display, nativeKey, nativeMods | Mod2Mask, window, owner, pointer, keyboard);
XSync (display, False);
XSetErrorHandler (handler);
return !error;
}
bool GlobalActionHelper::unregisterHotKey (quint32 nativeKey, quint32 nativeMods) {
Display *display = QX11Info::display ();
Window window = QX11Info::appRootWindow ();
error = false;
int (*handler)(Display *display, XErrorEvent *event) = XSetErrorHandler (customHandler);
XUngrabKey (display, nativeKey, nativeMods, window);
// allow numlock
XUngrabKey (display, nativeKey, nativeMods | Mod2Mask, window);
XSync (display, False);
XSetErrorHandler (handler);
return !error;
}
bool GlobalActionHelper::nativeEventFilter (const QByteArray &eventType,
void *message, long *result) {
Q_UNUSED (eventType);
Q_UNUSED (result);
xcb_generic_event_t *event = static_cast<xcb_generic_event_t *>(message);
if (event->response_type == XCB_KEY_PRESS) {
xcb_key_press_event_t *keyEvent = static_cast<xcb_key_press_event_t *>(message);
const quint32 keycode = keyEvent->detail;
const quint32 modifiers = keyEvent->state & ~XCB_MOD_MASK_2;
triggerHotKey (keycode, modifiers);
}
return false;
}
quint32 GlobalActionHelper::nativeKeycode (Qt::Key key) {
Display *display = QX11Info::display ();
KeySym keySym = XStringToKeysym (qPrintable (QKeySequence (key).toString ()));
return XKeysymToKeycode (display, keySym);
}
quint32 GlobalActionHelper::nativeModifiers (Qt::KeyboardModifiers modifiers) {
quint32 native = 0;
if (modifiers & Qt::ShiftModifier) {
native |= ShiftMask;
}
if (modifiers & Qt::ControlModifier) {
native |= ControlMask;
}
if (modifiers & Qt::AltModifier) {
native |= Mod1Mask;
}
if (modifiers & Qt::MetaModifier) {
native |= Mod4Mask;
}
return native;
}
#elif defined(Q_OS_WIN)
# include <qt_windows.h>
bool GlobalActionHelper::registerHotKey (quint32 nativeKey, quint32 nativeMods) {
return RegisterHotKey (0, nativeMods ^ nativeKey, nativeMods, nativeKey);
}
bool GlobalActionHelper::unregisterHotKey (quint32 nativeKey, quint32 nativeMods) {
return UnregisterHotKey (0, nativeMods ^ nativeKey);
}
bool GlobalActionHelper::nativeEventFilter (const QByteArray &eventType,
void *message, long *result) {
Q_UNUSED (eventType);
Q_UNUSED (result);
MSG *msg = static_cast<MSG *>(message);
if (msg->message == WM_HOTKEY) {
const quint32 keycode = HIWORD (msg->lParam);
const quint32 modifiers = LOWORD (msg->lParam);
triggerHotKey (keycode, modifiers);
}
return false;
}
quint32 GlobalActionHelper::nativeKeycode (Qt::Key key) {
switch (key) {
case Qt::Key_Escape:
return VK_ESCAPE;
case Qt::Key_Tab:
case Qt::Key_Backtab:
return VK_TAB;
case Qt::Key_Backspace:
return VK_BACK;
case Qt::Key_Return:
case Qt::Key_Enter:
return VK_RETURN;
case Qt::Key_Insert:
return VK_INSERT;
case Qt::Key_Delete:
return VK_DELETE;
case Qt::Key_Pause:
return VK_PAUSE;
case Qt::Key_Print:
return VK_PRINT;
case Qt::Key_Clear:
return VK_CLEAR;
case Qt::Key_Home:
return VK_HOME;
case Qt::Key_End:
return VK_END;
case Qt::Key_Left:
return VK_LEFT;
case Qt::Key_Up:
return VK_UP;
case Qt::Key_Right:
return VK_RIGHT;
case Qt::Key_Down:
return VK_DOWN;
case Qt::Key_PageUp:
return VK_PRIOR;
case Qt::Key_PageDown:
return VK_NEXT;
case Qt::Key_F1:
return VK_F1;
case Qt::Key_F2:
return VK_F2;
case Qt::Key_F3:
return VK_F3;
case Qt::Key_F4:
return VK_F4;
case Qt::Key_F5:
return VK_F5;
case Qt::Key_F6:
return VK_F6;
case Qt::Key_F7:
return VK_F7;
case Qt::Key_F8:
return VK_F8;
case Qt::Key_F9:
return VK_F9;
case Qt::Key_F10:
return VK_F10;
case Qt::Key_F11:
return VK_F11;
case Qt::Key_F12:
return VK_F12;
case Qt::Key_F13:
return VK_F13;
case Qt::Key_F14:
return VK_F14;
case Qt::Key_F15:
return VK_F15;
case Qt::Key_F16:
return VK_F16;
case Qt::Key_F17:
return VK_F17;
case Qt::Key_F18:
return VK_F18;
case Qt::Key_F19:
return VK_F19;
case Qt::Key_F20:
return VK_F20;
case Qt::Key_F21:
return VK_F21;
case Qt::Key_F22:
return VK_F22;
case Qt::Key_F23:
return VK_F23;
case Qt::Key_F24:
return VK_F24;
case Qt::Key_Space:
return VK_SPACE;
case Qt::Key_Asterisk:
return VK_MULTIPLY;
case Qt::Key_Plus:
return VK_ADD;
case Qt::Key_Comma:
return VK_SEPARATOR;
case Qt::Key_Minus:
return VK_SUBTRACT;
case Qt::Key_Slash:
return VK_DIVIDE;
case Qt::Key_MediaNext:
return VK_MEDIA_NEXT_TRACK;
case Qt::Key_MediaPrevious:
return VK_MEDIA_PREV_TRACK;
case Qt::Key_MediaPlay:
return VK_MEDIA_PLAY_PAUSE;
case Qt::Key_MediaStop:
return VK_MEDIA_STOP;
case Qt::Key_VolumeDown:
return VK_VOLUME_DOWN;
case Qt::Key_VolumeUp:
return VK_VOLUME_UP;
case Qt::Key_VolumeMute:
return VK_VOLUME_MUTE;
// numbers
case Qt::Key_0:
case Qt::Key_1:
case Qt::Key_2:
case Qt::Key_3:
case Qt::Key_4:
case Qt::Key_5:
case Qt::Key_6:
case Qt::Key_7:
case Qt::Key_8:
case Qt::Key_9:
return key;
// letters
case Qt::Key_A:
case Qt::Key_B:
case Qt::Key_C:
case Qt::Key_D:
case Qt::Key_E:
case Qt::Key_F:
case Qt::Key_G:
case Qt::Key_H:
case Qt::Key_I:
case Qt::Key_J:
case Qt::Key_K:
case Qt::Key_L:
case Qt::Key_M:
case Qt::Key_N:
case Qt::Key_O:
case Qt::Key_P:
case Qt::Key_Q:
case Qt::Key_R:
case Qt::Key_S:
case Qt::Key_T:
case Qt::Key_U:
case Qt::Key_V:
case Qt::Key_W:
case Qt::Key_X:
case Qt::Key_Y:
case Qt::Key_Z:
return key;
default:
return 0;
}
}
quint32 GlobalActionHelper::nativeModifiers (Qt::KeyboardModifiers modifiers) {
// MOD_ALT, MOD_CONTROL, (MOD_KEYUP), MOD_SHIFT, MOD_WIN
quint32 native = 0;
if (modifiers & Qt::ShiftModifier) {
native |= MOD_SHIFT;
}
if (modifiers & Qt::ControlModifier) {
native |= MOD_CONTROL;
}
if (modifiers & Qt::AltModifier) {
native |= MOD_ALT;
}
if (modifiers & Qt::MetaModifier) {
native |= MOD_WIN;
}
//if (modifiers & Qt::KeypadModifier)
//if (modifiers & Qt::GroupSwitchModifier)
return native;
}
#endif

View File

@ -1,29 +0,0 @@
#ifndef GLOBALACTIONHELPER_H
#define GLOBALACTIONHELPER_H
// Some functions copied from QXT lib
#include <QAbstractNativeEventFilter>
#include <QAction>
class GlobalActionHelper : public QAbstractNativeEventFilter {
public:
bool nativeEventFilter (const QByteArray &eventType, void *message,
long *result);
static void init ();
static bool makeGlobal (QAction *action);
static bool removeGlobal (QAction *action);
private:
static QHash<QPair<quint32, quint32>, QAction *> actions_;
static quint32 nativeKeycode (Qt::Key key);
static quint32 nativeModifiers (Qt::KeyboardModifiers modifiers);
static bool registerHotKey (quint32 nativeKey, quint32 nativeMods);
static bool unregisterHotKey (quint32 nativeKey, quint32 nativeMods);
static void triggerHotKey (quint32 nativeKey, quint32 nativeMods);
};
#endif // GLOBALACTIONHELPER_H

View File

@ -1,156 +0,0 @@
#include <QDebug>
#include <leptonica/allheaders.h>
#include <tesseract/host.h>
#include "ImageProcessing.h"
#include "StAssert.h"
#if defined(Q_OS_LINUX)
# include <fstream>
# include <limits>
qint64 getFreeMemory () {
std::string token;
std::ifstream file ("/proc/meminfo");
qint64 freeMem = 0;
while (file >> token) {
if (token == "MemFree:" || token == "Buffers:" || token == "Cached:") {
unsigned long mem = 0;
freeMem += (file >> mem) ? mem : 0;
}
}
return freeMem * 1024;
}
#elif defined(Q_OS_WIN)
# include <windows.h>
qint64 getFreeMemory () {
MEMORYSTATUSEX statex;
statex.dwLength = sizeof (statex);
if (GlobalMemoryStatusEx (&statex)) {
return statex.ullAvailPhys;
}
return -1;
}
#endif
Pix * convertImage (const QImage &image) {
PIX *pix;
int width = image.width ();
int height = image.height ();
int depth = image.depth ();
int bytesPerLine = image.bytesPerLine ();
int wpl = bytesPerLine / 4;
pix = pixCreate (width, height, depth);
pixSetWpl (pix, wpl);
pixSetColormap (pix, NULL);
memmove (pix->data, image.bits (), bytesPerLine * height);
const qreal toDPM = 1.0 / 0.0254;
int resolutionX = image.dotsPerMeterX () / toDPM;
int resolutionY = image.dotsPerMeterY () / toDPM;
if (resolutionX < 300) {
resolutionX = 300;
}
if (resolutionY < 300) {
resolutionY = 300;
}
pixSetResolution (pix, resolutionX, resolutionY);
return pix;
}
QImage convertImage (Pix &image) {
int width = pixGetWidth (&image);
int height = pixGetHeight (&image);
int depth = pixGetDepth (&image);
int bytesPerLine = pixGetWpl (&image) * 4;
l_uint32 *datas = pixGetData (&image);
QImage::Format format;
if (depth == 1) {
format = QImage::Format_Mono;
}
else if (depth == 8) {
format = QImage::Format_Indexed8;
}
else {
format = QImage::Format_RGB32;
}
QImage result ((uchar *)datas, width, height, bytesPerLine, format);
// Set resolution
l_int32 xres, yres;
pixGetResolution (&image, &xres, &yres);
const qreal toDPM = 1.0 / 0.0254;
result.setDotsPerMeterX (xres * toDPM);
result.setDotsPerMeterY (yres * toDPM);
// Handle pallete
QVector<QRgb> _bwCT;
_bwCT.append (qRgb (255,255,255));
_bwCT.append (qRgb (0,0,0));
QVector<QRgb> _grayscaleCT (256);
for (int i = 0; i < 256; i++) {
_grayscaleCT.append (qRgb (i, i, i));
}
switch (depth) {
case 1:
result.setColorTable (_bwCT);
break;
case 8:
result.setColorTable (_grayscaleCT);
break;
default:
result.setColorTable (_grayscaleCT);
}
if (result.isNull ()) {
static QImage none (0,0,QImage::Format_Invalid);
qDebug ("Invalid format!!!\n");
return none;
}
return result;
}
Pix * prepareImage (const QImage &image, int preferredScale) {
Pix *pix = convertImage (image);
ST_ASSERT (pix != NULL);
Pix *gray = pixConvertRGBToGray (pix, 0.0, 0.0, 0.0);
ST_ASSERT (gray != NULL);
pixDestroy (&pix);
Pix *scaled = gray;
if (preferredScale > 0) {
float maxScaleX = MAX_INT16 / double (gray->w);
float scaleX = std::min (float (preferredScale), maxScaleX);
float maxScaleY = MAX_INT16 / double (gray->h);
float scaleY = std::min (float (preferredScale), maxScaleY);
float scale = std::min (scaleX, scaleY);
qint64 availableMemory = getFreeMemory () * 0.95;
if (availableMemory > 0) {
qint32 actualSize = gray->w * gray->h * gray->d / 8;
float maxScaleMemory = float (availableMemory) / actualSize;
scale = std::min (scale, maxScaleMemory);
}
scaled = pixScale (gray, scale, scale);
if (scaled == NULL) {
scaled = gray;
}
}
if (scaled != gray) {
pixDestroy (&gray);
}
return scaled;
}
void cleanupImage (Pix **image) {
pixDestroy (image);
}

View File

@ -1,18 +0,0 @@
#ifndef IMAGEPROCESSING_H
#define IMAGEPROCESSING_H
#include <QImage>
class Pix;
//! Convert QImage to Leptonica's PIX.
Pix * convertImage (const QImage &image);
//! Convert Leptonica's PIX to QImage.
QImage convertImage (Pix &image);
//! Propare image for OCR.
Pix * prepareImage (const QImage &image, int preferredScale);
//! Free allocated resources for image.
void cleanupImage (Pix **image);
#endif // IMAGEPROCESSING_H

View File

@ -1,301 +0,0 @@
#include <QDir>
#include <QSettings>
#include "LanguageHelper.h"
#include "Settings.h"
#include "StAssert.h"
LanguageHelper::LanguageHelper () {
init ();
}
QStringList LanguageHelper::availableOcrLanguagesUi () const {
QStringList uiItems;
foreach (const QString &item, availableOcrLanguages_) {
uiItems << ocrCodeToUi (item);
}
uiItems.sort ();
return uiItems;
}
const QStringList &LanguageHelper::availableOcrLanguages () const {
return availableOcrLanguages_;
}
QStringList LanguageHelper::availableOcrLanguages (const QString &path) const {
QDir dir (path + "/tessdata/");
if (!dir.exists ()) {
return QStringList ();
}
QStringList items;
QStringList files = dir.entryList (QStringList () << "*.traineddata", QDir::Files);
foreach (const QString &file, files) {
QString lang = file.left (file.indexOf ("."));
items << lang;
}
return items;
}
QStringList LanguageHelper::availableOcrLanguagesUi (const QString &path) const {
QStringList uiItems, items;
items = availableOcrLanguages (path);
foreach (const QString &item, items) {
uiItems << ocrCodeToUi (item);
}
uiItems.sort ();
return uiItems;
}
QStringList LanguageHelper::translateLanguagesUi () const {
QStringList uiItems = translateLanguages_.keys ();
uiItems.sort ();
return uiItems;
}
QStringList LanguageHelper::translateLanguages () const {
return translateLanguages_.values ();
}
QString LanguageHelper::translateCodeToUi (const QString &text) const {
return translateLanguages_.key (text, text);
}
QString LanguageHelper::translateUiToCode (const QString &text) const {
return translateLanguages_.value (text, text);
}
QString LanguageHelper::ocrCodeToUi (const QString &text) const {
return ocrLanguages_.key (text, text);
}
QString LanguageHelper::ocrUiToCode (const QString &text) const {
return ocrLanguages_.value (text, text);
}
QString LanguageHelper::ocrToTranslateCodes (const QString &text) const {
QString ocrUi = ocrCodeToUi (text);
QString translateCode = translateUiToCode (ocrUi);
if (translateCode == ocrUi) {
translateCode = "auto";
}
return translateCode;
}
QString LanguageHelper::translateToOcrCodes (const QString &text) const {
QString translateUi = translateCodeToUi (text);
QString ocrCode = ocrUiToCode (translateUi);
if (translateUi == ocrCode) {
return QString ();
}
return ocrCode;
}
void LanguageHelper::init () {
initOcrLanguages ();
initTranslateLanguages ();
updateAvailableOcrLanguages ();
}
void LanguageHelper::updateAvailableOcrLanguages () {
availableOcrLanguages_.clear ();
QSettings settings;
settings.beginGroup (settings_names::recogntionGroup);
QString tessDataPlace = settings.value (settings_names::tessDataPlace,
settings_values::tessDataPlace).toString ();
availableOcrLanguages_ = availableOcrLanguages (tessDataPlace);
}
void LanguageHelper::updateMenu (QMenu *menu, const QStringList &languages, int groupSize) const {
ST_ASSERT (menu != NULL);
menu->clear ();
if (languages.isEmpty ()) {
return;
}
if (languages.size () <= groupSize) {
foreach (const QString &language, languages) {
menu->addAction (language);
}
}
else {
int subIndex = groupSize;
QMenu *subMenu = NULL;
QString prevLetter;
foreach (const QString &language, languages) {
QString curLetter = language.left (1);
if (++subIndex >= groupSize && prevLetter != curLetter) {
if (subMenu != NULL) {
subMenu->setTitle (subMenu->title () + " - " + prevLetter);
}
subMenu = menu->addMenu (curLetter);
subIndex = 0;
}
prevLetter = curLetter;
subMenu->addAction (language);
}
subMenu->setTitle (subMenu->title () + " - " + prevLetter);
}
}
void LanguageHelper::initTranslateLanguages () {
translateLanguages_.insert (QObject::tr ("Afrikaans"),"af");
translateLanguages_.insert (QObject::tr ("Albanian"),"sq");
translateLanguages_.insert (QObject::tr ("Arabic"),"ar");
translateLanguages_.insert (QObject::tr ("Armenian"),"hy");
translateLanguages_.insert (QObject::tr ("Azerbaijani"),"az");
translateLanguages_.insert (QObject::tr ("Basque"),"eu");
translateLanguages_.insert (QObject::tr ("Belarusian"),"be");
translateLanguages_.insert (QObject::tr ("Bulgarian"),"bg");
translateLanguages_.insert (QObject::tr ("Catalan"),"ca");
translateLanguages_.insert (QObject::tr ("Chinese (Simplified)"),"zh-CN");
translateLanguages_.insert (QObject::tr ("Chinese (Traditional)"),"zh-TW");
translateLanguages_.insert (QObject::tr ("Croatian"),"hr");
translateLanguages_.insert (QObject::tr ("Czech"),"cs");
translateLanguages_.insert (QObject::tr ("Danish"),"da");
translateLanguages_.insert (QObject::tr ("Dutch"),"nl");
translateLanguages_.insert (QObject::tr ("English"),"en");
translateLanguages_.insert (QObject::tr ("Estonian"),"et");
translateLanguages_.insert (QObject::tr ("Filipino"),"tl");
translateLanguages_.insert (QObject::tr ("Finnish"),"fi");
translateLanguages_.insert (QObject::tr ("French"),"fr");
translateLanguages_.insert (QObject::tr ("Galician"),"gl");
translateLanguages_.insert (QObject::tr ("Georgian"),"ka");
translateLanguages_.insert (QObject::tr ("German"),"de");
translateLanguages_.insert (QObject::tr ("Greek"),"el");
translateLanguages_.insert (QObject::tr ("Haitian Creole"),"ht");
translateLanguages_.insert (QObject::tr ("Hebrew"),"iw");
translateLanguages_.insert (QObject::tr ("Hindi"),"hi");
translateLanguages_.insert (QObject::tr ("Hungarian"),"hu");
translateLanguages_.insert (QObject::tr ("Icelandic"),"is");
translateLanguages_.insert (QObject::tr ("Indonesian"),"id");
translateLanguages_.insert (QObject::tr ("Irish"),"ga");
translateLanguages_.insert (QObject::tr ("Italian"),"it");
translateLanguages_.insert (QObject::tr ("Japanese"),"ja");
translateLanguages_.insert (QObject::tr ("Korean"),"ko");
translateLanguages_.insert (QObject::tr ("Latvian"),"lv");
translateLanguages_.insert (QObject::tr ("Lithuanian"),"lt");
translateLanguages_.insert (QObject::tr ("Macedonian"),"mk");
translateLanguages_.insert (QObject::tr ("Malay"),"ms");
translateLanguages_.insert (QObject::tr ("Maltese"),"mt");
translateLanguages_.insert (QObject::tr ("Norwegian"),"no");
translateLanguages_.insert (QObject::tr ("Persian"),"fa");
translateLanguages_.insert (QObject::tr ("Polish"),"pl");
translateLanguages_.insert (QObject::tr ("Portuguese"),"pt");
translateLanguages_.insert (QObject::tr ("Romanian"),"ro");
translateLanguages_.insert (QObject::tr ("Russian"),"ru");
translateLanguages_.insert (QObject::tr ("Serbian"),"sr");
translateLanguages_.insert (QObject::tr ("Slovak"),"sk");
translateLanguages_.insert (QObject::tr ("Slovenian"),"sl");
translateLanguages_.insert (QObject::tr ("Spanish"),"es");
translateLanguages_.insert (QObject::tr ("Swahili"),"sw");
translateLanguages_.insert (QObject::tr ("Swedish"),"sv");
translateLanguages_.insert (QObject::tr ("Thai"),"th");
translateLanguages_.insert (QObject::tr ("Turkish"),"tr");
translateLanguages_.insert (QObject::tr ("Ukrainian"),"uk");
translateLanguages_.insert (QObject::tr ("Urdu"),"ur");
translateLanguages_.insert (QObject::tr ("Vietnamese"),"vi");
translateLanguages_.insert (QObject::tr ("Welsh"),"cy");
translateLanguages_.insert (QObject::tr ("Yiddish"),"yi");
}
void LanguageHelper::initOcrLanguages () {
ocrLanguages_.insert (QObject::tr ("Ancient Greek"),"grc");
ocrLanguages_.insert (QObject::tr ("Esperanto alternative"),"epo_alt");
ocrLanguages_.insert (QObject::tr ("English"),"eng");
ocrLanguages_.insert (QObject::tr ("Ukrainian"),"ukr");
ocrLanguages_.insert (QObject::tr ("Turkish"),"tur");
ocrLanguages_.insert (QObject::tr ("Thai"),"tha");
ocrLanguages_.insert (QObject::tr ("Tagalog"),"tgl");
ocrLanguages_.insert (QObject::tr ("Telugu"),"tel");
ocrLanguages_.insert (QObject::tr ("Tamil"),"tam");
ocrLanguages_.insert (QObject::tr ("Swedish"),"swe");
ocrLanguages_.insert (QObject::tr ("Swahili"),"swa");
ocrLanguages_.insert (QObject::tr ("Serbian"),"srp");
ocrLanguages_.insert (QObject::tr ("Albanian"),"sqi");
ocrLanguages_.insert (QObject::tr ("Spanish"),"spa");
ocrLanguages_.insert (QObject::tr ("Slovenian"),"slv");
ocrLanguages_.insert (QObject::tr ("Slovakian"),"slk");
ocrLanguages_.insert (QObject::tr ("Romanian"),"ron");
ocrLanguages_.insert (QObject::tr ("Portuguese"),"por");
ocrLanguages_.insert (QObject::tr ("Polish"),"pol");
ocrLanguages_.insert (QObject::tr ("Norwegian"),"nor");
ocrLanguages_.insert (QObject::tr ("Dutch"),"nld");
ocrLanguages_.insert (QObject::tr ("Malay"),"msa");
ocrLanguages_.insert (QObject::tr ("Maltese"),"mlt");
ocrLanguages_.insert (QObject::tr ("Macedonian"),"mkd");
ocrLanguages_.insert (QObject::tr ("Malayalam"),"mal");
ocrLanguages_.insert (QObject::tr ("Lithuanian"),"lit");
ocrLanguages_.insert (QObject::tr ("Latvian"),"lav");
ocrLanguages_.insert (QObject::tr ("Korean"),"kor");
ocrLanguages_.insert (QObject::tr ("Kannada"),"kan");
ocrLanguages_.insert (QObject::tr ("Italian"),"ita");
ocrLanguages_.insert (QObject::tr ("Icelandic"),"isl");
ocrLanguages_.insert (QObject::tr ("Indonesian"),"ind");
ocrLanguages_.insert (QObject::tr ("Cherokee"),"chr");
ocrLanguages_.insert (QObject::tr ("Hungarian"),"hun");
ocrLanguages_.insert (QObject::tr ("Croatian"),"hrv");
ocrLanguages_.insert (QObject::tr ("Hindi"),"hin");
ocrLanguages_.insert (QObject::tr ("Hebrew"),"heb");
ocrLanguages_.insert (QObject::tr ("Galician"),"glg");
ocrLanguages_.insert (QObject::tr ("Middle French (ca. 1400-1600)"),"frm");
ocrLanguages_.insert (QObject::tr ("Frankish"),"frk");
ocrLanguages_.insert (QObject::tr ("French"),"fra");
ocrLanguages_.insert (QObject::tr ("Finnish"),"fin");
ocrLanguages_.insert (QObject::tr ("Basque"),"eus");
ocrLanguages_.insert (QObject::tr ("Estonian"),"est");
ocrLanguages_.insert (QObject::tr ("Math / equation"),"equ");
ocrLanguages_.insert (QObject::tr ("Esperanto"),"epo");
ocrLanguages_.insert (QObject::tr ("Middle English (1100-1500)"),"enm");
ocrLanguages_.insert (QObject::tr ("Greek"),"ell");
ocrLanguages_.insert (QObject::tr ("German"),"deu");
ocrLanguages_.insert (QObject::tr ("Danish"),"dan");
ocrLanguages_.insert (QObject::tr ("Czech"),"ces");
ocrLanguages_.insert (QObject::tr ("Catalan"),"cat");
ocrLanguages_.insert (QObject::tr ("Bulgarian"),"bul");
ocrLanguages_.insert (QObject::tr ("Bengali"),"ben");
ocrLanguages_.insert (QObject::tr ("Belarusian"),"bel");
ocrLanguages_.insert (QObject::tr ("Azerbaijani"),"aze");
ocrLanguages_.insert (QObject::tr ("Arabic"),"ara");
ocrLanguages_.insert (QObject::tr ("Afrikaans"),"afr");
ocrLanguages_.insert (QObject::tr ("Japanese"),"jpn");
ocrLanguages_.insert (QObject::tr ("Chinese (Simplified)"),"chi_sim");
ocrLanguages_.insert (QObject::tr ("Chinese (Traditional)"),"chi_tra");
ocrLanguages_.insert (QObject::tr ("Russian"),"rus");
ocrLanguages_.insert (QObject::tr ("Vietnamese"),"vie");
ocrLanguages_.insert (QObject::tr ("Amharic"),"amh");
ocrLanguages_.insert (QObject::tr ("Assamese"),"asm");
ocrLanguages_.insert (QObject::tr ("Tibetan"),"bod");
ocrLanguages_.insert (QObject::tr ("Bosnian"),"bos");
ocrLanguages_.insert (QObject::tr ("Cebuano"),"ceb");
ocrLanguages_.insert (QObject::tr ("Welsh"),"cym");
ocrLanguages_.insert (QObject::tr ("Dzongkha"),"dzo");
ocrLanguages_.insert (QObject::tr ("Persian"),"fas");
ocrLanguages_.insert (QObject::tr ("Irish"),"gle");
ocrLanguages_.insert (QObject::tr ("Gujarati"),"guj");
ocrLanguages_.insert (QObject::tr ("Haitian"),"hat");
ocrLanguages_.insert (QObject::tr ("Inuktitut"),"iku");
ocrLanguages_.insert (QObject::tr ("Javanese"),"jav");
ocrLanguages_.insert (QObject::tr ("Georgian"),"kat");
ocrLanguages_.insert (QObject::tr ("Kazakh"),"kaz");
ocrLanguages_.insert (QObject::tr ("Khmer"),"khm");
ocrLanguages_.insert (QObject::tr ("Kirghiz"),"kir");
ocrLanguages_.insert (QObject::tr ("Kurdish"),"kur");
ocrLanguages_.insert (QObject::tr ("Lao"),"lao");
ocrLanguages_.insert (QObject::tr ("Latin"),"lat");
ocrLanguages_.insert (QObject::tr ("Marathi"),"mar");
ocrLanguages_.insert (QObject::tr ("Burmese"),"mya");
ocrLanguages_.insert (QObject::tr ("Nepali"),"nep");
ocrLanguages_.insert (QObject::tr ("Oriya"),"ori");
ocrLanguages_.insert (QObject::tr ("Panjabi"),"pan");
ocrLanguages_.insert (QObject::tr ("Pushto"),"pus");
ocrLanguages_.insert (QObject::tr ("Sanskrit"),"san");
ocrLanguages_.insert (QObject::tr ("Sinhala"),"sin");
ocrLanguages_.insert (QObject::tr ("Syriac"),"syr");
ocrLanguages_.insert (QObject::tr ("Tajik"),"tgk");
ocrLanguages_.insert (QObject::tr ("Tigrinya"),"tir");
ocrLanguages_.insert (QObject::tr ("Uighur"),"uig");
ocrLanguages_.insert (QObject::tr ("Urdu"),"urd");
ocrLanguages_.insert (QObject::tr ("Uzbek"),"uzb");
ocrLanguages_.insert (QObject::tr ("Yiddish"),"yid");
}

View File

@ -1,43 +0,0 @@
#ifndef LANGUAGEHELPER_H
#define LANGUAGEHELPER_H
#include <QMap>
#include <QStringList>
#include <QMenu>
class LanguageHelper {
public:
LanguageHelper ();
QStringList availableOcrLanguagesUi () const;
const QStringList &availableOcrLanguages () const;
QStringList availableOcrLanguagesUi (const QString &path) const;
QStringList translateLanguagesUi () const;
QStringList translateLanguages () const;
QString translateCodeToUi (const QString &text) const;
QString translateUiToCode (const QString &text) const;
QString ocrCodeToUi (const QString &text) const;
QString ocrUiToCode (const QString &text) const;
QString ocrToTranslateCodes (const QString &text) const;
QString translateToOcrCodes (const QString &text) const;
void updateAvailableOcrLanguages ();
//! Update languages menu. Group items into submenus if needed.
void updateMenu (QMenu *menu, const QStringList &languages, int groupSize = 10) const;
private:
QStringList availableOcrLanguages (const QString &path) const;
void init ();
void initTranslateLanguages ();
void initOcrLanguages ();
private:
QStringList availableOcrLanguages_;
QMap<QString, QString> translateLanguages_;
QMap<QString, QString> ocrLanguages_;
};
#endif // LANGUAGEHELPER_H

View File

@ -1,457 +0,0 @@
#include "Manager.h"
#include <QDebug>
#include <QMenu>
#include <QApplication>
#include <QDesktopWidget>
#include <QScreen>
#include <QDesktopWidget>
#include <QThread>
#include <QSettings>
#include <QClipboard>
#include <QMessageBox>
#include <QInputDialog>
#include <QNetworkProxy>
#include "Settings.h"
#include "SettingsEditor.h"
#include "SelectionDialog.h"
#include "GlobalActionHelper.h"
#include "Recognizer.h"
#include "WebTranslator.h"
#include "ResultDialog.h"
#include "LanguageHelper.h"
#include "StAssert.h"
#include "Utils.h"
#include "Updater.h"
Manager::Manager (QObject *parent) :
QObject (parent),
trayIcon_ (new QSystemTrayIcon (this)),
dictionary_ (new LanguageHelper),
resultDialog_ (new ResultDialog (*dictionary_)),
updater_ (new Updater (this)), updateTimer_ (new QTimer (this)),
captureAction_ (NULL), repeatCaptureAction_ (NULL),
repeatAction_ (NULL), clipboardAction_ (NULL),
useResultDialog_ (true), doTranslation_ (true), itemProcessingCount_ (0) {
updateNormalIcon ();
GlobalActionHelper::init ();
qRegisterMetaType<ProcessingItem>();
// Recognizer
Recognizer *recognizer = new Recognizer;
connect (this, SIGNAL (requestRecognize (ProcessingItem)),
recognizer, SLOT (recognize (ProcessingItem)));
connect (recognizer, SIGNAL (recognized (ProcessingItem)),
this, SIGNAL (requestTranslate (ProcessingItem)));
connect (recognizer, SIGNAL (error (QString)),
SLOT (showError (QString)));
connect (this, SIGNAL (settingsEdited ()),
recognizer, SLOT (applySettings ()));
QThread *recognizerThread = new QThread (this);
threads_ << recognizerThread;
recognizer->moveToThread (recognizerThread);
recognizerThread->start ();
connect (qApp, SIGNAL (aboutToQuit ()), recognizerThread, SLOT (quit ()));
// Translator
WebTranslator *translator = new WebTranslator;
connect (this, SIGNAL (requestTranslate (ProcessingItem)),
translator, SLOT (translate (ProcessingItem)));
connect (translator, SIGNAL (translated (ProcessingItem)),
SLOT (showResult (ProcessingItem)));
connect (translator, SIGNAL (error (QString)),
SLOT (showError (QString)));
connect (this, SIGNAL (settingsEdited ()),
translator, SLOT (applySettings ()));
connect (this, SIGNAL (settingsEdited ()), this, SLOT (applySettings ()));
connect (updater_, SIGNAL (updated ()), SIGNAL (settingsEdited ()));
connect (updater_, SIGNAL (error (QString)), SLOT (showError (QString)));
updateTimer_->setSingleShot (true);
connect (updateTimer_, SIGNAL (timeout ()), SLOT (checkForUpdates ()));
resultDialog_->setWindowIcon (trayIcon_->icon ());
connect (this, SIGNAL (settingsEdited ()), resultDialog_, SLOT (applySettings ()));
connect (resultDialog_, SIGNAL (requestRecognize (ProcessingItem)),
this, SIGNAL (requestRecognize (ProcessingItem)));
connect (resultDialog_, SIGNAL (requestTranslate (ProcessingItem)),
this, SIGNAL (requestTranslate (ProcessingItem)));
connect (resultDialog_, SIGNAL (requestClipboard ()), SLOT (copyLastToClipboard ()));
connect (resultDialog_, SIGNAL (requestImageClipboard ()),
SLOT (copyLastImageToClipboard ()));
connect (resultDialog_, SIGNAL (requestEdition (ProcessingItem)),
this, SLOT (editRecognized (ProcessingItem)));
connect (trayIcon_, SIGNAL (activated (QSystemTrayIcon::ActivationReason)),
SLOT (processTrayAction (QSystemTrayIcon::ActivationReason)));
trayIcon_->setContextMenu (trayContextMenu ());
updateActionsState ();
trayIcon_->show ();
applySettings ();
}
QMenu * Manager::trayContextMenu () {
QMenu *menu = new QMenu ();
captureAction_ = menu->addAction (tr ("Захват"), this, SLOT (capture ()));
repeatCaptureAction_ = menu->addAction (tr ("Повторить захват"),
this, SLOT (repeatCapture ()));
QMenu *translateMenu = menu->addMenu (tr ("Результат"));
repeatAction_ = translateMenu->addAction (tr ("Показать"), this,
SLOT (showLast ()));
clipboardAction_ = translateMenu->addAction (tr ("В буфер"), this,
SLOT (copyLastToClipboard ()));
menu->addAction (tr ("Настройки"), this, SLOT (settings ()));
menu->addAction (tr ("О программе"), this, SLOT (about ()));
menu->addAction (tr ("Выход"), this, SLOT (close ()));
return menu;
}
void Manager::updateActionsState (bool isEnabled) {
#ifdef Q_OS_LINUX
// Avoid unneeded tray blinking (required to update context menu).
QList<QAction *> actions;
actions << captureAction_ << repeatCaptureAction_ << repeatAction_ << clipboardAction_;
QList<bool> states;
foreach (const QAction * action, actions) {
states << action->isEnabled ();
}
#endif
captureAction_->setEnabled (isEnabled);
repeatCaptureAction_->setEnabled (isEnabled && !selections_.isEmpty ());
const ProcessingItem &lastItem = resultDialog_->item ();
repeatAction_->setEnabled (isEnabled && lastItem.isValid ());
clipboardAction_->setEnabled (isEnabled && lastItem.isValid ());
#ifdef Q_OS_LINUX
for (int i = 0, end = actions.size (); i < end; ++i) {
if (states.at (i) != actions.at (i)->isEnabled ()) {
trayIcon_->hide ();
trayIcon_->show ();
break;
}
}
#endif
}
void Manager::applySettings () {
#define GET(NAME) settings.value (settings_names::NAME, settings_values::NAME)
QSettings settings;
settings.beginGroup (settings_names::guiGroup);
QStringList globalActionsFailed;
Q_CHECK_PTR (captureAction_);
GlobalActionHelper::removeGlobal (captureAction_);
captureAction_->setShortcut (GET (captureHotkey).toString ());
if (!GlobalActionHelper::makeGlobal (captureAction_)) {
globalActionsFailed << captureAction_->shortcut ().toString ();
}
Q_CHECK_PTR (repeatCaptureAction_);
GlobalActionHelper::removeGlobal (repeatCaptureAction_);
repeatCaptureAction_->setShortcut (GET (repeatCaptureHotkey).toString ());
if (!GlobalActionHelper::makeGlobal (repeatCaptureAction_)) {
globalActionsFailed << repeatCaptureAction_->shortcut ().toString ();
}
Q_CHECK_PTR (repeatAction_);
GlobalActionHelper::removeGlobal (repeatAction_);
repeatAction_->setShortcut (GET (repeatHotkey).toString ());
if (!GlobalActionHelper::makeGlobal (repeatAction_)) {
globalActionsFailed << repeatAction_->shortcut ().toString ();
}
Q_CHECK_PTR (clipboardAction_);
GlobalActionHelper::removeGlobal (clipboardAction_);
clipboardAction_->setShortcut (GET (clipboardHotkey).toString ());
if (!GlobalActionHelper::makeGlobal (clipboardAction_)) {
globalActionsFailed << clipboardAction_->shortcut ().toString ();
}
if (!globalActionsFailed.isEmpty ()) {
showError (tr ("Failed to register global shortcuts:\n%1")
.arg (globalActionsFailed.join ("\n")));
}
// Depends on SettingsEditor button indexes. 1==dialog
useResultDialog_ = GET (resultShowType).toBool ();
QNetworkProxy proxy = QNetworkProxy::applicationProxy ();
QList<int> proxyTypes = proxyTypeOrder ();
int proxyTypeIndex = std::min (GET (proxyType).toInt (), proxyTypes.size ());
proxy.setType (QNetworkProxy::ProxyType (proxyTypes.at (std::max (proxyTypeIndex, 0))));
proxy.setHostName (GET (proxyHostName).toString ());
proxy.setPort (GET (proxyPort).toInt ());
proxy.setUser (GET (proxyUser).toString ());
if (GET (proxySavePassword).toBool ()) {
proxy.setPassword (encode (GET (proxyPassword).toString ()));
}
QNetworkProxy::setApplicationProxy (proxy);
scheduleUpdate ();
settings.endGroup ();
settings.beginGroup (settings_names::recogntionGroup);
defaultOrcLanguage_ = GET (ocrLanguage).toString ();
settings.endGroup ();
settings.beginGroup (settings_names::translationGroup);
defaultTranslationLanguage_ = GET (translationLanguage).toString ();
doTranslation_ = GET (doTranslation).toBool ();
settings.endGroup ();
Q_CHECK_PTR (dictionary_);
dictionary_->updateAvailableOcrLanguages ();
#undef GET
}
void Manager::scheduleUpdate (bool justChecked) {
#define GET(NAME) settings.value (settings_names::NAME, settings_values::NAME)
QSettings settings;
settings.beginGroup (settings_names::guiGroup);
updateTimer_->stop ();
if (justChecked) {
settings.setValue (settings_names::lastUpdateCheck, QDateTime::currentDateTime ());
}
QDateTime nextUpdateCheck = updater_->nextCheckTime (GET (lastUpdateCheck).toDateTime (),
GET (autoUpdateType).toInt ());
if (nextUpdateCheck.isValid ()) {
updateTimer_->start (QDateTime::currentDateTime ().msecsTo (nextUpdateCheck));
}
#undef GET
}
void Manager::checkForUpdates () {
updater_->checkForUpdates ();
scheduleUpdate (true);
}
Manager::~Manager () {
foreach (SelectionDialog * selection, selections_.values ()) {
selection->hide ();
delete selection;
}
trayIcon_->hide ();
delete trayIcon_->contextMenu ();
foreach (QThread * thread, threads_) {
thread->quit ();
thread->wait (1000000);
}
}
void Manager::capture () {
QList<QScreen *> screens = QApplication::screens ();
foreach (QScreen * screen, screens) {
QRect geometry = screen->availableGeometry ();
QPixmap pixmap = screen->grabWindow (0, geometry.x (), geometry.y (),
geometry.width (), geometry.height ());
QString name = screen->name ();
if (!selections_.contains (name)) {
SelectionDialog *selection = new SelectionDialog (*dictionary_);
selection->setWindowIcon (trayIcon_->icon ());
connect (this, SIGNAL (closeSelections ()), selection, SLOT (close ()));
connect (this, SIGNAL (settingsEdited ()), selection, SLOT (applySettings ()));
connect (selection, SIGNAL (selected (ProcessingItem)),
SLOT (handleSelection (ProcessingItem)));
connect (selection, SIGNAL (rejected ()), SIGNAL (closeSelections ()));
selections_[name] = selection;
}
SelectionDialog *selection = selections_[name];
selection->setPixmap (pixmap, geometry);
}
updateActionsState ();
}
void Manager::handleSelection (ProcessingItem item) {
bool altMod = item.modifiers & Qt::AltModifier;
bool doTranslation = (doTranslation_ && !altMod) || (!doTranslation_ && altMod);
if (doTranslation) {
item.translateLanguage = defaultTranslationLanguage_;
}
if (item.ocrLanguage.isEmpty ()) {
item.ocrLanguage = defaultOrcLanguage_;
}
if (item.swapLanguages_) {
QString translate = (item.translateLanguage.isEmpty ())
? defaultTranslationLanguage_ : item.translateLanguage;
if (doTranslation) {
item.translateLanguage = dictionary_->ocrToTranslateCodes (item.ocrLanguage);
}
item.sourceLanguage.clear ();
item.ocrLanguage = dictionary_->translateToOcrCodes (translate);
if (item.ocrLanguage.isEmpty ()) {
showError (tr ("Не найден подходящий язык распознавания."));
return;
}
}
if (item.sourceLanguage.isEmpty ()) {
item.sourceLanguage = dictionary_->ocrToTranslateCodes (item.ocrLanguage);
}
emit requestRecognize (item);
++itemProcessingCount_;
updateNormalIcon ();
if (!(item.modifiers & Qt::ControlModifier)) {
emit closeSelections ();
}
}
void Manager::repeatCapture () {
if (selections_.isEmpty ()) {
return;
}
QList<QScreen *> screens = QApplication::screens ();
foreach (QScreen * screen, screens) {
QString name = screen->name ();
if (!selections_.contains (name)) {
continue;
}
SelectionDialog *selection = selections_[name];
selection->show ();
selection->activateWindow ();
}
}
void Manager::settings () {
SettingsEditor editor (*dictionary_);
editor.setWindowIcon (trayIcon_->icon ());
connect (&editor, SIGNAL (settingsEdited ()), SIGNAL (settingsEdited ()));
connect (&editor, SIGNAL (updateCheckRequested ()), SLOT (checkForUpdates ()));
updateActionsState (false);
editor.exec ();
updateActionsState (true);
}
void Manager::close () {
QApplication::quit ();
}
void Manager::about () {
QString text = tr ("Программа для распознавания текста на экране.\n" \
"Создана с использованием Qt, tesseract-ocr, Google Translate.\n"
"Автор: Gres (translator@gres.biz)\n"
"Версия: %1 от %2 %3").arg (updater_->currentAppVersion ())
.arg (__DATE__).arg (__TIME__);
QString tips = tr ("\n\nПодсказки.\n"
"Клик по иконке в трее:\n"
"* левой кнопкой - отобразить последний результат\n"
"* средней кнопкой - скопировать последний результат в буфер обмена\n"
#ifdef Q_OS_WIN
"* двойной клик - повторный захват последнего экрана\n"
#endif
"\n"
"Захвата изображения при зажатых кнопках:\n"
"* Ctrl - не выходить из режима захвата\n"
"* Alt - выполнить перевод, если в настройках он выключен "
"(и наоборот, не выполнять, если включен)\n"
"");
QMessageBox message (QMessageBox::Information, tr ("О программе"), text + tips,
QMessageBox::Ok);
message.setIconPixmap (trayIcon_->icon ().pixmap (QSize (64, 64)));
message.exec ();
}
void Manager::processTrayAction (QSystemTrayIcon::ActivationReason reason) {
if (reason == QSystemTrayIcon::Trigger && repeatAction_->isEnabled ()) {
showLast ();
}
else if (reason == QSystemTrayIcon::MiddleClick && clipboardAction_->isEnabled ()) {
copyLastToClipboard ();
trayIcon_->showMessage (tr ("Результат"),
tr ("Последний результат был скопирован в буфер обмена."),
QSystemTrayIcon::Information);
}
else if (reason == QSystemTrayIcon::DoubleClick && repeatCaptureAction_->isEnabled ()) {
repeatCapture ();
}
}
void Manager::editRecognized (ProcessingItem item) {
QString fixed = QInputDialog::getMultiLineText (
NULL, tr ("Правка"), tr ("Исправьте распознанный текст"), item.recognized);
if (!fixed.isEmpty ()) {
item.recognized = fixed;
++itemProcessingCount_;
updateNormalIcon ();
emit requestTranslate (item);
}
}
void Manager::showLast () {
const ProcessingItem &item = resultDialog_->item ();
if (item.isValid ()) {
++itemProcessingCount_;
showResult (item);
}
}
void Manager::copyLastToClipboard () {
const ProcessingItem &item = resultDialog_->item ();
if (item.isValid ()) {
QClipboard *clipboard = QApplication::clipboard ();
QString message = item.recognized;
if (!item.translated.isEmpty ()) {
message += " - " + item.translated;
}
clipboard->setText (message);
}
}
void Manager::copyLastImageToClipboard () {
const ProcessingItem &item = resultDialog_->item ();
if (item.isValid ()) {
QClipboard *clipboard = QApplication::clipboard ();
clipboard->setPixmap (item.source);
}
}
void Manager::showResult (ProcessingItem item) {
--itemProcessingCount_;
if (!item.isValid ()) {
// delay because it can show error
QTimer::singleShot (3000, this, SLOT (updateNormalIcon ()));
return;
}
changeIcon (IconTypeSuccess);
if (useResultDialog_) {
resultDialog_->showResult (item);
}
else {
QString message = item.recognized + " - " + item.translated;
trayIcon_->showMessage (tr ("Результат"), message, QSystemTrayIcon::Information);
}
updateActionsState ();
}
void Manager::showError (QString text) {
qCritical () << text;
changeIcon (IconTypeError);
trayIcon_->showMessage (tr ("Ошибка"), text, QSystemTrayIcon::Critical);
}
void Manager::changeIcon (int iconType, int timeoutMsec) {
QString fileName;
switch (iconType) {
case IconTypeSuccess:
fileName = ":/images/STIconGreen.png";
break;
case IconTypeError:
fileName = ":/images/STIconRed.png";
break;
default:
return;
}
trayIcon_->setIcon (QIcon (fileName));
if (timeoutMsec > 0) {
QTimer::singleShot (timeoutMsec, this, SLOT (updateNormalIcon ()));
}
}
void Manager::updateNormalIcon () {
QString fileName = itemProcessingCount_ > 0
? ":/images/STIconOrange.png" : ":/images/STIconBlue.png";
trayIcon_->setIcon (QIcon (fileName));
}

View File

@ -1,84 +0,0 @@
#ifndef MANAGER_H
#define MANAGER_H
#include <QPixmap>
#include <QSystemTrayIcon>
#include <QMap>
#include "ProcessingItem.h"
class QAction;
class QMenu;
class SelectionDialog;
class ResultDialog;
class LanguageHelper;
class Updater;
class Manager : public QObject {
Q_OBJECT
enum IconType {
IconTypeNormal, IconTypeWorking, IconTypeError, IconTypeSuccess
};
public:
explicit Manager (QObject *parent = 0);
~Manager ();
signals:
void requestRecognize (ProcessingItem item);
void requestTranslate (ProcessingItem item);
void closeSelections ();
void settingsEdited ();
private slots:
void capture ();
void repeatCapture ();
void settings ();
void close ();
void about ();
void showLast ();
void copyLastToClipboard ();
void copyLastImageToClipboard ();
void applySettings ();
void checkForUpdates ();
void processTrayAction (QSystemTrayIcon::ActivationReason reason);
void editRecognized (ProcessingItem item);
void handleSelection (ProcessingItem item);
void showResult (ProcessingItem item);
void showError (QString text);
void updateNormalIcon ();
private:
QMenu * trayContextMenu ();
void updateActionsState (bool isEnabled = true);
void changeIcon (int iconType, int timeoutMsec = 3000);
void scheduleUpdate (bool justChecked = false);
private:
QSystemTrayIcon *trayIcon_;
LanguageHelper *dictionary_;
//! Selection dialogs for each screen. Key - screen name.
QMap<QString, SelectionDialog *> selections_;
ResultDialog *resultDialog_;
Updater *updater_;
QTimer *updateTimer_;
QAction *captureAction_;
QAction *repeatCaptureAction_;
QAction *repeatAction_;
QAction *clipboardAction_;
bool useResultDialog_;
//! Used threads. For proper termination.
QList<QThread *> threads_;
QString defaultTranslationLanguage_;
QString defaultOrcLanguage_;
bool doTranslation_;
int itemProcessingCount_;
};
#endif // MANAGER_H

View File

@ -1,17 +0,0 @@
#include "ProcessingItem.h"
ProcessingItem::ProcessingItem ()
: swapLanguages_ (false) {
}
bool ProcessingItem::isValid (bool checkOnlyInput) const {
bool valid = true;
valid &= (!screenPos.isNull ());
valid &= (!source.isNull ());
valid &= (!ocrLanguage.isEmpty ());
if (!checkOnlyInput) {
valid &= (!recognized.isEmpty ());
}
return valid;
}

View File

@ -1,24 +0,0 @@
#ifndef PROCESSINGITEM_H
#define PROCESSINGITEM_H
#include <QPixmap>
struct ProcessingItem {
ProcessingItem ();
QPoint screenPos;
QPixmap source;
QString recognized;
QString translated;
QString ocrLanguage;
QString sourceLanguage;
QString translateLanguage;
Qt::KeyboardModifiers modifiers;
bool swapLanguages_;
bool isValid (bool checkOnlyInput = false) const;
};
Q_DECLARE_METATYPE (ProcessingItem)
#endif // PROCESSINGITEM_H

111
README.md
View File

@ -1,43 +1,92 @@
[![Build Status](https://travis-ci.org/OneMoreGres/ScreenTranslator.svg)](https://travis-ci.org/OneMoreGres/ScreenTranslator.svg) # Screen Translator
[![appveyor](https://img.shields.io/appveyor/ci/OneMoreGres/ScreenTranslator.svg)](https://img.shields.io/appveyor/ci/OneMoreGres/ScreenTranslator.svg)
**The project is almost abandoned. I don't have time for it and I can only fix minor issues**
Screen Translator ## Introduction
=================
Introduction
------------
This software allows you to translate any text on screen. This software allows you to translate any text on screen.
Basically it is a combination of screen capture, OCR and translation tools. Basically it is a combination of screen capture, OCR and translation tools.
Translation is currently done via online services.
Usage ## Installation
-----
1. Press capture hotkey.
2. Select region on screen.
3. Get translation of recognized text.
Features **Windows**: download archive from [github releases](https://github.com/OneMoreGres/ScreenTranslator/releases) page, extract it and run `.exe` file.
--------
* Many OCR languages (can be modified dynamically)
* Global hotkeys for main actions
* Copy last translation to clipboard
* Repeat last translation
* Show result in 2 ways (widget or tray baloon)
* Preprocess (scale) recognizeable image
* Interface languages (ru, eng)
If the app fails to start complaining about missing dlls or there are any update errors related to SSL/TLS then install or repair `vs_redist*.exe` from the release archive.
Limitations **Linux**: download `.AppImage` file from [github releases](https://github.com/OneMoreGres/ScreenTranslator/releases), make executable (`chmod +x <file>`) and run it.
-----------
* Works only on primary screen
* Can not capture some dynamic web-pages
* Not very precise OCR
* Not all functions are cross-platform (may be bugged on some systems)
Used software **OS X**: currently not supported.
-------------
* see [Qt 5](http://qt-project.org/) ### App translation
* see [Tesseract](https://code.google.com/p/tesseract-ocr/)
* see [Leptonica](http://leptonica.com/) (Tesseract dependency) To install Hebrew translation of the app (thanks to [Y-PLONI](https://github.com/Y-PLONI)),
download [this](https://github.com/OneMoreGres/ScreenTranslator/releases/download/3.3.0/screentranslator_he.qm)
file and place it into the `translations` folder next to `screen-translator.exe`.
## Setup
The app doesn't have a main window.
After start it shows only the tray icon.
If the app detects invalid settings, it will show the error message via system tray.
It will also highlight the section name in red on the left panel of the settings window.
Clicking on that section name will show a more detailed error message in the right panel (also in red).
The packages downloaded from this site do not include resources, such as recognition language packs or scripts to interact with online translation services.
To download them, open the settings window and go to the `Update` section.
In the right panel, expand the `recognizers` and `translators` sections.
Select preferred items, then right click and choose `Install/Update`.
After the progress bar reaches `100%`, the resource's state will change to `Up to Date`.
You must download at least one `recognizers` resource and one `translators` resource.
After finishing downloads, go to the `Recognition` section and update the default recognition language setting (the source to be translated).
Then go to the `Translation` section, update the default translation language setting (the language to be translated into) and enable some or all translation sevices (you may also change their order by dragging).
After that all sections in the left panel should be black.
Then click `Ok` to close settings.
## Usage
1. Run program (note that it doesn't have main window).
2. Press capture hotkey.
3. Select region on screen. Customize it if needed.
4. Get translation of recognized text.
5. Check for updates if something is not working.
## FAQ
By default resources are downloaded to the one of the user's folders.
If `Portable` setting in `General` section is checked, then resources will be downloaded to the app's folder.
Set `QTWEBENGINE_DISABLE_SANDBOX=1` environment variable when fail to start due to crash.
Answers to some frequently asked questions can be found in issues or
[wiki](https://github.com/OneMoreGres/ScreenTranslator/wiki/FAQ)
## Limitations
* Can not capture some dynamic web-pages/full screen applications
## Dependencies
* see [Qt 5](https://qt-project.org/)
* see [Tesseract](https://github.com/tesseract-ocr/tesseract/)
* see [Leptonica](https://leptonica.com/)
* several online translation services * several online translation services
## Build from source
Look at the scripts (python3) in the `share/ci` folder.
Normally, you should only edit the `config.py` file.
Build dependencies at first, then build the app.
## Attributions
* icons made by
[Smashicons](https://www.flaticon.com/authors/smashicons),
[Freepik](https://www.flaticon.com/authors/freepik),
from [Flaticon](https://www.flaticon.com/)

View File

@ -1,93 +0,0 @@
#include "Recognizer.h"
#include <tesseract/baseapi.h>
#include <QDebug>
#include <QSettings>
#include "Settings.h"
#include "ImageProcessing.h"
#include "StAssert.h"
#include "RecognizerHelper.h"
Recognizer::Recognizer (QObject *parent) :
QObject (parent),
engine_ (NULL), recognizerHelper_ (new RecognizerHelper), imageScale_ (0) {
applySettings ();
}
void Recognizer::applySettings () {
QSettings settings;
settings.beginGroup (settings_names::recogntionGroup);
recognizerHelper_->load ();
tessDataDir_ = settings.value (settings_names::tessDataPlace,
settings_values::tessDataPlace).toString ();
if (tessDataDir_.right (1) != "/") {
tessDataDir_ += "/";
}
ocrLanguage_ = settings.value (settings_names::ocrLanguage,
settings_values::ocrLanguage).toString ();
imageScale_ = settings.value (settings_names::imageScale,
settings_values::imageScale).toInt ();
initEngine (engine_, ocrLanguage_);
}
bool Recognizer::initEngine (tesseract::TessBaseAPI * &engine, const QString &language) {
if (tessDataDir_.isEmpty () || language.isEmpty ()) {
emit error (tr ("Неверные параметры для OCR"));
return false;
}
if (engine != NULL) {
delete engine;
}
engine = new tesseract::TessBaseAPI ();
int result = engine->Init (qPrintable (tessDataDir_), qPrintable (language),
tesseract::OEM_DEFAULT);
if (result != 0) {
emit error (tr ("Ошибка инициализации OCR: %1").arg (result));
delete engine;
engine = NULL;
return false;
}
return true;
}
void Recognizer::recognize (ProcessingItem item) {
if (!item.isValid (true)) {
emit recognized (item);
return;
}
bool isCustomLanguage = (item.ocrLanguage != ocrLanguage_);
tesseract::TessBaseAPI *engine = (isCustomLanguage) ? NULL : engine_;
QString language = (isCustomLanguage) ? item.ocrLanguage : ocrLanguage_;
if (engine == NULL) {
if (!initEngine (engine, language)) {
emit recognized (item);
return;
}
}
Pix *image = prepareImage (item.source.toImage (), imageScale_);
ST_ASSERT (image != NULL);
engine->SetImage (image);
char *outText = engine->GetUTF8Text ();
engine->Clear ();
cleanupImage (&image);
QString result = QString (outText).trimmed ();
delete [] outText;
if (isCustomLanguage) {
delete engine;
}
if (!result.isEmpty ()) {
item.recognized = recognizerHelper_->substitute (result, language);
}
else {
emit error (tr ("Текст не распознан."));
}
emit recognized (item);
}

View File

@ -1,41 +0,0 @@
#ifndef RECOGNIZER_H
#define RECOGNIZER_H
#include <QObject>
#include "QPixmap"
#include "ProcessingItem.h"
namespace tesseract {
class TessBaseAPI;
}
class RecognizerHelper;
class Recognizer : public QObject {
Q_OBJECT
public:
explicit Recognizer (QObject *parent = 0);
signals:
void recognized (ProcessingItem item);
void error (QString text);
public slots:
void recognize (ProcessingItem item);
void applySettings ();
private:
bool initEngine (tesseract::TessBaseAPI * &engine, const QString &language);
private:
tesseract::TessBaseAPI *engine_;
RecognizerHelper *recognizerHelper_;
QString tessDataDir_;
QString ocrLanguage_;
int imageScale_;
};
#endif // RECOGNIZER_H

View File

@ -1,88 +0,0 @@
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QSettings>
#include <QApplication>
#include "RecognizerHelper.h"
RecognizerHelper::RecognizerHelper ()
: fileName_ ("st_subs.csv") {
#ifdef Q_OS_LINUX
QDir settingDir = QFileInfo (QSettings ().fileName ()).dir ();
fileName_ = settingDir.absoluteFilePath (fileName_);
#else
fileName_ = QApplication::applicationDirPath () + QDir::separator () + fileName_;
#endif
}
void RecognizerHelper::load () {
subs_.clear ();
QFile f (fileName_);
if (!f.open (QFile::ReadOnly)) {
return;
}
QByteArray data = f.readAll ();
f.close ();
QStringList lines = QString::fromUtf8 (data).split ('\n', QString::SkipEmptyParts);
foreach (const QString &line, lines) {
QStringList parts = line.mid (1, line.size () - 2).split ("\",\""); // remove "
if (parts.size () < 3) {
continue;
}
subs_.append (Sub (parts[0], parts[1], parts[2]));
}
}
void RecognizerHelper::save () {
QFile f (fileName_);
if (!f.open (QFile::WriteOnly)) {
return;
}
foreach (const Sub &sub, subs_) {
QStringList parts = QStringList () << sub.language << sub.source << sub.target;
QString line = "\"" + parts.join ("\",\"") + "\"\n";
f.write (line.toUtf8 ());
}
f.close ();
}
QString RecognizerHelper::substitute (const QString &source, const QString &language) const {
QString result = source;
while (true) {
int bestMatchIndex = -1;
int bestMatchLen = 0;
int index = -1;
foreach (const Sub &sub, subs_) {
++index;
if (sub.language != language || !result.contains (sub.source)) {
continue;
}
int len = sub.source.length ();
if (len > bestMatchLen) {
bestMatchLen = len;
bestMatchIndex = index;
}
}
if (bestMatchIndex > -1) {
const Sub &sub = subs_.at (bestMatchIndex);
result.replace (sub.source, sub.target);
continue;
}
break;
}
return result;
}
const RecognizerHelper::Subs &RecognizerHelper::subs () const {
return subs_;
}
void RecognizerHelper::setSubs (const Subs &subs) {
subs_ = subs;
}
RecognizerHelper::Sub::Sub (const QString &language, const QString &source, const QString &target)
: language (language), source (source), target (target) {
}

View File

@ -1,33 +0,0 @@
#ifndef RECOGNIZERHELPER_H
#define RECOGNIZERHELPER_H
#include <QString>
class RecognizerHelper {
public:
struct Sub {
Sub (const QString &language = QString (), const QString &source = QString (),
const QString &target = QString ());
QString language;
QString source;
QString target;
};
typedef QList<Sub> Subs;
public:
RecognizerHelper ();
void load ();
void save ();
QString substitute (const QString &source, const QString& language) const;
const Subs &subs () const;
void setSubs (const Subs &subs);
private:
QString fileName_;
Subs subs_;
};
#endif // RECOGNIZERHELPER_H

View File

@ -1,11 +0,0 @@
<RCC>
<qresource prefix="/">
<file>translations/translation_en.qm</file>
<file>translations/translation_ru.qm</file>
<file>images/STIconBlue.png</file>
<file>images/STIconGreen.png</file>
<file>images/STIconOrange.png</file>
<file>images/STIconRed.png</file>
<file>version.json</file>
</qresource>
</RCC>

View File

@ -1,121 +0,0 @@
#include "ResultDialog.h"
#include "ui_ResultDialog.h"
#include "StAssert.h"
#include "LanguageHelper.h"
#include <QDesktopWidget>
#include <QMouseEvent>
#include <QMenu>
ResultDialog::ResultDialog (const LanguageHelper &dictionary, QWidget *parent) :
QDialog (parent),
ui (new Ui::ResultDialog),
dictionary_ (dictionary),
contextMenu_ (NULL), recognizeSubMenu_ (NULL), translateSubMenu_ (NULL),
clipboardAction_ (NULL), imageClipboardAction_ (NULL), correctAction_ (NULL) {
ui->setupUi (this);
setWindowFlags (Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint |
Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
QString styleSheet =
"#recognizeLabel, #translateLabel {"
"color: black;"
"background: qlineargradient(x1:0, y1:0, x2:1, y2:1,"
"stop:0 darkGray, stop: 0.5 lightGray, stop:1 darkGray);"
"}";
setStyleSheet (styleSheet);
installEventFilter (this);
createContextMenu ();
applySettings ();
}
ResultDialog::~ResultDialog () {
delete contextMenu_;
delete ui;
}
const ProcessingItem &ResultDialog::item () const {
return item_;
}
void ResultDialog::applySettings () {
dictionary_.updateMenu (recognizeSubMenu_, dictionary_.availableOcrLanguagesUi ());
dictionary_.updateMenu (translateSubMenu_, dictionary_.translateLanguagesUi ());
}
void ResultDialog::createContextMenu () {
contextMenu_ = new QMenu ();
recognizeSubMenu_ = contextMenu_->addMenu (tr ("Распознать другой язык"));
translateSubMenu_ = contextMenu_->addMenu (tr ("Перевести на другой язык"));
clipboardAction_ = contextMenu_->addAction (tr ("Скопировать в буфер"));
imageClipboardAction_ = contextMenu_->addAction (tr ("Скопировать рисунок в буфер"));
correctAction_ = contextMenu_->addAction (tr ("Исправить распознанный текст"));
}
bool ResultDialog::eventFilter (QObject *object, QEvent *event) {
Q_UNUSED (object);
if (event->type () == QEvent::MouseButtonPress) {
Qt::MouseButton button = static_cast<QMouseEvent *>(event)->button ();
if (button == Qt::RightButton) {
QAction *action = contextMenu_->exec (QCursor::pos ());
if (recognizeSubMenu_->findChildren<QAction *> ().contains (action)) {
ProcessingItem item = item_;
item.translated = item.recognized = QString ();
item.ocrLanguage = dictionary_.ocrUiToCode (action->text ());
emit requestRecognize (item);
}
else if (translateSubMenu_->findChildren<QAction *> ().contains (action)) {
ProcessingItem item = item_;
item.translated.clear ();
item.translateLanguage = dictionary_.translateUiToCode (action->text ());
emit requestTranslate (item);
}
else if (action == clipboardAction_) {
emit requestClipboard ();
}
else if (action == imageClipboardAction_) {
emit requestImageClipboard ();
}
else if (action == correctAction_) {
emit requestEdition (item_);
// Return because Manager calls showResult() before hide() otherwise.
return QDialog::eventFilter (object, event);
}
}
hide ();
}
else if (event->type () == QEvent::WindowDeactivate) {
hide ();
}
return QDialog::eventFilter (object, event);
}
void ResultDialog::showResult (ProcessingItem item) {
ST_ASSERT (item.isValid ());
item_ = item;
ui->sourceLabel->setPixmap (item.source);
ui->recognizeLabel->setText (item.recognized);
ui->translateLabel->setText (item.translated);
bool gotTranslation = !item.translated.isEmpty ();
ui->translateLabel->setVisible (gotTranslation);
ui->translateLine->setVisible (gotTranslation);
show ();
adjustSize ();
#ifdef Q_OS_LINUX
hide (); // buggy otherwise (on some systems)
show ();
#endif
QDesktopWidget *desktop = QApplication::desktop ();
Q_CHECK_PTR (desktop);
QPoint correction = QPoint ((width () - item.source.width ()) / 2, ui->frame->lineWidth ());
move (item.screenPos - correction);
QRect screenRect = desktop->screenGeometry (this);
int minY = screenRect.bottom () - height ();
if (y () > minY) {
move (x (), minY);
}
activateWindow ();
}

View File

@ -1,51 +0,0 @@
#ifndef RESULTDIALOG_H
#define RESULTDIALOG_H
#include <QDialog>
#include <QMenu>
#include "ProcessingItem.h"
namespace Ui {
class ResultDialog;
}
class LanguageHelper;
class ResultDialog : public QDialog {
Q_OBJECT
public:
explicit ResultDialog (const LanguageHelper &dictionary, QWidget *parent = 0);
~ResultDialog ();
signals:
void requestRecognize (ProcessingItem item);
void requestTranslate (ProcessingItem item);
void requestClipboard (); // Assume that slot will be called immediately.
void requestImageClipboard (); // Assume that slot will be called immediately.
void requestEdition (ProcessingItem item);
public:
const ProcessingItem &item () const;
bool eventFilter (QObject *object, QEvent *event);
public slots:
void showResult (ProcessingItem item);
void applySettings ();
private:
void createContextMenu ();
private:
Ui::ResultDialog *ui;
const LanguageHelper &dictionary_;
QMenu *contextMenu_;
QMenu *recognizeSubMenu_;
QMenu *translateSubMenu_;
QAction *clipboardAction_;
QAction *imageClipboardAction_;
QAction *correctAction_;
ProcessingItem item_;
};
#endif // RESULTDIALOG_H

View File

@ -1,116 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ResultDialog</class>
<widget class="QDialog" name="ResultDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>260</width>
<height>222</height>
</rect>
</property>
<property name="windowTitle">
<string>Результат</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="sourceLabel">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="Line" name="recognizeLine">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="recognizeLabel">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="Line" name="translateLine">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="translateLabel">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -1,92 +0,0 @@
#-------------------------------------------------
#
# Project created by QtCreator 2013-11-22T12:00:23
#
#-------------------------------------------------
QT += core gui network webkitwidgets
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = ScreenTranslator
TEMPLATE = app
CONFIG += c++11
win32{
INCLUDEPATH += $$PWD/../build/mingw/deps/include
LIBS += -L$$PWD/../build/mingw/deps/lib -lUser32 -lws2_32
}
linux{
QT += x11extras
INCLUDEPATH += $$PWD/../build/linux/deps/include
LIBS += -L$$PWD/../build/linux/deps/lib -lX11 -Wl,-rpath,.
}
LIBS += -ltesseract -llept
include(3rd-party/qtsingleapplication/qtsingleapplication.pri)
SOURCES += main.cpp\
Manager.cpp \
SettingsEditor.cpp \
SelectionDialog.cpp \
GlobalActionHelper.cpp \
Recognizer.cpp \
ResultDialog.cpp \
ProcessingItem.cpp \
ImageProcessing.cpp \
LanguageHelper.cpp \
WebTranslator.cpp \
WebTranslatorProxy.cpp \
TranslatorHelper.cpp \
RecognizerHelper.cpp \
Utils.cpp \
Updater.cpp
HEADERS += \
Manager.h \
SettingsEditor.h \
SelectionDialog.h \
GlobalActionHelper.h \
Recognizer.h \
Settings.h \
ProcessingItem.h \
ResultDialog.h \
ImageProcessing.h \
LanguageHelper.h \
WebTranslator.h \
WebTranslatorProxy.h \
StAssert.h \
TranslatorHelper.h \
RecognizerHelper.h \
Utils.h \
Updater.h
FORMS += \
SettingsEditor.ui \
SelectionDialog.ui \
ResultDialog.ui
RESOURCES += \
Recources.qrc
TRANSLATIONS += \
translations/translation_en.ts \
translations/translation_ru.ts
OTHER_FILES += \
images/* \
translators/* \
scripts/* \
distr/* \
version.json \
README.md \
uncrustify.cfg\
.travis.yml \
TODO.md
QMAKE_TARGET_COMPANY = Gres
QMAKE_TARGET_PRODUCT = Screen Translator
QMAKE_TARGET_COPYRIGHT = Copyright (c) Gres
VERSION = 2.0.0.0
RC_ICONS = images/icon.ico

View File

@ -1,122 +0,0 @@
#include "SelectionDialog.h"
#include "ui_SelectionDialog.h"
#include "LanguageHelper.h"
#include "StAssert.h"
#include <QMouseEvent>
#include <QPainter>
#include <QDebug>
#include <QMenu>
SelectionDialog::SelectionDialog (const LanguageHelper &dictionary, QWidget *parent) :
QDialog (parent),
ui (new Ui::SelectionDialog), dictionary_ (dictionary),
languageMenu_ (new QMenu), swapLanguagesAction_ (NULL) {
ui->setupUi (this);
setWindowFlags (Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint |
Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
ui->label->setAutoFillBackground (false);
ui->label->installEventFilter (this);
applySettings ();
}
SelectionDialog::~SelectionDialog () {
delete languageMenu_;
delete ui;
}
void SelectionDialog::applySettings () {
dictionary_.updateMenu (languageMenu_, dictionary_.availableOcrLanguagesUi ());
if (!languageMenu_->isEmpty ()) {
swapLanguagesAction_ = languageMenu_->addAction (tr ("Поменять язык текста и перевода"));
}
}
bool SelectionDialog::eventFilter (QObject *object, QEvent *event) {
if (object != ui->label) {
return QDialog::eventFilter (object, event);
}
if (event->type () == QEvent::Show) {
startSelectPos_ = currentSelectPos_ = QPoint ();
}
else if (event->type () == QEvent::MouseButtonPress) {
QMouseEvent *mouseEvent = static_cast <QMouseEvent *> (event);
if ((mouseEvent->button () == Qt::LeftButton ||
mouseEvent->button () == Qt::RightButton) && startSelectPos_.isNull ()) {
startSelectPos_ = mouseEvent->pos ();
}
}
else if (event->type () == QEvent::MouseMove) {
QMouseEvent *mouseEvent = static_cast <QMouseEvent *> (event);
if ((mouseEvent->buttons () & Qt::LeftButton ||
mouseEvent->buttons () & Qt::RightButton) && !startSelectPos_.isNull ()) {
currentSelectPos_ = mouseEvent->pos ();
ui->label->repaint ();
}
}
else if (event->type () == QEvent::Paint) {
QRect selection = QRect (startSelectPos_, currentSelectPos_).normalized ();
if (selection.isValid ()) {
QPainter painter (ui->label);
painter.setPen (Qt::red);
painter.drawRect (selection);
}
}
else if (event->type () == QEvent::MouseButtonRelease) {
QMouseEvent *mouseEvent = static_cast <QMouseEvent *> (event);
if (mouseEvent->button () == Qt::LeftButton ||
mouseEvent->button () == Qt::RightButton) {
if (startSelectPos_.isNull () || currentPixmap_.isNull ()) {
return QDialog::eventFilter (object, event);
}
QPoint endPos = mouseEvent->pos ();
QRect selection = QRect (startSelectPos_, endPos).normalized ();
startSelectPos_ = currentSelectPos_ = QPoint ();
QPixmap selectedPixmap = currentPixmap_.copy (selection);
if (selectedPixmap.width () < 3 || selectedPixmap.height () < 3) {
reject ();
return QDialog::eventFilter (object, event);
}
ProcessingItem item;
item.source = selectedPixmap;
item.screenPos = pos () + selection.topLeft ();
item.modifiers = mouseEvent->modifiers ();
if (mouseEvent->button () == Qt::RightButton &&
!languageMenu_->children ().isEmpty ()) {
QAction *action = languageMenu_->exec (QCursor::pos ());
if (action == NULL) {
reject ();
return QDialog::eventFilter (object, event);
}
if (action == swapLanguagesAction_) {
item.swapLanguages_ = true;
}
else {
item.ocrLanguage = dictionary_.ocrUiToCode (action->text ());
ST_ASSERT (!item.ocrLanguage.isEmpty ());
item.sourceLanguage = dictionary_.ocrToTranslateCodes (item.ocrLanguage);
ST_ASSERT (!item.sourceLanguage.isEmpty ());
}
}
emit selected (item);
}
}
return QDialog::eventFilter (object, event);
}
void SelectionDialog::setPixmap (QPixmap pixmap, const QRect &showGeometry) {
ST_ASSERT (!pixmap.isNull ());
ST_ASSERT (!showGeometry.isEmpty ());
currentPixmap_ = pixmap;
QPalette palette = this->palette ();
palette.setBrush (this->backgroundRole (), pixmap);
this->setPalette (palette);
this->setGeometry (showGeometry);
show ();
activateWindow ();
}

View File

@ -1,43 +0,0 @@
#ifndef SELECTIONDIALOG_H
#define SELECTIONDIALOG_H
#include <QDialog>
#include <QPixmap>
#include <QMenu>
#include "ProcessingItem.h"
namespace Ui {
class SelectionDialog;
}
class LanguageHelper;
class SelectionDialog : public QDialog {
Q_OBJECT
public:
explicit SelectionDialog (const LanguageHelper &dictionary, QWidget *parent = 0);
~SelectionDialog ();
bool eventFilter (QObject *object, QEvent *event);
signals:
void selected (ProcessingItem pixmap);
void nothingSelected ();
public slots:
//! Show pixmap with given geometry.
void setPixmap (QPixmap pixmap, const QRect &showGeometry);
void applySettings ();
private:
Ui::SelectionDialog *ui;
const LanguageHelper &dictionary_;
QPoint startSelectPos_;
QPoint currentSelectPos_;
QPixmap currentPixmap_;
QMenu *languageMenu_;
QAction *swapLanguagesAction_;
};
#endif // SELECTIONDIALOG_H

View File

@ -1,43 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SelectionDialog</class>
<widget class="QDialog" name="SelectionDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="cursor">
<cursorShape>CrossCursor</cursorShape>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -1,81 +0,0 @@
#ifndef SETTINGS_H
#define SETTINGS_H
#include <QString>
namespace settings_names {
//! UI
const QString guiGroup = "GUI";
const QString geometry = "geometry";
const QString captureHotkey = "captureHotkey";
const QString repeatCaptureHotkey = "repeatCaptureHotkey";
const QString repeatHotkey = "repeatHotkey";
const QString clipboardHotkey = "clipboardHotkey";
const QString resultShowType = "resultShowType";
const QString proxyType = "proxyType";
const QString proxyHostName = "proxyHostName";
const QString proxyPort = "proxyPort";
const QString proxyUser = "proxyUser";
const QString proxyPassword = "proxyPassword";
const QString proxySavePassword = "proxySavePassword";
const QString autoUpdateType = "autoUpdateType";
const QString lastUpdateCheck = "lastUpdateCheck";
//! Recognition
const QString recogntionGroup = "Recognition";
const QString tessDataPlace = "tessdata_dir";
const QString ocrLanguage = "language";
const QString imageScale = "image_scale";
//! Translation
const QString translationGroup = "Translation";
const QString doTranslation = "doTranslation";
const QString ignoreSslErrors = "ignoreSslErrors";
const QString forceRotateTranslators = "forceRotateTranslators";
const QString sourceLanguage = "source_language";
const QString translationLanguage = "translation_language";
const QString translationTimeout = "translation_timeout";
const QString translationDebugMode = "translation_debug";
const QString translators = "translators";
}
namespace settings_values {
const QString appName = "ScreenTranslator";
const QString companyName = "Gres";
//! UI
const QString captureHotkey = "Ctrl+Alt+Z";
const QString repeatCaptureHotkey = "Ctrl+Alt+S";
const QString repeatHotkey = "Ctrl+Alt+X";
const QString clipboardHotkey = "Ctrl+Alt+C";
const QString resultShowType = "1";//dialog
const int proxyType = 0;
const QString proxyHostName = "";
const int proxyPort = 8080;
const QString proxyUser = "";
const QString proxyPassword = "";
const bool proxySavePassword = false;
const int autoUpdateType = 0; //Never
const QString lastUpdateCheck = "";
//! Recognition
#if defined(Q_OS_LINUX)
const QString tessDataPlace = "/usr/share/tesseract-ocr/";
#else
const QString tessDataPlace = "./";
#endif
const QString ocrLanguage = "eng";
const int imageScale = 5;
//! Translation
const bool doTranslation = true;
const bool ignoreSslErrors = false;
const bool forceRotateTranslators = false;
const QString sourceLanguage = "auto";
const QString translationLanguage = "ru";
const int translationTimeout = 15; // secs
const bool translationDebugMode = false;
const QString translators = "";
}
#endif // SETTINGS_H

View File

@ -1,292 +0,0 @@
#include "SettingsEditor.h"
#include "ui_SettingsEditor.h"
#include "LanguageHelper.h"
#include "TranslatorHelper.h"
#include "RecognizerHelper.h"
#include "StAssert.h"
#include "Utils.h"
#include <QSettings>
#include <QFileDialog>
#include <QDir>
#include <QRegExpValidator>
#include <QNetworkProxy>
#include "Settings.h"
SettingsEditor::SettingsEditor (const LanguageHelper &dictionary, QWidget *parent) :
QDialog (parent),
ui (new Ui::SettingsEditor), translatorHelper_ (new TranslatorHelper),
recognizerHelper_ (new RecognizerHelper), dictionary_ (dictionary),
buttonGroup_ (new QButtonGroup (this)) {
ui->setupUi (this);
buttonGroup_->addButton (ui->trayRadio, 0);
buttonGroup_->addButton (ui->dialogRadio, 1);
connect (ui->updateButton, SIGNAL (clicked (bool)), SIGNAL (updateCheckRequested ()));
QStringList updateTypes = QStringList () << tr ("Никогда") << tr ("Ежедневно")
<< tr ("Еженедельно") << tr ("Ежемесячно");
ui->updateCombo->addItems (updateTypes);
connect (ui->tessdataButton, SIGNAL (clicked ()), SLOT (openTessdataDialog ()));
connect (ui->tessdataEdit, SIGNAL (textChanged (const QString &)),
SLOT (initOcrLangCombo (const QString &)));
connect (ui->recognizerFixTable, SIGNAL (itemChanged (QTableWidgetItem *)),
SLOT (recognizerFixTableItemChanged (QTableWidgetItem *)));
ui->translateLangCombo->addItems (dictionary_.translateLanguagesUi ());
typedef QNetworkProxy::ProxyType ProxyType;
QMap<ProxyType, QString> proxyTypeNames;
proxyTypeNames.insert (QNetworkProxy::NoProxy, tr ("Нет"));
proxyTypeNames.insert (QNetworkProxy::Socks5Proxy, tr ("SOCKS 5"));
proxyTypeNames.insert (QNetworkProxy::HttpProxy, tr ("HTTP"));
QList<int> proxyOrder = proxyTypeOrder ();
foreach (int type, proxyOrder) {
ui->proxyTypeCombo->addItem (proxyTypeNames.value (QNetworkProxy::ProxyType (type)));
}
QRegExp urlRegexp (R"(^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$)");
ui->proxyHostEdit->setValidator (new QRegExpValidator (urlRegexp, ui->proxyHostEdit));
ui->proxyPassEdit->setEchoMode (QLineEdit::PasswordEchoOnEdit);
loadSettings ();
loadState ();
}
SettingsEditor::~SettingsEditor () {
saveState ();
delete recognizerHelper_;
delete translatorHelper_;
delete ui;
}
void SettingsEditor::done (int result) {
if (result == QDialog::Accepted) {
saveSettings ();
emit settingsEdited ();
}
QDialog::done (result);
}
void SettingsEditor::saveSettings () const {
using namespace settings_names;
QSettings settings;
settings.beginGroup (guiGroup);
settings.setValue (captureHotkey, ui->captureEdit->keySequence ().toString ());
settings.setValue (repeatCaptureHotkey, ui->repeatCaptureEdit->keySequence ().toString ());
settings.setValue (repeatHotkey, ui->repeatEdit->keySequence ().toString ());
settings.setValue (clipboardHotkey, ui->clipboardEdit->keySequence ().toString ());
settings.setValue (resultShowType, buttonGroup_->checkedId ());
settings.setValue (proxyType, ui->proxyTypeCombo->currentIndex ());
settings.setValue (proxyHostName, ui->proxyHostEdit->text ());
settings.setValue (proxyPort, ui->proxyPortSpin->value ());
settings.setValue (proxyUser, ui->proxyUserEdit->text ());
if (ui->proxySaveCheck->isChecked ()) {
settings.setValue (proxyPassword, encode (ui->proxyPassEdit->text ()));
}
else {
settings.remove (proxyPassword);
QNetworkProxy proxy = QNetworkProxy::applicationProxy ();
proxy.setPassword (ui->proxyPassEdit->text ());
QNetworkProxy::setApplicationProxy (proxy);
}
settings.setValue (proxySavePassword, ui->proxySaveCheck->isChecked ());
settings.setValue (autoUpdateType, ui->updateCombo->currentIndex ());
settings.endGroup ();
settings.beginGroup (recogntionGroup);
settings.setValue (tessDataPlace, ui->tessdataEdit->text ());
QString ocrLanguageVal = dictionary_.ocrUiToCode (ui->ocrLangCombo->currentText ());
settings.setValue (ocrLanguage, ocrLanguageVal);
settings.setValue (imageScale, ui->imageScaleSpin->value ());
{ //Recognizer substitutions
RecognizerHelper::Subs subs;
QTableWidget *t = ui->recognizerFixTable; // Shortcut
for (int i = 0, end = t->rowCount () - 1; i < end; ++i) {
QComboBox *combo = static_cast<QComboBox *>(t->cellWidget (i, SubsColLanguage));
QString langUi = combo->currentText ();
RecognizerHelper::Sub sub;
sub.language = dictionary_.ocrUiToCode (langUi);
#define GET(COL) (t->item (i, COL) ? t->item (i, COL)->text () : QString ())
sub.source = GET (SubsColSource);
sub.target = GET (SubsColTarget);
#undef GET
if (langUi.isEmpty () || sub.language == langUi || sub.source.isEmpty ()) {
continue;
}
subs.append (sub);
}
recognizerHelper_->setSubs (subs);
recognizerHelper_->save ();
}
settings.endGroup ();
settings.beginGroup (translationGroup);
settings.setValue (doTranslation, ui->doTranslationCheck->isChecked ());
settings.setValue (ignoreSslErrors, ui->ignoreSslCheck->isChecked ());
settings.setValue (forceRotateTranslators, ui->forceRotateCheck->isChecked ());
settings.setValue (translationDebugMode, ui->translatorDebugCheck->isChecked ());
QString trLanguage = dictionary_.translateUiToCode (ui->translateLangCombo->currentText ());
settings.setValue (translationLanguage, trLanguage);
QString sourceLanguageVal = dictionary_.ocrToTranslateCodes (ocrLanguage);
settings.setValue (sourceLanguage, sourceLanguageVal);
settings.setValue (translationTimeout, ui->translateTimeoutSpin->value ());
{//Translators
QStringList enabled;
for (int i = 0, end = ui->translatorList->count (); i < end; ++i) {
QListWidgetItem *item = ui->translatorList->item (i);
if (item->checkState () == Qt::Checked) {
enabled << item->text ();
}
}
translatorHelper_->setEnabledTranslators (enabled);
}
settings.endGroup ();
}
void SettingsEditor::openTessdataDialog () {
QString path = QFileDialog::getExistingDirectory (this, tr ("Путь к tessdata"));
if (path.isEmpty ()) {
return;
}
QDir dir (path);
if (dir.dirName () == QString ("tessdata")) {
dir.cdUp ();
}
ui->tessdataEdit->setText (dir.path ());
}
void SettingsEditor::loadSettings () {
#define GET(FIELD) settings.value (settings_names::FIELD, settings_values::FIELD)
QSettings settings;
settings.beginGroup (settings_names::guiGroup);
ui->captureEdit->setKeySequence (QKeySequence (GET (captureHotkey).toString ()));
ui->repeatCaptureEdit->setKeySequence (QKeySequence (GET (repeatCaptureHotkey).toString ()));
ui->repeatEdit->setKeySequence (QKeySequence (GET (repeatHotkey).toString ()));
ui->clipboardEdit->setKeySequence (QKeySequence (GET (clipboardHotkey).toString ()));
QAbstractButton *button = buttonGroup_->button (GET (resultShowType).toInt ());
Q_CHECK_PTR (button);
button->setChecked (true);
ui->proxyTypeCombo->setCurrentIndex (GET (proxyType).toInt ());
ui->proxyHostEdit->setText (GET (proxyHostName).toString ());
ui->proxyPortSpin->setValue (GET (proxyPort).toInt ());
ui->proxyUserEdit->setText (GET (proxyUser).toString ());
ui->proxySaveCheck->setChecked (GET (proxySavePassword).toBool ());
if (ui->proxySaveCheck->isChecked ()) {
ui->proxyPassEdit->setText (encode (GET (proxyPassword).toString ()));
}
else {
ui->proxyPassEdit->setText (QNetworkProxy::applicationProxy ().password ());
}
ui->updateCombo->setCurrentIndex (GET (autoUpdateType).toInt ());
settings.endGroup ();
settings.beginGroup (settings_names::recogntionGroup);
ui->tessdataEdit->setText (GET (tessDataPlace).toString ());
QString ocrLanguage = dictionary_.ocrCodeToUi (GET (ocrLanguage).toString ());
ui->ocrLangCombo->setCurrentText (ocrLanguage);
ui->imageScaleSpin->setValue (GET (imageScale).toInt ());
{//Recognizer substitutions
recognizerHelper_->load ();
RecognizerHelper::Subs subs = recognizerHelper_->subs ();
ui->recognizerFixTable->setRowCount (subs.size ());
int row = 0;
foreach (const RecognizerHelper::Sub & sub, subs) {
if (!initSubsTableRow (row, sub.language)) {
continue;
}
ui->recognizerFixTable->setItem (row, SubsColSource, new QTableWidgetItem (sub.source));
ui->recognizerFixTable->setItem (row, SubsColTarget, new QTableWidgetItem (sub.target));
++row;
}
ui->recognizerFixTable->setRowCount (row + 1);
initSubsTableRow (row);
ui->recognizerFixTable->resizeColumnsToContents ();
}
settings.endGroup ();
settings.beginGroup (settings_names::translationGroup);
ui->doTranslationCheck->setChecked (GET (doTranslation).toBool ());
ui->ignoreSslCheck->setChecked (GET (ignoreSslErrors).toBool ());
ui->forceRotateCheck->setChecked (GET (forceRotateTranslators).toBool ());
ui->translatorDebugCheck->setChecked (GET (translationDebugMode).toBool ());
QString trLanguage = dictionary_.translateCodeToUi (GET (translationLanguage).toString ());
ui->translateLangCombo->setCurrentText (trLanguage);
ui->translateTimeoutSpin->setValue (GET (translationTimeout).toInt ());
{// Translators
QStringList enabled;
ui->translatorList->addItems (translatorHelper_->possibleTranslators (enabled));
for (int i = 0, end = ui->translatorList->count (); i < end; ++i) {
QListWidgetItem *item = ui->translatorList->item (i);
Qt::CheckState state = enabled.contains (item->text ()) ? Qt::Checked : Qt::Unchecked;
item->setCheckState (state);
}
}
settings.endGroup ();
#undef GET
}
bool SettingsEditor::initSubsTableRow (int row, const QString &languageCode) {
QString lang = dictionary_.ocrCodeToUi (languageCode);
if (!languageCode.isEmpty () && lang == languageCode) {
return false;
}
QComboBox *langCombo = new QComboBox (ui->recognizerFixTable);
langCombo->setModel (ui->ocrLangCombo->model ());
if (!languageCode.isEmpty ()) {
langCombo->setCurrentText (lang);
}
else {
langCombo->setCurrentIndex (ui->ocrLangCombo->currentIndex ());
}
ui->recognizerFixTable->setCellWidget (row, SubsColLanguage, langCombo);
return true;
}
void SettingsEditor::saveState () const {
QSettings settings;
settings.beginGroup (settings_names::guiGroup);
settings.setValue (objectName () + "_" + settings_names::geometry, saveGeometry ());
}
void SettingsEditor::loadState () {
QSettings settings;
settings.beginGroup (settings_names::guiGroup);
restoreGeometry (settings.value (objectName () + "_" + settings_names::geometry).toByteArray ());
}
void SettingsEditor::initOcrLangCombo (const QString &path) {
ui->ocrLangCombo->clear ();
ui->ocrLangCombo->addItems (dictionary_.availableOcrLanguagesUi (path));
}
void SettingsEditor::recognizerFixTableItemChanged (QTableWidgetItem *item) {
ST_ASSERT (item->column () < 3);
int row = item->row ();
QTableWidget *t = ui->recognizerFixTable;
#define CHECK(COL) (!t->item (row, COL) || t->item (row, COL)->text ().isEmpty ())
bool isRowEmpty = CHECK (SubsColSource) && CHECK (SubsColTarget);
#undef CHECK
int lastRow = ui->recognizerFixTable->rowCount () - 1;
if (isRowEmpty && row != lastRow) {
ui->recognizerFixTable->removeRow (row);
}
else if (!isRowEmpty && row == lastRow) {
int newRow = lastRow + 1;
ui->recognizerFixTable->insertRow (newRow);
initSubsTableRow (newRow);
}
}

View File

@ -1,54 +0,0 @@
#ifndef SETTINGSEDITOR_H
#define SETTINGSEDITOR_H
#include <QDialog>
#include <QButtonGroup>
#include <QMap>
class QTableWidgetItem;
namespace Ui {
class SettingsEditor;
}
class LanguageHelper;
class TranslatorHelper;
class RecognizerHelper;
class SettingsEditor : public QDialog {
Q_OBJECT
enum SubsCol {
SubsColLanguage = 0, SubsColSource, SubsColTarget
};
public:
explicit SettingsEditor (const LanguageHelper &dictionary, QWidget *parent = 0);
~SettingsEditor ();
signals:
void settingsEdited ();
void updateCheckRequested ();
public slots:
void done (int result);
private slots:
void saveSettings () const;
void openTessdataDialog ();
void initOcrLangCombo (const QString &path);
void recognizerFixTableItemChanged (QTableWidgetItem *item);
private:
void loadSettings ();
void saveState () const;
void loadState ();
bool initSubsTableRow (int row, const QString &languageCode = QString ());
private:
Ui::SettingsEditor *ui;
TranslatorHelper *translatorHelper_;
RecognizerHelper *recognizerHelper_;
const LanguageHelper &dictionary_;
QButtonGroup *buttonGroup_;
};
#endif // SETTINGSEDITOR_H

View File

@ -1,530 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SettingsEditor</class>
<widget class="QDialog" name="SettingsEditor">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>553</width>
<height>483</height>
</rect>
</property>
<property name="windowTitle">
<string>Настройки</string>
</property>
<layout class="QGridLayout" name="gridLayout_6">
<item row="1" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="commonTab">
<attribute name="title">
<string>Общее</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_8">
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Горячие клавиши</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Сочетание клавиш для перехода в режим захвата.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Захватить</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QKeySequenceEdit" name="captureEdit"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_8">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Сочетание клавиш для перехода в режим захвата, но с использованием последнего использованного, а не текущего, изображения.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Захватить повторно</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QKeySequenceEdit" name="repeatCaptureEdit"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Сочетание клавиш для повторного отображения последнего результата.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Показать</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QKeySequenceEdit" name="repeatEdit"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_7">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Сочетание клавиш для копирования последнего результата в буфер обмена.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Скопировать</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QKeySequenceEdit" name="clipboardEdit"/>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Прокси</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Тип:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="proxyTypeCombo"/>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Пользователь:</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLineEdit" name="proxyUserEdit"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Адрес:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="proxyHostEdit"/>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Пароль:</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLineEdit" name="proxyPassEdit"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Порт:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="proxyPortSpin">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>65535</number>
</property>
</widget>
</item>
<item row="2" column="2" colspan="2">
<widget class="QCheckBox" name="proxySaveCheck">
<property name="text">
<string>Сохранять пароль (небезопасно)</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QGroupBox" name="resultGroup">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Вывод результата</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QRadioButton" name="trayRadio">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Трей</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QRadioButton" name="dialogRadio">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Окно</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Обновление</string>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>Проверять обновления:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="updateCombo"/>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="updateButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Проверить</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item row="3" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>270</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="recognizeTab">
<attribute name="title">
<string>Распознавание</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Необходимо для распознавания.&lt;/p&gt;&lt;p&gt;Скачивается отсюда: &lt;a href=&quot;https://github.com/tesseract-ocr/tessdata&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#7593bc;&quot;&gt;https://github.com/tesseract-ocr/tessdata&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;quot;./&amp;quot; означает, что папка &amp;quot;tessdata&amp;quot; находится в одной директории с исполняемым файлом программы.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Путь к tessdata</string>
</property>
<property name="buddy">
<cstring>tessdataEdit</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="tessdataEdit"/>
</item>
<item row="0" column="2">
<widget class="QToolButton" name="tessdataButton">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Заполняется на основании содержания tessdata&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Язык распознавания</string>
</property>
<property name="buddy">
<cstring>ocrLangCombo</cstring>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QComboBox" name="ocrLangCombo"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Масштабирование изображения для улучшения распознания. Больше - лучше (до определенных пределов), но медленнее и потребляет больше памяти.&lt;/p&gt;&lt;p&gt;Рекомендуемые значения от 5 до 10.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Увеличение масштаба</string>
</property>
<property name="buddy">
<cstring>imageScaleSpin</cstring>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QSpinBox" name="imageScaleSpin"/>
</item>
<item row="3" column="0" colspan="3">
<widget class="QLabel" name="label_11">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Символы, регулярно распознаваемые с ошибками. При обнаружении будут заменены на указанные.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Исправления:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="4" column="0" colspan="3">
<widget class="QTableWidget" name="recognizerFixTable">
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<column>
<property name="text">
<string>Язык</string>
</property>
</column>
<column>
<property name="text">
<string>Исходный текст</string>
</property>
</column>
<column>
<property name="text">
<string>Исправление</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="translateTab">
<attribute name="title">
<string>Перевод</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_7">
<item row="0" column="0">
<widget class="QCheckBox" name="doTranslationCheck">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Необходимо ли переводить (вкл) распознанный текст.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Переводить текст</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_9">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Максимальное время, которое может быть затрачено на перевод, чтобы он не считался &amp;quot;зависшим&amp;quot;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Максимальное время перевода:</string>
</property>
</widget>
</item>
<item row="3" column="1" colspan="2">
<widget class="QSpinBox" name="translateTimeoutSpin">
<property name="suffix">
<string> сек.</string>
</property>
</widget>
</item>
<item row="4" column="1" colspan="2">
<widget class="QComboBox" name="translateLangCombo"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_6">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Язык, на который осуществляется перевод.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Язык результата:</string>
</property>
<property name="buddy">
<cstring>translateLangCombo</cstring>
</property>
</widget>
</item>
<item row="5" column="0" colspan="3">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Переводчики:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="6" column="0" colspan="3">
<widget class="QListWidget" name="translatorList">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Отображены в порядке убывания приоритета.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::InternalMove</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::MoveAction</enum>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QCheckBox" name="translatorDebugCheck">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Отображает окно переводчика. Следует использовать только для разработки переводчиков.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Режим отладки</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="ignoreSslCheck">
<property name="text">
<string>Игнорировать ошибки SSL</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QCheckBox" name="forceRotateCheck">
<property name="text">
<string>Принудительно менять переводчики</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>tabWidget</tabstop>
<tabstop>captureEdit</tabstop>
<tabstop>repeatCaptureEdit</tabstop>
<tabstop>repeatEdit</tabstop>
<tabstop>clipboardEdit</tabstop>
<tabstop>trayRadio</tabstop>
<tabstop>dialogRadio</tabstop>
<tabstop>proxyTypeCombo</tabstop>
<tabstop>proxyHostEdit</tabstop>
<tabstop>proxyPortSpin</tabstop>
<tabstop>proxyUserEdit</tabstop>
<tabstop>proxyPassEdit</tabstop>
<tabstop>proxySaveCheck</tabstop>
<tabstop>tessdataEdit</tabstop>
<tabstop>tessdataButton</tabstop>
<tabstop>ocrLangCombo</tabstop>
<tabstop>imageScaleSpin</tabstop>
<tabstop>recognizerFixTable</tabstop>
<tabstop>doTranslationCheck</tabstop>
<tabstop>translatorDebugCheck</tabstop>
<tabstop>translateTimeoutSpin</tabstop>
<tabstop>translateLangCombo</tabstop>
<tabstop>translatorList</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>SettingsEditor</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>256</x>
<y>447</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>SettingsEditor</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>324</x>
<y>447</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -1,15 +0,0 @@
#ifndef ST_ASSERT_H
#define ST_ASSERT_H
#include <assert.h>
#if !defined(ST_ASSERT)
# if defined(ST_NO_ASSERT)
# define ST_ASSERT(CONDITION)
# else
# define ST_ASSERT(CONDITION) assert (CONDITION)
# endif
#endif
#endif // ST_ASSERT_H

View File

@ -1,82 +0,0 @@
#include <QSettings>
#include <QDir>
#include <QFile>
#include <QApplication>
#include "TranslatorHelper.h"
#include "Settings.h"
TranslatorHelper::TranslatorHelper ()
: translatorsDir_ ("translators"), currentIndex_ (0), triesLeft_ (0) {
translatorsDir_ = QApplication::applicationDirPath () + QDir::separator () + translatorsDir_;
}
void TranslatorHelper::setEnabledTranslators (const QStringList &enabled) const {
QSettings settings;
settings.beginGroup (settings_names::translationGroup);
settings.setValue (settings_names::translators, enabled.join ("|"));
}
QStringList TranslatorHelper::possibleTranslators (QStringList &enabled) const {
#define GET(FIELD) settings.value (settings_names::FIELD, settings_values::FIELD)
QSettings settings;
settings.beginGroup (settings_names::translationGroup);
QStringList exist = QDir (translatorsDir_).entryList (QStringList () << "*.js", QDir::Files);
QStringList saved = GET (translators).toString ().split ("|", QString::SkipEmptyParts);
QStringList on, off;
std::copy_if (saved.begin (), saved.end (), std::back_inserter (on), [&](const QString &i) {
return exist.contains (i);
});
on = on.isEmpty () ? exist : on;
std::copy_if (exist.begin (), exist.end (), std::back_inserter (off), [&](const QString &i) {
return !on.contains (i);
});
enabled = on;
return (on + off);
#undef GET
}
QStringList TranslatorHelper::enabledTranslatorScripts () const {
QStringList enabled;
possibleTranslators (enabled);
QStringList scripts;
foreach (const QString &name, enabled) {
QFile f (translatorsDir_ + QDir::separator () + name);
if (f.open (QFile::ReadOnly)) {
QString script = QString::fromUtf8 (f.readAll ());
if (!script.isEmpty ()) {
scripts << script;
}
}
}
return scripts;
}
void TranslatorHelper::loadScripts () {
scripts_ = enabledTranslatorScripts ();
}
void TranslatorHelper::newItem (bool forceRotate) {
triesLeft_ = scripts_.size ();
currentIndex_ = forceRotate ? currentIndex_ + 1 : 0;
}
QString TranslatorHelper::nextScript () {
--triesLeft_;
if (++currentIndex_ >= scripts_.size ()) {
currentIndex_ = 0;
}
return currentScript ();
}
QString TranslatorHelper::currentScript () const {
return (triesLeft_ > 0 ? scripts_.at (currentIndex_) : QString ());
}
bool TranslatorHelper::gotScripts () const {
return !scripts_.isEmpty ();
}

View File

@ -1,28 +0,0 @@
#ifndef TRANSLATORHELPER_H
#define TRANSLATORHELPER_H
#include <QStringList>
class TranslatorHelper {
public:
TranslatorHelper ();
QStringList possibleTranslators (QStringList &enabled) const;
QStringList enabledTranslatorScripts () const;
void setEnabledTranslators (const QStringList &enabled) const;
void loadScripts ();
void newItem (bool forceRotate);
QString nextScript ();
QString currentScript () const;
bool gotScripts () const;
private:
QString translatorsDir_;
QStringList scripts_;
int currentIndex_;
int triesLeft_;
};
#endif // TRANSLATORHELPER_H

View File

@ -1,264 +0,0 @@
#include <QDir>
#include <QFile>
#include <QJsonDocument>
#include <QJsonArray>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QMessageBox>
#include <QApplication>
#include "Updater.h"
#include "StAssert.h"
namespace {
#define FIELD(NAME) const QString _ ## NAME = #NAME
FIELD (Application);
FIELD (name);
FIELD (version);
FIELD (compatibleVersion);
FIELD (built_in);
FIELD (versionString);
FIELD (permissions);
FIELD (url);
FIELD (path);
#undef FIELD
#if defined(Q_OS_WIN)
const QString _platform = "_win";
#elif defined(Q_OS_LINUX)
const QString _platform = "_linux";
#endif
QString versionField (const QJsonObject &component, const QString &field) {
return component.contains (field + _platform)
? component[field + _platform].toVariant ().toString ()
: component[field].toVariant ().toString ();
}
QFileInfo fileDir (const QString &fileName) {
return QFileInfo (fileName).absolutePath ();
}
}
Updater::Updater (QObject *parent)
: QObject (parent),
network_ (new QNetworkAccessManager (this)),
componentsUpdating_ (0) {
updatesFileName_ = QApplication::applicationDirPath () + QDir::separator () + "updates.json";
backupSuffix_ = "_backup";
connect (network_, SIGNAL (finished (QNetworkReply *)),
SLOT (replyFinished (QNetworkReply *)));
getCurrentVersion ();
updateCurrentVersion ();
}
QDateTime Updater::nextCheckTime (const QDateTime &lastCheckTime, int updateType) const {
QDateTime nextTime;
switch (updateType) {
case UpdateTypeDaily:
nextTime = lastCheckTime.addDays (1);
break;
case UpdateTypeWeekly:
nextTime = lastCheckTime.addDays (7);
break;
case UpdateTypeMonthly:
nextTime = lastCheckTime.addDays (30);
break;
case UpdateTypeNever:
default:
return QDateTime ();
}
if (nextTime < QDateTime::currentDateTime ()) {
return QDateTime::currentDateTime ().addSecs (5);
}
return nextTime;
}
void Updater::getCurrentVersion () {
QFile f (":/version.json");
if (f.open (QFile::ReadOnly)) {
currentVersion_ = QJsonDocument::fromJson (f.readAll ()).object ();
f.close ();
}
else {
emit error (tr ("Ошибка определения текущей версии. Обновление недоступно."));
}
}
void Updater::updateCurrentVersion () {
QFile f (updatesFileName_);
if (!f.open (QFile::ReadOnly)) {
return;
}
QJsonObject updated = QJsonDocument::fromJson (f.readAll ()).object ();
f.close ();
foreach (const QString &component, updated.keys ()) {
QJsonObject current = currentVersion_[component].toObject ();
int updatedVersion = updated[component].toInt ();
if (current[_built_in].toBool () || current[_version].toInt () >= updatedVersion) {
continue;
}
current[_version] = updatedVersion;
currentVersion_[component] = current;
}
}
QString Updater::currentAppVersion () const {
return currentVersion_[_Application].toObject ()[_versionString].toString ();
}
void Updater::checkForUpdates () {
getAvailableVersion ();
}
void Updater::getAvailableVersion () {
QNetworkRequest request (versionField (currentVersion_, _url));
request.setAttribute (QNetworkRequest::User, _version);
network_->get (request);
}
void Updater::replyFinished (QNetworkReply *reply) {
if (reply->error () != QNetworkReply::NoError) {
emit tr ("Ошибка загрузки информации для обновления.");
return;
}
QByteArray content = reply->readAll ();
QString component = reply->request ().attribute (QNetworkRequest::User).toString ();
if (component == _version) {
availableVersion_ = QJsonDocument::fromJson (content).object ();
parseAvailableVersion ();
}
else if (availableVersion_.contains (component) && !content.isEmpty ()) {
installComponent (component, content);
}
reply->deleteLater ();
}
void Updater::parseAvailableVersion () {
QStringList inaccessible, incompatible;
QStringList updateList;
QDir currentDir;
foreach (const QString &component, availableVersion_.keys ()) {
QJsonObject available = availableVersion_[component].toObject ();
QJsonObject current = currentVersion_[component].toObject ();
QString path = versionField (available, _path);
if (path.isEmpty ()) {
continue;
}
QFileInfo installDir = fileDir (path);
if (!installDir.exists ()) {
currentDir.mkpath (installDir.absoluteFilePath ());
}
if (!installDir.isWritable ()) { // check dir because install = remove + make new
inaccessible << installDir.absoluteFilePath ();
}
if (current[_version].toInt () < versionField (available, _compatibleVersion).toInt ()) {
incompatible << component;
}
if (!QFile::exists (path) || current[_version].toInt () < available[_version].toInt ()) {
updateList << component;
}
}
if (updateList.isEmpty ()) {
return;
}
QFileInfo updateFileDir = fileDir (updatesFileName_);
if (!updateFileDir.isWritable ()) {
inaccessible << updateFileDir.absoluteFilePath ();
}
inaccessible.removeDuplicates ();
QString message = tr ("Доступно обновлений: %1.\n").arg (updateList.size ());
QMessageBox::StandardButtons buttons = QMessageBox::Ok;
if (!incompatible.isEmpty ()) {
message += tr ("Несовместимых обновлений: %1.\nВыполните обновление вручную.")
.arg (incompatible.size ());
}
else if (!inaccessible.isEmpty ()) {
message += tr ("Недоступных для записи директорий: %1.\n%2\nИзмените права доступа и "
"повторите попытку или выполните обновление вручную.")
.arg (inaccessible.size ()).arg (inaccessible.join ("\n"));
}
else {
message += tr ("Обновить?");
buttons = QMessageBox::Yes | QMessageBox::No;
}
int result = QMessageBox::question (NULL, tr ("Обновление"), message, buttons);
if (result == QMessageBox::Yes) {
componentsUpdating_ = updateList.size ();
foreach (const QString &component, updateList) {
getComponent (component);
}
}
}
void Updater::getComponent (const QString &component) {
QJsonObject available = availableVersion_[component].toObject ();
QString path = versionField (available, _path);
if (path.isEmpty ()) {
--componentsUpdating_;
return;
}
QString url = versionField (available, _url);
if (url.isEmpty ()) { // just remove component
installComponent (component, QByteArray ());
}
else {
QNetworkRequest request (url);
request.setAttribute (QNetworkRequest::User, component);
network_->get (request);
}
}
void Updater::installComponent (const QString &component, const QByteArray &newContent) {
--componentsUpdating_;
ST_ASSERT (availableVersion_.contains (component));
QJsonObject available = availableVersion_[component].toObject ();
QString path = versionField (available, _path);
ST_ASSERT (!path.isEmpty ());
QString backup = path + backupSuffix_;
QFile::remove (backup);
QFile::rename (path, backup);
if (!newContent.isEmpty ()) {
QFile f (path);
if (!f.open (QFile::WriteOnly)) {
emit error (tr ("Ошибка обновления файла (%1).").arg (path));
return;
}
f.write (newContent);
f.close ();
bool ok;
QFileDevice::Permissions perm (available[_permissions].toString ().toUInt (&ok, 16));
if (ok) {
f.setPermissions (perm);
}
}
updateVersionInfo (component, available[_version].toInt ());
if (componentsUpdating_ == 0) {
emit updated ();
QString message = tr ("Обновление завершено. Для активации некоторых компонентов "
"может потребоваться перезапуск.");
QMessageBox::information (NULL, tr ("Обновление"), message, QMessageBox::Ok);
}
}
void Updater::updateVersionInfo (const QString &component, int version) {
QFile f (updatesFileName_);
if (!f.open (QFile::ReadWrite)) {
emit error (tr ("Ошибка обновления файла с текущей версией."));
return;
}
QJsonObject updated = QJsonDocument::fromJson (f.readAll ()).object ();
updated[component] = version;
f.seek (0);
f.write (QJsonDocument (updated).toJson ());
f.close ();
}

View File

@ -1,65 +0,0 @@
#ifndef UPDATER_H
#define UPDATER_H
#include <QObject>
#include <QJsonObject>
#include <QNetworkAccessManager>
/*!
* \brief The Updater class.
*
* Allows to download and copy files from remote source to local machine.
*/
class Updater : public QObject {
Q_OBJECT
public:
enum UpdateType {
UpdateTypeNever, UpdateTypeDaily, UpdateTypeWeekly, UpdateTypeMonthly
};
explicit Updater (QObject *parent = 0);
QString currentAppVersion () const;
//! Initiate updates check.
void checkForUpdates ();
//! Get nearest update check time based on given settings.
QDateTime nextCheckTime (const QDateTime &lastCheckTime, int updateType) const;
signals:
void error (const QString &message);
//! Emited after all components updated.
void updated ();
private slots:
//! Handle remote downloads finish.
void replyFinished (QNetworkReply *reply);
private:
//! Load current version info (built-in).
void getCurrentVersion ();
//! Update current version info with information about preformed updates.
void updateCurrentVersion ();
//! Load latest available version info from remote source.
void getAvailableVersion ();
//! Check is updates available, prompt user and start update.
void parseAvailableVersion ();
//! Start update of given component.
void getComponent (const QString &component);
//! Finalize update of given component with given new content.
void installComponent (const QString &component, const QByteArray &newContent);
//! Save information about component update on disk (for updateCurrentVersion()).
void updateVersionInfo (const QString &component, int version);
private:
QNetworkAccessManager *network_;
QJsonObject availableVersion_;
QJsonObject currentVersion_;
QString updatesFileName_;
int componentsUpdating_;
QString backupSuffix_;
};
#endif // UPDATER_H

View File

@ -1,21 +0,0 @@
#include <QNetworkProxy>
#include "Utils.h"
QString encode (const QString &source) {
if (source.isEmpty ()) {
return source;
}
char encKeys[] = {14, 26, 99, 43};
std::string result = source.toStdString ();
for (int i = 0, end = result.size (); i < end; ++i) {
result [i] = result[i] ^ encKeys[ i % sizeof(encKeys)];
}
return QString::fromUtf8 (result.data ());
}
QList<int> proxyTypeOrder () {
QList<int> proxyOrder;
proxyOrder << QNetworkProxy::NoProxy << QNetworkProxy::Socks5Proxy << QNetworkProxy::HttpProxy;
return proxyOrder;
}

10
Utils.h
View File

@ -1,10 +0,0 @@
#ifndef UTILS_H
#define UTILS_H
#include <QString>
QString encode (const QString &source);
QList<int> proxyTypeOrder ();
#endif // UTILS_H

View File

@ -1,156 +0,0 @@
#include <QWebView>
#include <QWebFrame>
#include <QSettings>
#include <QNetworkReply>
#include <QFile>
#include "WebTranslator.h"
#include "ProcessingItem.h"
#include "Settings.h"
#include "StAssert.h"
#include "WebTranslatorProxy.h"
#include "TranslatorHelper.h"
WebTranslator::WebTranslator ()
: QObject (),
proxy_ (new WebTranslatorProxy (this)), view_ (new QWebView),
translatorHelper_ (new TranslatorHelper), isReady_ (true),
ignoreSslErrors_ (settings_values::ignoreSslErrors),
forceRotateTranslators_ (settings_values::forceRotateTranslators) {
view_->settings ()->setAttribute (QWebSettings::AutoLoadImages, false);
view_->settings ()->setAttribute (QWebSettings::DeveloperExtrasEnabled, true);
view_->settings ()->setAttribute (QWebSettings::LocalStorageEnabled, true);
connect (view_, SIGNAL (loadFinished (bool)), SLOT (loadFinished (bool)));
connect (view_->page ()->mainFrame (), SIGNAL (javaScriptWindowObjectCleared ()),
this, SLOT (addProxyToView ()));
connect (view_->page ()->networkAccessManager (), SIGNAL (finished (QNetworkReply *)),
this, SLOT (replyFinished (QNetworkReply *)));
connect (view_->page ()->networkAccessManager (),
SIGNAL (sslErrors (QNetworkReply *, QList<QSslError>)),
this, SLOT (handleSslErrors (QNetworkReply *, QList<QSslError>)));
translationTimeout_.setSingleShot (true);
connect (&translationTimeout_, SIGNAL (timeout ()), SLOT (abortTranslation ()));
connect (proxy_, SIGNAL (translated (QString)), SLOT (proxyTranslated (QString)));
// Delay because it can emit signal that is not connected yet.
QTimer::singleShot (500, this, SLOT (applySettings ()));
}
WebTranslator::~WebTranslator () {
delete translatorHelper_;
delete view_;
}
void WebTranslator::addProxyToView () {
view_->page ()->mainFrame ()->addToJavaScriptWindowObject ("st_wtp", proxy_);
view_->page ()->mainFrame ()->evaluateJavaScript (translatorHelper_->currentScript ());
}
void WebTranslator::translate (ProcessingItem item) {
if (!item.isValid () || item.translateLanguage.isEmpty ()) {
emit translated (item);
return;
}
queue_.push_back (item);
translateQueued ();
}
void WebTranslator::translateQueued () {
if (isReady_ && !queue_.isEmpty ()) {
translatorHelper_->newItem (forceRotateTranslators_);
proxy_->setItem (queue_.first ());
if (!tryNextTranslator (true)) {
return;
}
}
}
void WebTranslator::proxyTranslated (const QString &text) {
if (!queue_.isEmpty () && queue_.first ().recognized == proxy_->sourceText ()) {
if (text.isEmpty () && tryNextTranslator ()) {
return;
}
ProcessingItem &item = queue_.first ();
item.translated = text;
emit translated (item);
}
finishTranslation (false);
}
void WebTranslator::handleSslErrors (QNetworkReply *reply, const QList<QSslError> &) {
if (ignoreSslErrors_) {
reply->ignoreSslErrors ();
}
}
void WebTranslator::abortTranslation () {
if (!tryNextTranslator ()) {
emit error (tr ("Перевод отменен по таймауту."));
finishTranslation ();
}
}
void WebTranslator::loadFinished (bool ok) {
if (!ok && !tryNextTranslator ()) {
QString url = view_->url ().toString ();
emit error (tr ("Ошибка загрузки страницы (%1) для перевода.").arg (url));
finishTranslation ();
}
}
void WebTranslator::finishTranslation (bool markAsTranslated) {
translationTimeout_.stop ();
view_->stop ();
if (!queue_.isEmpty ()) {
if (markAsTranslated) {
emit translated (queue_.first ());
}
queue_.pop_front ();
}
isReady_ = true;
translateQueued ();
}
bool WebTranslator::tryNextTranslator (bool firstTime) {
QString script = firstTime ? translatorHelper_->currentScript ()
: translatorHelper_->nextScript ();
if (script.isEmpty ()) {
return false;
}
translationTimeout_.stop ();
view_->stop ();
addProxyToView ();
view_->page ()->mainFrame ()->evaluateJavaScript ("translate();");
isReady_ = false;
translationTimeout_.start ();
return true;
}
void WebTranslator::replyFinished (QNetworkReply *reply) {
emit proxy_->resourceLoaded (reply->url ().toString ());
}
void WebTranslator::applySettings () {
QSettings settings;
settings.beginGroup (settings_names::translationGroup);
#define GET(NAME) settings.value (settings_names::NAME, settings_values::NAME)
translationTimeout_.setInterval (GET (translationTimeout).toInt () * 1000);
translatorHelper_->loadScripts ();
if (!translatorHelper_->gotScripts ()) {
emit error (tr ("Нет сценариев для перевода. Измените настройки."));
}
bool debugMode = GET (translationDebugMode).toBool ();
setDebugMode (debugMode);
ignoreSslErrors_ = GET (ignoreSslErrors).toBool ();
forceRotateTranslators_ = GET (forceRotateTranslators).toBool ();
#undef GET
}
void WebTranslator::setDebugMode (bool isOn) {
view_->setVisible (isOn);
}

View File

@ -1,57 +0,0 @@
#ifndef WEBTRANSLATOR_H
#define WEBTRANSLATOR_H
#include <QObject>
#include <QMap>
#include <QTimer>
#include "ProcessingItem.h"
class QWebView;
class QNetworkReply;
class QSslError;
class WebTranslatorProxy;
class TranslatorHelper;
class WebTranslator : public QObject {
Q_OBJECT
public:
explicit WebTranslator ();
~WebTranslator ();
signals:
void translated (ProcessingItem item);
void error (QString text);
public slots:
void translate (ProcessingItem item);
void applySettings ();
void setDebugMode (bool isOn);
private slots:
void loadFinished (bool ok);
void replyFinished (QNetworkReply *reply);
void addProxyToView ();
void abortTranslation ();
void proxyTranslated (const QString &text);
void handleSslErrors (QNetworkReply *reply, const QList<QSslError> &errors);
private:
void translateQueued ();
void finishTranslation (bool markAsTranslated = true);
bool tryNextTranslator (bool firstTime = false);
private:
WebTranslatorProxy *proxy_;
QWebView *view_;
TranslatorHelper *translatorHelper_;
QVector<ProcessingItem> queue_;
bool isReady_;
bool ignoreSslErrors_;
bool forceRotateTranslators_;
QTimer translationTimeout_;
};
#endif // WEBTRANSLATOR_H

View File

@ -1,25 +0,0 @@
#include "WebTranslatorProxy.h"
#include "ProcessingItem.h"
WebTranslatorProxy::WebTranslatorProxy (QObject *parent)
: QObject (parent) {
}
void WebTranslatorProxy::setItem (const ProcessingItem &item) {
sourceText_ = item.recognized;
sourceLanguage_ = item.ocrLanguage;
resultLanguage_ = item.translateLanguage;
}
const QString &WebTranslatorProxy::sourceText () const {
return sourceText_;
}
const QString &WebTranslatorProxy::sourceLanguage () const {
return sourceLanguage_;
}
const QString &WebTranslatorProxy::resultLanguage () const {
return resultLanguage_;
}

View File

@ -1,37 +0,0 @@
#ifndef WEBTRANSLATORPROXY_H
#define WEBTRANSLATORPROXY_H
#include <QObject>
class ProcessingItem;
/*!
* \brief Proxy class between WebTranslator and QWebView.
*/
class WebTranslatorProxy : public QObject {
Q_OBJECT
Q_PROPERTY (QString sourceText READ sourceText)
Q_PROPERTY (QString sourceLanguage READ sourceLanguage)
Q_PROPERTY (QString resultLanguage READ resultLanguage)
public:
explicit WebTranslatorProxy (QObject *parent = 0);
void setItem (const ProcessingItem &item);
const QString &sourceText () const;
const QString &sourceLanguage () const;
const QString &resultLanguage () const;
signals:
void translated (const QString &text);
void resourceLoaded (const QString &url);
private:
QString sourceText_;
QString sourceLanguage_;
QString resultLanguage_;
};
#endif // WEBTRANSLATORPROXY_H

View File

@ -1,69 +0,0 @@
Changes.
2.0.2:
* Added force translator rotation option.
2.0.1:
* Fixed installer.
2.0.0:
* Added a version for linux.
* Added support for multiple monitors.
* Added ability of recognition without translation.
* Added ability to recapture from old image.
* Added ability to recapture without closing capture window.
* Added ability to re-recognize other language.
* Added ability to display intermediate result when error occured.
* Added support for different translation services.
* Added ability to copy image to clipboard.
* Added ability to edit recognized text.
* Added ability to automatically correct common recognition mistakes.
* Added ability to use a proxy.
* Added ability to swap translation and recognition languages.
* Updated icons.
* Show progress on icon.
* Added ability to automatically update.
1.2.3:
* Fixed possible crash.
* Added version information and some error messages.
1.2.2:
* Added alternative translation source.
1.2.1:
* Fixed the bug with the lack of translation.
* Fixed the bug with the use of language recognition by default when you select another one in OCR region selection mode.
1.2.0:
+ Changed installer.
+ Added all available languages for recognition.
+ Added ability to specify language when selecting the field of recognition using right click.
+ Human readable language names.
* Reduced memory usage.
* Updated libraries.
1.1.3:
* Added library libgcc_s_dw2-1.dll.
* Updated libraries.
1.1.2:
* If you specify in the settings the path to tessdata characters "\" or "/" at the end of the path are no longer required.
1.1.1:
* Fixed an issue with incorrect window size when display results.
1.1.0:
+ Displays the result in the window, along with the picture.
+ Context menu expanded. Added buttons display the last result and copy it to the clipboard.

View File

@ -1,69 +0,0 @@
Изменения.
2.0.2:
* Добавлена настройка принудительной смены переводчиков.
2.0.1:
* Исправлен установщик.
2.0.0:
* Добавлена версия под linux.
* Добавлена поддержка нескольких мониторов.
* Добавлеа возможность распознание без перевода.
* Добавлена возможность вызова старого рисунка для выделения.
* Добавлена возможность повторного выделения без закрытия окна захвата.
* Добавлена возможность повторного распознания на другом языке.
* Добавлена возможность отображения промежуточного результата при ошибке перевода.
* Добавлена поддержка разных сервисов перевода.
* Добавлена возможность копирования изображения в буфер.
* Добавлена возможность редакции распознанного текста.
* Добавлена возможность автоматической коррекции частых ошибок распознавания.
* Добавлена возможность использования прокси.
* Добавлена возможность разовой смена языка перевода и распознавания.
* Обновлены иконки.
* Добавлено отображение статуса работы на иконке.
* Добавлена возможность автоматического обновления.
1.2.3:
* Устранена возможная причина падения.
* Добавлена информация о версии и некоторые сообщения об ошибках.
1.2.2:
* Добавлен альтернативный источник перевода.
1.2.1:
* Устранена ошибка отсутствия перевода.
* Устранена ошибка использования языка распознавания по умолчанию при выборе другого в окне выделения области распознавания.
1.2.0:
+ Изменен установщик.
+ В установщик добавлены все доступные языки для распознавания.
+ Добавлена возможность указания языка при выборе области распознавания при помощи выделения с правым кликом.
+ Человекочитаемые названия языков.
* Уменьшено потребление памяти.
* Обновлены библиотеки.
1.1.3:
- В установщик добавлена библиотека libgcc_s_dw2-1.dll.
- Обновлены библиотеки.
1.1.2:
- При задании в настройках пути к tessdata символы «\» или «/» в конце пути теперь не обязательны.
1.1.1:
- Пофиксен баг с неверным размером окна отображения результатов.
1.1.0:
- Отображение результата в окошке, вместе с картинкой.
- Контекстное меню расширено. Добавлены кнопки отображения последнего результата и копирования его в буфер обмена.

View File

@ -1,16 +0,0 @@
Package: screen-translator
Version: 1
Section: graphics
Architecture: amd64
Depends: libtesseract3, libqt5webkit5, libqt5x11extras5
Recommends: tesseract-ocr-eng, tesseract-ocr-rus, tesseract-ocr-deu, tesseract-ocr-spa, tesseract-ocr-chi-sim, tesseract-ocr-fra, tesseract-ocr-jpn
Installed-Size: 1
Priority: optional
Maintainer: Gres <translator@gres.biz>
Homepage: https://github.com/OneMoreGres/ScreenTranslator
Description: Screen capture, OCR and translation tool.
This software allows to translate any text on screen.
Basically it is a combination of screen capture,
OCR and translation tools.

View File

@ -1,9 +0,0 @@
[Desktop Entry]
Version=1
Name=Screen Translator
Comment=Screen capture, OCR and translation tool.
Exec=/opt/ScreenTranslator/ScreenTranslator
Icon=ScreenTranslator.png
Terminal=false
Type=Application
Categories=Graphics;

View File

@ -1,129 +0,0 @@
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#ifexist "defines.iss"
#include "defines.iss"
#endif
#ifndef MyAppVersion
#define MyAppVersion "1.0.0"
#endif
#define MyAppName "Screen Translator"
#define MyAppPublisher "Gres"
#define MyAppURL "http://gres.biz/screen-translator/"
#define MyAppExeName "ScreenTranslator.exe"
#define MyAppDescription "Screen capture and translation tool"
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{016F399E-0EED-476C-AB00-8AD0FF5BFD77}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
AllowNoIcons=yes
PrivilegesRequired=admin
CloseApplications=yes
OutputDir=..
OutputBaseFilename=screen-translator-online-{#MyAppVersion}
SetupIconFile=icon.ico
RestartIfNeededByRun=False
ShowLanguageDialog=auto
VersionInfoCompany={#MyAppPublisher}
VersionInfoDescription={#MyAppDescription}
VersionInfoProductName={#MyAppName}
VersionInfoProductVersion={#MyAppVersion}
VersionInfoVersion={#MyAppVersion}
Compression=lzma2/ultra64
InternalCompressLevel=ultra
SolidCompression=yes
[Languages]
Name: "en"; MessagesFile: "compiler:Default.isl,default.isl"; LicenseFile: "LICENSE_en.md"; InfoBeforeFile: "Changelog_en.txt"
Name: "ru"; MessagesFile: "compiler:Languages\Russian.isl,russian.isl"; LicenseFile: "LICENSE_ru.md"; InfoBeforeFile: "Changelog_ru.txt"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
Name: "startupicon"; Description: "{cm:CreateStartupIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: quicklaunchicon
Name: "{commonstartup}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: startupicon
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
Filename: "{tmp}\vcredist_x86.exe"; Description: "{cm:InstallRedist}"; Parameters: "/install"; Flags: postinstall skipifsilent
[Files]
Source: "content\ScreenTranslator.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: Executable
Source: "content\*.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: Libraries
Source: "content\platforms\*"; DestDir: "{app}\platforms"; Flags: ignoreversion; Components: Libraries
Source: "content\translators\*"; DestDir: "{app}\translators"; Flags: ignoreversion; Components: Translators
Source: "content\vcredist_x86.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall;
[Types]
Name: "custom"; Description: "Custom installation"; Flags: iscustom
[Components]
Name: "Executable"; Description: "{cm:Executables}"; Types: custom; Flags: fixed;
Name: "Libraries"; Description: "{cm:Libraries}"; Types: custom; Flags: fixed;
Name: "Translators"; Description: "{cm:Translators}"; Types: custom; Flags: fixed;
#include "tessdata.iss"
[UninstallDelete]
Type: files; Name: "{app}\updates.json"
Type: files; Name: "{app}\st_subs.csv"
[UninstallRun]
Filename: "taskkill.exe"; Parameters: "/IM ScreenTranslator.exe /T /F"
[Code]
#define DwinsHs_Use_Predefined_Downloading_WizardPage
#define DwinsHs_Auto_Continue
#include "dwinshs.iss"
procedure InitializeWizard();
begin
DwinsHs_InitializeWizard(wpPreparing);
end;
procedure CurPageChanged(CurPageID: Integer);
begin
DwinsHs_CurPageChanged(CurPageID, nil, nil);
end;
function ShouldSkipPage(CurPageId: Integer): Boolean;
begin
Result := False;
DwinsHs_ShouldSkipPage(CurPageId, Result);
end;
function BackButtonClick(CurPageID: Integer): Boolean;
begin
Result := True;
DwinsHs_BackButtonClick(CurPageID);
end;
function NextButtonClick(CurPageID: Integer): Boolean;
begin
Result := True;
DwinsHs_NextButtonClick(CurPageID, Result);
end;
procedure CancelButtonClick(CurPageID: Integer; var Cancel, Confirm: Boolean);
begin
DwinsHs_CancelButtonClick(CurPageID, Cancel, Confirm);
end;

View File

@ -1,91 +0,0 @@
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#ifexist "defines.iss"
#include "defines.iss"
#endif
#ifndef MyAppVersion
#define MyAppVersion "1.0.0"
#endif
#define MyAppName "Screen Translator"
#define MyAppPublisher "Gres"
#define MyAppURL "http://gres.biz/screen-translator/"
#define MyAppExeName "ScreenTranslator.exe"
#define MyAppDescription "Screen capture and translation tool"
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{016F399E-0EED-476C-AB00-8AD0FF5BFD77}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
AllowNoIcons=yes
PrivilegesRequired=admin
CloseApplications=yes
OutputDir=..
OutputBaseFilename=screen-translator-offline-{#MyAppVersion}
SetupIconFile=icon.ico
RestartIfNeededByRun=False
ShowLanguageDialog=auto
VersionInfoCompany={#MyAppPublisher}
VersionInfoDescription={#MyAppDescription}
VersionInfoProductName={#MyAppName}
VersionInfoProductVersion={#MyAppVersion}
VersionInfoVersion={#MyAppVersion}
Compression=lzma2/ultra64
InternalCompressLevel=ultra
SolidCompression=yes
[Languages]
Name: "en"; MessagesFile: "compiler:Default.isl,default.isl"; LicenseFile: "LICENSE_en.md"; InfoBeforeFile: "Changelog_en.txt"
Name: "ru"; MessagesFile: "compiler:Languages\Russian.isl,russian.isl"; LicenseFile: "LICENSE_ru.md"; InfoBeforeFile: "Changelog_ru.txt"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
Name: "startupicon"; Description: "{cm:CreateStartupIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: quicklaunchicon
Name: "{commonstartup}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: startupicon
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
Filename: "{tmp}\vcredist_x86.exe"; Description: "{cm:InstallRedist}"; Parameters: "/install"; Flags: postinstall skipifsilent
[Files]
Source: "content\ScreenTranslator.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: Executable
Source: "content\*.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: Libraries
Source: "content\platforms\*"; DestDir: "{app}\platforms"; Flags: ignoreversion; Components: Libraries
Source: "content\translators\*"; DestDir: "{app}\translators"; Flags: ignoreversion; Components: Translators
Source: "content\vcredist_x86.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall;
[Types]
Name: "custom"; Description: "Custom installation"; Flags: iscustom
[Components]
Name: "Executable"; Description: "{cm:Executables}"; Types: custom; Flags: fixed;
Name: "Libraries"; Description: "{cm:Libraries}"; Types: custom; Flags: fixed;
Name: "Translators"; Description: "{cm:Translators}"; Types: custom; Flags: fixed;
#include "tessdataBuiltin.iss"
[UninstallDelete]
Type: files; Name: "{app}\updates.json"
Type: files; Name: "{app}\st_subs.csv"
[UninstallRun]
Filename: "taskkill.exe"; Parameters: "/IM ScreenTranslator.exe /T /F"

View File

@ -1,9 +0,0 @@
Лицензия MIT
Copyright (c) 2017 Gres (gres@gres.biz)
Данная лицензия разрешает лицам, получившим копию данного программного обеспечения и сопутствующей документации (в дальнейшем именуемыми «Программное Обеспечение»), безвозмездно использовать Программное Обеспечение без ограничений, включая неограниченное право на использование, копирование, изменение, добавление, публикацию, распространение, сублицензирование и/или продажу копий Программного Обеспечения, а также лицам, которым предоставляется данное Программное Обеспечение, при соблюдении следующих условий:
Указанное выше уведомление об авторском праве и данные условия должны быть включены во все копии или значимые части данного Программного Обеспечения.
ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНО ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ ГАРАНТИИ ТОВАРНОЙ ПРИГОДНОСТИ, СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ НАЗНАЧЕНИЮ И ОТСУТСТВИЯ НАРУШЕНИЙ, НО НЕ ОГРАНИЧИВАЯСЬ ИМИ. НИ В КАКОМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ НЕ НЕСУТ ОТВЕТСТВЕННОСТИ ПО КАКИМ-ЛИБО ИСКАМ, ЗА УЩЕРБ ИЛИ ПО ИНЫМ ТРЕБОВАНИЯМ, В ТОМ ЧИСЛЕ, ПРИ ДЕЙСТВИИ КОНТРАКТА, ДЕЛИКТЕ ИЛИ ИНОЙ СИТУАЦИИ, ВОЗНИКШИМ ИЗ-ЗА ИСПОЛЬЗОВАНИЯ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ ИЛИ ИНЫХ ДЕЙСТВИЙ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ.

View File

@ -1,109 +0,0 @@
#iso-639-3 standard code to names
afr Afrikaans Африкаанс
amh Amharic Амхарский
ara Arabic Арабский
asm Assamese Ассамский
aze Azerbaijani Азербайджанский
#aze_cyrl aze_cyrl
bel Belarusian Белорусский
ben Bengali Бенгальский
bod Tibetan Тибетский
bos Bosnian Боснийский
bul Bulgarian Болгарии
cat Catalan Каталонский
ceb Cebuano Кебуано
ces Czech Чешский
chi_sim Chineese_simplified Китайский_упрощенный
chi_tra Chineese_traditional Китайский_традиционный
chr Cherokee Чероки
cym Welsh Валлийский
dan Danish Датский
#dan_frak dan_frak
deu German Немецкий
#deu_frak deu_frak
dzo Dzongkha Джонгкха
ell Modern_Greek Новогреческий
eng English Английский
enm Middle_English Средневековый_английский
epo Esperanto Эсперанто
equ Math Математика
est Estonian Эстонский
eus Basque Басков
fas Persian Персидский
fin Finnish Финский
fra French Французский
frk Frankish Франкский
frm Middle_French Средневековый_французский
gle Irish Ирландский
glg Galician Галисийский
grc Ancient_Greek Древнегреческий
guj Gujarati Гуджарати
hat Haitian Гаити
heb Hebrew Иврит
hin Hindi Хинди
hrv Croatian Хорватский
hun Hungarian Венгерский
iku Inuktitut Инуктитут
ind Indonesian Индонезийский
isl Icelandic Исландский
ita Italian Итальянский
#ita_old ita_old
jav Javanese Яванский
jpn Japanese Японский
kan Kannada Каннада
kat Georgian Грузинский
#kat_old kat_old
kaz Kazakh Казахский
khm Khmer Кхмерский
kir Kirghiz Киргизский
kor Korean Корейский
kur Kurdish Курдский
lao Lao Лао
lat Latin Латинский
lav Latvian Латышский
lit Lithuanian Литовский
mal Malayalam Малаялам
mar Marathi Маратхи
mkd Macedonian Македонский
mlt Maltese Мальтийский
msa Malay Малайский
mya Burmese Бирманский
nep Nepali Непальский
nld Dutch Голландский
nor Norwegian Норвежский
ori Oriya Ория
#osd OSD OSD
pan Panjabi Панджаби
pol Polish Польский
por Portuguese Португальский
pus Pushto Пушту
ron Romanian Румынский
rus Russian Русский
san Sanskrit Санскрит
sin Sinhala Сингальский
slk Slovak Словацкий
#slk_frak slk_frak
slv Slovenian Словенский
spa Spanish Испанский
#spa_old spa_old
sqi Albanian Албанский
srp Serbian Сербский
#srp_latn srp_latn
swa Swahili Суахили
swe Swedish Шведский
syr Syriac Сирийский
tam Tamil Тамил
tel Telugu Телугу
tgk Tajik Таджикиский
tgl Tagalog Тагальский
tha Thai Тайский
tir Tigrinya Тиграи
tur Turkish Турецкий
uig Uighur Уйгурский
ukr Ukrainian Украинский
urd Urdu Урду
uzb Uzbek Узбекский
#uzb_cyrl uzb_cyrl
vie Vietnamese Вьетнамский
yid Yiddish Идиш

View File

@ -1,106 +0,0 @@
[CustomMessages]
CreateStartupIcon=Create autostart icon
Executables=Executables
Libraries=Libraries
Translators=Translators
InstallRedist=Install VC redistributable
Languages=OCR Languages
Afrikaans=Afrikaans
Albanian=Albanian
Amharic=Amharic
Ancient_Greek=Ancient Greek
Arabic=Arabic
Assamese=Assamese
Azerbaijani=Azerbaijani
Basque=Basque
Belarusian=Belarusian
Bengali=Bengali
Bosnian=Bosnian
Bulgarian=Bulgarian
Burmese=Burmese
Catalan=Catalan
Cebuano=Cebuano
Cherokee=Cherokee
Chineese_simplified=Chineese simplified
Chineese_traditional=Chineese traditional
Croatian=Croatian
Czech=Czech
Danish=Danish
Dutch=Dutch
Dzongkha=Dzongkha
English=English
Esperanto=Esperanto
Estonian=Estonian
Finnish=Finnish
Frankish=Frankish
French=French
Galician=Galician
Georgian=Georgian
German=German
Gujarati=Gujarati
Haitian=Haitian
Hebrew=Hebrew
Hindi=Hindi
Hungarian=Hungarian
Icelandic=Icelandic
Indonesian=Indonesian
Inuktitut=Inuktitut
Irish=Irish
Italian=Italian
Japanese=Japanese
Javanese=Javanese
Kannada=Kannada
Kazakh=Kazakh
Khmer=Khmer
Kirghiz=Kirghiz
Korean=Korean
Kurdish=Kurdish
Lao=Lao
Latin=Latin
Latvian=Latvian
Lithuanian=Lithuanian
Macedonian=Macedonian
Malay=Malay
Malayalam=Malayalam
Maltese=Maltese
Marathi=Marathi
Math=Math
Middle_English=Middle English
Middle_French=Middle French
Modern_Greek=Modern Greek
Nepali=Nepali
Norwegian=Norwegian
Oriya=Oriya
Panjabi=Panjabi
Persian=Persian
Polish=Polish
Portuguese=Portuguese
Pushto=Pushto
Romanian=Romanian
Russian=Russian
Sanskrit=Sanskrit
Serbian=Serbian
Sinhala=Sinhala
Slovak=Slovak
Slovenian=Slovenian
Spanish=Spanish
Swahili=Swahili
Swedish=Swedish
Syriac=Syriac
Tagalog=Tagalog
Tajik=Tajik
Tamil=Tamil
Telugu=Telugu
Thai=Thai
Tibetan=Tibetan
Tigrinya=Tigrinya
Turkish=Turkish
Uighur=Uighur
Ukrainian=Ukrainian
Urdu=Urdu
Uzbek=Uzbek
Vietnamese=Vietnamese
Welsh=Welsh
Yiddish=Yiddish

File diff suppressed because it is too large Load Diff

View File

@ -1,94 +0,0 @@
#!/bin/bash
TESSDATA_DIR="$1"
if [ -z "$TESSDATA_DIR" ]; then echo "Usage $0 <tessdata_dir>"; exit 0; fi
TESSDATA_DIR=`readlink -e $TESSDATA_DIR`
OUT_FILE="tessdata.iss"
OUT_FILE=`readlink -m $OUT_FILE`
LANGS_FILE="code2langTr.txt"
function getLangsOrder {
local FIELD=$1
local ORDER=`cat $LANGS_FILE | cut -d' ' -f$FIELD | sort`
local FNAMES=""
for i in $ORDER; do
local FNAME=`grep "$i" $LANGS_FILE | cut -d' ' -f1`
if [[ -z "$FNAME" || "${FNAME:0:1}" == "#" ]]; then
continue;
fi
FNAMES=$FNAMES" $FNAME"
done
echo $FNAMES
}
FILES="[Files]\n"
COMPONENTS="[Components]\nName: \"Languages\"; Description: \"{cm:Languages}\"; Types: custom\n"
MESSAGES_EN="\n[CustomMessages]\nen.Languages=OCR Languages\n"
MESSAGES_RU="\n[CustomMessages]\nru.Languages=Языки распознавания\n"
PREV_LANG=""
CUSTOM_LANGS="eng"
function fillIss {
local LANG_FIELD=$1
local COMPONENT_LANG=$2
local ONLY_COMPONENTS=$3
COMPONENTS=$COMPONENTS"\n"
local ORDER=`cat $LANGS_FILE | cut -d' ' -f$LANG_FIELD | sort`
for i in $ORDER; do
local LANG_LINE=$(grep " $i " $LANGS_FILE)
local FNAME=$(echo "$LANG_LINE" | cut -d' ' -f1)
local LANG_EN=$(echo "$LANG_LINE" | cut -d' ' -f2)
local LANG_RU=$(echo "$LANG_LINE" | cut -d' ' -f3)
if [[ -z "$FNAME" || "${FNAME:0:1}" == "#" ]]; then
continue;
fi
local CUR_LANG_FILES=`find $TESSDATA_DIR -name "$FNAME.*"`
if [ -z "$CUR_LANG_FILES" ]; then
echo "no lang"
continue
fi
local COMPONENT_SIZE=0
for s in `find $TESSDATA_DIR -name "$FNAME.*" -exec wc -c {} \; | cut -d' ' -f1`; do
COMPONENT_SIZE=$(expr $COMPONENT_SIZE + $s)
done
TYPES=""
if [[ $CUSTOM_LANGS =~ $FNAME ]]; then
TYPES="custom"
fi
if [ ! -z "$TYPES" ]; then
TYPES="Types: $TYPES; ";
fi
COMPONENTS=$COMPONENTS"Name: \"Languages\\\\$LANG_EN\"; Description: \"{cm:$LANG_EN}\"; Languages: $COMPONENT_LANG;
$TYPES ExtraDiskSpaceRequired: $COMPONENT_SIZE\n"
if $ONLY_COMPONENTS; then
continue;
fi
MESSAGES_EN=$MESSAGES_EN"en.$LANG_EN=$(echo "$LANG_EN" | sed 's/_/ /g')\n"
MESSAGES_RU=$MESSAGES_RU"ru.$LANG_EN=$(echo "$LANG_RU" | sed 's/_/ /g')\n"
for f in $CUR_LANG_FILES; do
local FNAME=$(basename "$f")
FILES=$FILES"Source: \"{tmp}\\\\$FNAME\"; DestDir: \"{app}\\\\tessdata\"; Components: Languages\\\\$LANG_EN;
Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\\\\$FNAME'),
'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/$FNAME', 'ST_setup', 'Get', 0);\n"
done
done
}
fillIss 2 "en" false
fillIss 3 "ru" true
echo -e $FILES > $OUT_FILE
echo -e $COMPONENTS >> $OUT_FILE
echo -e $MESSAGES_EN >> $OUT_FILE
echo -e $MESSAGES_RU >> $OUT_FILE
iconv -f utf8 -t cp1251 $OUT_FILE -o $OUT_FILE.1
mv $OUT_FILE.1 $OUT_FILE

View File

@ -1,122 +0,0 @@
[CustomMessages]
CreateStartupIcon=Äîáàâèòü â àâòîçàïóñê
Executables=Èñïîëíÿåìûå ôàéëû
Libraries=Áèáëèîòåêè
Translators=Ïåðåâîä÷èêè
InstallRedist=Óñòàíîâèòü áèáëèîòåêè Visual C++
DwinsHs_PageCaption =Çàãðóçêà ôàéëîâ
DwinsHs_PageDescription =Ïîæàëóéñòà, äîæäèòåñü îêîí÷àíèÿ çàãðóçêè...
DwinsHs_TotalProgress =Îáùèé ïðîãðåññ:
DwinsHs_CurrentFile =Òåêóùèé ôàéë:
DwinsHs_File =Ôàéë:
DwinsHs_Speed =Ñêîðîñòü:
DwinsHs_Status =Ñòàòóñ:
DwinsHs_ElapsedTime =Çàòðà÷åííîå âðåìÿ:
DwinsHs_RemainingTime =Îñòàâøååñÿ âðåìÿ:
DwinsHs_Status_GetFileInformation =Ïîëó÷åíèå ðàçìåðà ôàéëà
DwinsHs_Status_StartingDownload =Íà÷àëî çàãðóçêè
DwinsHs_Status_Downloading =Çàãðóçêà
DwinsHs_Status_DownlaodComplete =Çàãðóçêà çàâåðøåíà
Languages=ßçûêè ðàñïîçíàâàíèÿ
Afrikaans=Àôðèêààíñ
Albanian=Àëáàíñêèé
Amharic=Àìõàðñêèé
Ancient_Greek=Äðåâíåãðå÷åñêèé
Arabic=Àðàáñêèé
Assamese=Àññàìñêèé
Azerbaijani=Àçåðáàéäæàíñêèé
Basque=Áàñêîâ
Belarusian=Áåëîðóññêèé
Bengali=Áåíãàëüñêèé
Bosnian=Áîñíèéñêèé
Bulgarian=Áîëãàðèè
Burmese=Áèðìàíñêèé
Catalan=Êàòàëîíñêèé
Cebuano=Êåáóàíî
Cherokee=×åðîêè
Chineese_simplified=Êèòàéñêèé óïðîùåííûé
Chineese_traditional=Êèòàéñêèé òðàäèöèîííûé
Croatian=Õîðâàòñêèé
Czech=×åøñêèé
Danish=Äàòñêèé
Dutch=Ãîëëàíäñêèé
Dzongkha=Äæîíãêõà
English=Àíãëèéñêèé
Esperanto=Ýñïåðàíòî
Estonian=Ýñòîíñêèé
Finnish=Ôèíñêèé
Frankish=Ôðàíêñêèé
French=Ôðàíöóçñêèé
Galician=Ãàëèñèéñêèé
Georgian=Ãðóçèíñêèé
German=Íåìåöêèé
Gujarati=Ãóäæàðàòè
Haitian=Ãàèòè
Hebrew=Èâðèò
Hindi=Õèíäè
Hungarian=Âåíãåðñêèé
Icelandic=Èñëàíäñêèé
Indonesian=Èíäîíåçèéñêèé
Inuktitut=Èíóêòèòóò
Irish=Èðëàíäñêèé
Italian=Èòàëüÿíñêèé
Japanese=ßïîíñêèé
Javanese=ßâàíñêèé
Kannada=Êàííàäà
Kazakh=Êàçàõñêèé
Khmer=Êõìåðñêèé
Kirghiz=Êèðãèçñêèé
Korean=Êîðåéñêèé
Kurdish=Êóðäñêèé
Lao=Ëàî
Latin=Ëàòèíñêèé
Latvian=Ëàòûøñêèé
Lithuanian=Ëèòîâñêèé
Macedonian=Ìàêåäîíñêèé
Malay=Ìàëàéñêèé
Malayalam=Ìàëàÿëàì
Maltese=Ìàëüòèéñêèé
Marathi=Ìàðàòõè
Math=Ìàòåìàòèêà
Middle_English=Ñðåäíåâåêîâûé àíãëèéñêèé
Middle_French=Ñðåäíåâåêîâûé ôðàíöóçñêèé
Modern_Greek=Íîâîãðå÷åñêèé
Nepali=Íåïàëüñêèé
Norwegian=Íîðâåæñêèé
Oriya=Îðèÿ
Panjabi=Ïàíäæàáè
Persian=Ïåðñèäñêèé
Polish=Ïîëüñêèé
Portuguese=Ïîðòóãàëüñêèé
Pushto=Ïóøòó
Romanian=Ðóìûíñêèé
Russian=Ðóññêèé
Sanskrit=Ñàíñêðèò
Serbian=Ñåðáñêèé
Sinhala=Ñèíãàëüñêèé
Slovak=Ñëîâàöêèé
Slovenian=Ñëîâåíñêèé
Spanish=Èñïàíñêèé
Swahili=Ñóàõèëè
Swedish=Øâåäñêèé
Syriac=Ñèðèéñêèé
Tagalog=Òàãàëüñêèé
Tajik=Òàäæèêèñêèé
Tamil=Òàìèë
Telugu=Òåëóãó
Thai=Òàéñêèé
Tibetan=Òèáåòñêèé
Tigrinya=Òèãðàè
Turkish=Òóðåöêèé
Uighur=Óéãóðñêèé
Ukrainian=Óêðàèíñêèé
Urdu=Óðäó
Uzbek=Óçáåêñêèé
Vietnamese=Âüåòíàìñêèé
Welsh=Âàëëèéñêèé
Yiddish=Èäèø

View File

@ -1,348 +0,0 @@
[Files]
Source: "{tmp}\afr.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Afrikaans; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\afr.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/afr.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\sqi.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Albanian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\sqi.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/sqi.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\amh.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Amharic; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\amh.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/amh.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\grc.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Ancient_Greek; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\grc.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/grc.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\ara.cube.nn"; DestDir: "{app}\tessdata"; Components: Languages\Arabic; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ara.cube.nn'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ara.cube.nn', 'ST_setup', 'Get', 0);
Source: "{tmp}\ara.cube.bigrams"; DestDir: "{app}\tessdata"; Components: Languages\Arabic; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ara.cube.bigrams'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ara.cube.bigrams', 'ST_setup', 'Get', 0);
Source: "{tmp}\ara.cube.word-freq"; DestDir: "{app}\tessdata"; Components: Languages\Arabic; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ara.cube.word-freq'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ara.cube.word-freq', 'ST_setup', 'Get', 0);
Source: "{tmp}\ara.cube.size"; DestDir: "{app}\tessdata"; Components: Languages\Arabic; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ara.cube.size'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ara.cube.size', 'ST_setup', 'Get', 0);
Source: "{tmp}\ara.cube.params"; DestDir: "{app}\tessdata"; Components: Languages\Arabic; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ara.cube.params'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ara.cube.params', 'ST_setup', 'Get', 0);
Source: "{tmp}\ara.cube.fold"; DestDir: "{app}\tessdata"; Components: Languages\Arabic; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ara.cube.fold'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ara.cube.fold', 'ST_setup', 'Get', 0);
Source: "{tmp}\ara.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Arabic; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ara.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ara.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\ara.cube.lm"; DestDir: "{app}\tessdata"; Components: Languages\Arabic; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ara.cube.lm'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ara.cube.lm', 'ST_setup', 'Get', 0);
Source: "{tmp}\asm.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Assamese; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\asm.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/asm.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\aze.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Azerbaijani; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\aze.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/aze.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\eus.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Basque; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\eus.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/eus.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\bel.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Belarusian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\bel.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/bel.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\ben.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Bengali; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ben.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ben.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\bos.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Bosnian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\bos.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/bos.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\bul.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Bulgarian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\bul.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/bul.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\mya.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Burmese; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\mya.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/mya.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\cat.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Catalan; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\cat.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/cat.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\ceb.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Cebuano; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ceb.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ceb.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\chr.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Cherokee; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\chr.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/chr.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\chi_sim.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Chineese_simplified; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\chi_sim.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/chi_sim.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\chi_tra.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Chineese_traditional; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\chi_tra.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/chi_tra.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\hrv.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Croatian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\hrv.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/hrv.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\ces.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Czech; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ces.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ces.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\dan.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Danish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\dan.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/dan.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\nld.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Dutch; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\nld.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/nld.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\dzo.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Dzongkha; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\dzo.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/dzo.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\eng.cube.word-freq"; DestDir: "{app}\tessdata"; Components: Languages\English; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\eng.cube.word-freq'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/eng.cube.word-freq', 'ST_setup', 'Get', 0);
Source: "{tmp}\eng.cube.params"; DestDir: "{app}\tessdata"; Components: Languages\English; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\eng.cube.params'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/eng.cube.params', 'ST_setup', 'Get', 0);
Source: "{tmp}\eng.cube.bigrams"; DestDir: "{app}\tessdata"; Components: Languages\English; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\eng.cube.bigrams'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/eng.cube.bigrams', 'ST_setup', 'Get', 0);
Source: "{tmp}\eng.cube.nn"; DestDir: "{app}\tessdata"; Components: Languages\English; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\eng.cube.nn'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/eng.cube.nn', 'ST_setup', 'Get', 0);
Source: "{tmp}\eng.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\English; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\eng.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/eng.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\eng.cube.fold"; DestDir: "{app}\tessdata"; Components: Languages\English; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\eng.cube.fold'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/eng.cube.fold', 'ST_setup', 'Get', 0);
Source: "{tmp}\eng.cube.size"; DestDir: "{app}\tessdata"; Components: Languages\English; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\eng.cube.size'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/eng.cube.size', 'ST_setup', 'Get', 0);
Source: "{tmp}\eng.tesseract_cube.nn"; DestDir: "{app}\tessdata"; Components: Languages\English; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\eng.tesseract_cube.nn'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/eng.tesseract_cube.nn', 'ST_setup', 'Get', 0);
Source: "{tmp}\eng.cube.lm"; DestDir: "{app}\tessdata"; Components: Languages\English; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\eng.cube.lm'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/eng.cube.lm', 'ST_setup', 'Get', 0);
Source: "{tmp}\epo.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Esperanto; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\epo.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/epo.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\est.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Estonian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\est.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/est.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\fin.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Finnish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\fin.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/fin.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\frk.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Frankish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\frk.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/frk.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\fra.tesseract_cube.nn"; DestDir: "{app}\tessdata"; Components: Languages\French; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\fra.tesseract_cube.nn'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/fra.tesseract_cube.nn', 'ST_setup', 'Get', 0);
Source: "{tmp}\fra.cube.params"; DestDir: "{app}\tessdata"; Components: Languages\French; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\fra.cube.params'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/fra.cube.params', 'ST_setup', 'Get', 0);
Source: "{tmp}\fra.cube.lm"; DestDir: "{app}\tessdata"; Components: Languages\French; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\fra.cube.lm'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/fra.cube.lm', 'ST_setup', 'Get', 0);
Source: "{tmp}\fra.cube.fold"; DestDir: "{app}\tessdata"; Components: Languages\French; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\fra.cube.fold'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/fra.cube.fold', 'ST_setup', 'Get', 0);
Source: "{tmp}\fra.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\French; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\fra.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/fra.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\fra.cube.size"; DestDir: "{app}\tessdata"; Components: Languages\French; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\fra.cube.size'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/fra.cube.size', 'ST_setup', 'Get', 0);
Source: "{tmp}\fra.cube.bigrams"; DestDir: "{app}\tessdata"; Components: Languages\French; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\fra.cube.bigrams'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/fra.cube.bigrams', 'ST_setup', 'Get', 0);
Source: "{tmp}\fra.cube.nn"; DestDir: "{app}\tessdata"; Components: Languages\French; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\fra.cube.nn'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/fra.cube.nn', 'ST_setup', 'Get', 0);
Source: "{tmp}\fra.cube.word-freq"; DestDir: "{app}\tessdata"; Components: Languages\French; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\fra.cube.word-freq'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/fra.cube.word-freq', 'ST_setup', 'Get', 0);
Source: "{tmp}\glg.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Galician; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\glg.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/glg.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\kat.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Georgian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\kat.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/kat.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\deu.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\German; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\deu.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/deu.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\guj.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Gujarati; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\guj.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/guj.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\hat.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Haitian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\hat.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/hat.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\heb.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Hebrew; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\heb.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/heb.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\hin.cube.nn"; DestDir: "{app}\tessdata"; Components: Languages\Hindi; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\hin.cube.nn'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/hin.cube.nn', 'ST_setup', 'Get', 0);
Source: "{tmp}\hin.cube.lm"; DestDir: "{app}\tessdata"; Components: Languages\Hindi; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\hin.cube.lm'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/hin.cube.lm', 'ST_setup', 'Get', 0);
Source: "{tmp}\hin.tesseract_cube.nn"; DestDir: "{app}\tessdata"; Components: Languages\Hindi; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\hin.tesseract_cube.nn'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/hin.tesseract_cube.nn', 'ST_setup', 'Get', 0);
Source: "{tmp}\hin.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Hindi; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\hin.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/hin.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\hin.cube.params"; DestDir: "{app}\tessdata"; Components: Languages\Hindi; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\hin.cube.params'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/hin.cube.params', 'ST_setup', 'Get', 0);
Source: "{tmp}\hin.cube.word-freq"; DestDir: "{app}\tessdata"; Components: Languages\Hindi; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\hin.cube.word-freq'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/hin.cube.word-freq', 'ST_setup', 'Get', 0);
Source: "{tmp}\hin.cube.fold"; DestDir: "{app}\tessdata"; Components: Languages\Hindi; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\hin.cube.fold'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/hin.cube.fold', 'ST_setup', 'Get', 0);
Source: "{tmp}\hin.cube.bigrams"; DestDir: "{app}\tessdata"; Components: Languages\Hindi; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\hin.cube.bigrams'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/hin.cube.bigrams', 'ST_setup', 'Get', 0);
Source: "{tmp}\hun.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Hungarian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\hun.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/hun.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\isl.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Icelandic; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\isl.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/isl.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\ind.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Indonesian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ind.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ind.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\iku.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Inuktitut; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\iku.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/iku.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\gle.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Irish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\gle.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/gle.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\ita.tesseract_cube.nn"; DestDir: "{app}\tessdata"; Components: Languages\Italian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ita.tesseract_cube.nn'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ita.tesseract_cube.nn', 'ST_setup', 'Get', 0);
Source: "{tmp}\ita.cube.word-freq"; DestDir: "{app}\tessdata"; Components: Languages\Italian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ita.cube.word-freq'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ita.cube.word-freq', 'ST_setup', 'Get', 0);
Source: "{tmp}\ita.cube.params"; DestDir: "{app}\tessdata"; Components: Languages\Italian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ita.cube.params'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ita.cube.params', 'ST_setup', 'Get', 0);
Source: "{tmp}\ita.cube.fold"; DestDir: "{app}\tessdata"; Components: Languages\Italian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ita.cube.fold'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ita.cube.fold', 'ST_setup', 'Get', 0);
Source: "{tmp}\ita.cube.bigrams"; DestDir: "{app}\tessdata"; Components: Languages\Italian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ita.cube.bigrams'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ita.cube.bigrams', 'ST_setup', 'Get', 0);
Source: "{tmp}\ita.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Italian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ita.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ita.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\ita.cube.size"; DestDir: "{app}\tessdata"; Components: Languages\Italian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ita.cube.size'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ita.cube.size', 'ST_setup', 'Get', 0);
Source: "{tmp}\ita.cube.nn"; DestDir: "{app}\tessdata"; Components: Languages\Italian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ita.cube.nn'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ita.cube.nn', 'ST_setup', 'Get', 0);
Source: "{tmp}\ita.cube.lm"; DestDir: "{app}\tessdata"; Components: Languages\Italian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ita.cube.lm'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ita.cube.lm', 'ST_setup', 'Get', 0);
Source: "{tmp}\jpn.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Japanese; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\jpn.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/jpn.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\jav.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Javanese; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\jav.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/jav.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\kan.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Kannada; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\kan.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/kan.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\kaz.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Kazakh; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\kaz.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/kaz.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\khm.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Khmer; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\khm.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/khm.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\kir.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Kirghiz; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\kir.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/kir.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\kor.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Korean; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\kor.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/kor.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\kur.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Kurdish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\kur.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/kur.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\lao.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Lao; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\lao.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/lao.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\lat.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Latin; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\lat.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/lat.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\lav.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Latvian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\lav.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/lav.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\lit.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Lithuanian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\lit.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/lit.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\mkd.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Macedonian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\mkd.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/mkd.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\msa.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Malay; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\msa.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/msa.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\mal.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Malayalam; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\mal.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/mal.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\mlt.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Maltese; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\mlt.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/mlt.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\mar.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Marathi; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\mar.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/mar.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\equ.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Math; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\equ.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/equ.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\enm.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Middle_English; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\enm.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/enm.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\frm.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Middle_French; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\frm.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/frm.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\ell.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Modern_Greek; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ell.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ell.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\nep.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Nepali; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\nep.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/nep.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\nor.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Norwegian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\nor.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/nor.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\ori.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Oriya; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ori.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ori.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\pan.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Panjabi; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\pan.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/pan.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\fas.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Persian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\fas.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/fas.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\pol.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Polish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\pol.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/pol.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\por.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Portuguese; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\por.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/por.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\pus.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Pushto; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\pus.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/pus.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\ron.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Romanian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ron.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ron.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\rus.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Russian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\rus.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/rus.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\rus.cube.size"; DestDir: "{app}\tessdata"; Components: Languages\Russian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\rus.cube.size'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/rus.cube.size', 'ST_setup', 'Get', 0);
Source: "{tmp}\rus.cube.fold"; DestDir: "{app}\tessdata"; Components: Languages\Russian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\rus.cube.fold'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/rus.cube.fold', 'ST_setup', 'Get', 0);
Source: "{tmp}\rus.cube.lm"; DestDir: "{app}\tessdata"; Components: Languages\Russian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\rus.cube.lm'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/rus.cube.lm', 'ST_setup', 'Get', 0);
Source: "{tmp}\rus.cube.word-freq"; DestDir: "{app}\tessdata"; Components: Languages\Russian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\rus.cube.word-freq'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/rus.cube.word-freq', 'ST_setup', 'Get', 0);
Source: "{tmp}\rus.cube.nn"; DestDir: "{app}\tessdata"; Components: Languages\Russian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\rus.cube.nn'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/rus.cube.nn', 'ST_setup', 'Get', 0);
Source: "{tmp}\rus.cube.params"; DestDir: "{app}\tessdata"; Components: Languages\Russian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\rus.cube.params'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/rus.cube.params', 'ST_setup', 'Get', 0);
Source: "{tmp}\san.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Sanskrit; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\san.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/san.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\srp.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Serbian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\srp.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/srp.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\sin.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Sinhala; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\sin.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/sin.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\slk.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Slovak; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\slk.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/slk.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\slv.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Slovenian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\slv.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/slv.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\spa.cube.word-freq"; DestDir: "{app}\tessdata"; Components: Languages\Spanish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\spa.cube.word-freq'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/spa.cube.word-freq', 'ST_setup', 'Get', 0);
Source: "{tmp}\spa.cube.lm"; DestDir: "{app}\tessdata"; Components: Languages\Spanish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\spa.cube.lm'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/spa.cube.lm', 'ST_setup', 'Get', 0);
Source: "{tmp}\spa.cube.fold"; DestDir: "{app}\tessdata"; Components: Languages\Spanish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\spa.cube.fold'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/spa.cube.fold', 'ST_setup', 'Get', 0);
Source: "{tmp}\spa.cube.size"; DestDir: "{app}\tessdata"; Components: Languages\Spanish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\spa.cube.size'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/spa.cube.size', 'ST_setup', 'Get', 0);
Source: "{tmp}\spa.cube.bigrams"; DestDir: "{app}\tessdata"; Components: Languages\Spanish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\spa.cube.bigrams'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/spa.cube.bigrams', 'ST_setup', 'Get', 0);
Source: "{tmp}\spa.cube.nn"; DestDir: "{app}\tessdata"; Components: Languages\Spanish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\spa.cube.nn'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/spa.cube.nn', 'ST_setup', 'Get', 0);
Source: "{tmp}\spa.cube.params"; DestDir: "{app}\tessdata"; Components: Languages\Spanish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\spa.cube.params'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/spa.cube.params', 'ST_setup', 'Get', 0);
Source: "{tmp}\spa.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Spanish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\spa.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/spa.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\swa.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Swahili; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\swa.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/swa.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\swe.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Swedish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\swe.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/swe.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\syr.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Syriac; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\syr.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/syr.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\tgl.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Tagalog; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\tgl.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/tgl.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\tgk.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Tajik; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\tgk.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/tgk.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\tam.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Tamil; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\tam.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/tam.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\tel.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Telugu; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\tel.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/tel.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\tha.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Thai; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\tha.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/tha.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\bod.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Tibetan; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\bod.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/bod.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\tir.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Tigrinya; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\tir.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/tir.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\tur.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Turkish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\tur.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/tur.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\uig.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Uighur; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\uig.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/uig.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\ukr.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Ukrainian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ukr.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ukr.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\urd.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Urdu; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\urd.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/urd.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\uzb.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Uzbek; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\uzb.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/uzb.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\vie.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Vietnamese; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\vie.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/vie.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\cym.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Welsh; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\cym.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/cym.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\yid.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Yiddish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\yid.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/yid.traineddata', 'ST_setup', 'Get', 0);
[Components]
Name: "Languages"; Description: "{cm:Languages}"; Types: custom
Name: "Languages\Afrikaans"; Description: "{cm:Afrikaans}"; Languages: en; ExtraDiskSpaceRequired: 5198548
Name: "Languages\Albanian"; Description: "{cm:Albanian}"; Languages: en; ExtraDiskSpaceRequired: 6587325
Name: "Languages\Amharic"; Description: "{cm:Amharic}"; Languages: en; ExtraDiskSpaceRequired: 2953500
Name: "Languages\Ancient_Greek"; Description: "{cm:Ancient_Greek}"; Languages: en; ExtraDiskSpaceRequired: 5182527
Name: "Languages\Arabic"; Description: "{cm:Arabic}"; Languages: en; ExtraDiskSpaceRequired: 28534834
Name: "Languages\Assamese"; Description: "{cm:Assamese}"; Languages: en; ExtraDiskSpaceRequired: 15827072
Name: "Languages\Azerbaijani"; Description: "{cm:Azerbaijani}"; Languages: en; ExtraDiskSpaceRequired: 6615244
Name: "Languages\Basque"; Description: "{cm:Basque}"; Languages: en; ExtraDiskSpaceRequired: 4969647
Name: "Languages\Belarusian"; Description: "{cm:Belarusian}"; Languages: en; ExtraDiskSpaceRequired: 6822594
Name: "Languages\Bengali"; Description: "{cm:Bengali}"; Languages: en; ExtraDiskSpaceRequired: 15552533
Name: "Languages\Bosnian"; Description: "{cm:Bosnian}"; Languages: en; ExtraDiskSpaceRequired: 5432328
Name: "Languages\Bulgarian"; Description: "{cm:Bulgarian}"; Languages: en; ExtraDiskSpaceRequired: 6026234
Name: "Languages\Burmese"; Description: "{cm:Burmese}"; Languages: en; ExtraDiskSpaceRequired: 69770179
Name: "Languages\Catalan"; Description: "{cm:Catalan}"; Languages: en; ExtraDiskSpaceRequired: 5356190
Name: "Languages\Cebuano"; Description: "{cm:Cebuano}"; Languages: en; ExtraDiskSpaceRequired: 1686752
Name: "Languages\Cherokee"; Description: "{cm:Cherokee}"; Languages: en; ExtraDiskSpaceRequired: 1083194
Name: "Languages\Chineese_simplified"; Description: "{cm:Chineese_simplified}"; Languages: en; ExtraDiskSpaceRequired: 42089623
Name: "Languages\Chineese_traditional"; Description: "{cm:Chineese_traditional}"; Languages: en; ExtraDiskSpaceRequired: 56692327
Name: "Languages\Croatian"; Description: "{cm:Croatian}"; Languages: en; ExtraDiskSpaceRequired: 9135966
Name: "Languages\Czech"; Description: "{cm:Czech}"; Languages: en; ExtraDiskSpaceRequired: 11896327
Name: "Languages\Danish"; Description: "{cm:Danish}"; Languages: en; ExtraDiskSpaceRequired: 7340575
Name: "Languages\Dutch"; Description: "{cm:Dutch}"; Languages: en; ExtraDiskSpaceRequired: 17098919
Name: "Languages\Dzongkha"; Description: "{cm:Dzongkha}"; Languages: en; ExtraDiskSpaceRequired: 3310882
Name: "Languages\English"; Description: "{cm:English}"; Languages: en; Types: custom; ExtraDiskSpaceRequired: 38371506
Name: "Languages\Esperanto"; Description: "{cm:Esperanto}"; Languages: en; ExtraDiskSpaceRequired: 6602178
Name: "Languages\Estonian"; Description: "{cm:Estonian}"; Languages: en; ExtraDiskSpaceRequired: 9644486
Name: "Languages\Finnish"; Description: "{cm:Finnish}"; Languages: en; ExtraDiskSpaceRequired: 13274908
Name: "Languages\Frankish"; Description: "{cm:Frankish}"; Languages: en; ExtraDiskSpaceRequired: 16451109
Name: "Languages\French"; Description: "{cm:French}"; Languages: en; ExtraDiskSpaceRequired: 37350210
Name: "Languages\Galician"; Description: "{cm:Galician}"; Languages: en; ExtraDiskSpaceRequired: 5520499
Name: "Languages\Georgian"; Description: "{cm:Georgian}"; Languages: en; ExtraDiskSpaceRequired: 6219735
Name: "Languages\German"; Description: "{cm:German}"; Languages: en; ExtraDiskSpaceRequired: 13367187
Name: "Languages\Gujarati"; Description: "{cm:Gujarati}"; Languages: en; ExtraDiskSpaceRequired: 10622356
Name: "Languages\Haitian"; Description: "{cm:Haitian}"; Languages: en; ExtraDiskSpaceRequired: 1349947
Name: "Languages\Hebrew"; Description: "{cm:Hebrew}"; Languages: en; ExtraDiskSpaceRequired: 4339016
Name: "Languages\Hindi"; Description: "{cm:Hindi}"; Languages: en; ExtraDiskSpaceRequired: 22717250
Name: "Languages\Hungarian"; Description: "{cm:Hungarian}"; Languages: en; ExtraDiskSpaceRequired: 12213770
Name: "Languages\Icelandic"; Description: "{cm:Icelandic}"; Languages: en; ExtraDiskSpaceRequired: 6098683
Name: "Languages\Indonesian"; Description: "{cm:Indonesian}"; Languages: en; ExtraDiskSpaceRequired: 6503178
Name: "Languages\Inuktitut"; Description: "{cm:Inuktitut}"; Languages: en; ExtraDiskSpaceRequired: 995246
Name: "Languages\Irish"; Description: "{cm:Irish}"; Languages: en; ExtraDiskSpaceRequired: 3482557
Name: "Languages\Italian"; Description: "{cm:Italian}"; Languages: en; ExtraDiskSpaceRequired: 32720949
Name: "Languages\Japanese"; Description: "{cm:Japanese}"; Languages: en; ExtraDiskSpaceRequired: 33072615
Name: "Languages\Javanese"; Description: "{cm:Javanese}"; Languages: en; ExtraDiskSpaceRequired: 4404351
Name: "Languages\Kannada"; Description: "{cm:Kannada}"; Languages: en; ExtraDiskSpaceRequired: 35657050
Name: "Languages\Kazakh"; Description: "{cm:Kazakh}"; Languages: en; ExtraDiskSpaceRequired: 4529022
Name: "Languages\Khmer"; Description: "{cm:Khmer}"; Languages: en; ExtraDiskSpaceRequired: 48851416
Name: "Languages\Kirghiz"; Description: "{cm:Kirghiz}"; Languages: en; ExtraDiskSpaceRequired: 5502225
Name: "Languages\Korean"; Description: "{cm:Korean}"; Languages: en; ExtraDiskSpaceRequired: 13309831
Name: "Languages\Kurdish"; Description: "{cm:Kurdish}"; Languages: en; ExtraDiskSpaceRequired: 2020502
Name: "Languages\Lao"; Description: "{cm:Lao}"; Languages: en; ExtraDiskSpaceRequired: 21118927
Name: "Languages\Latin"; Description: "{cm:Latin}"; Languages: en; ExtraDiskSpaceRequired: 6028030
Name: "Languages\Latvian"; Description: "{cm:Latvian}"; Languages: en; ExtraDiskSpaceRequired: 7802105
Name: "Languages\Lithuanian"; Description: "{cm:Lithuanian}"; Languages: en; ExtraDiskSpaceRequired: 8916163
Name: "Languages\Macedonian"; Description: "{cm:Macedonian}"; Languages: en; ExtraDiskSpaceRequired: 3837583
Name: "Languages\Malay"; Description: "{cm:Malay}"; Languages: en; ExtraDiskSpaceRequired: 6495742
Name: "Languages\Malayalam"; Description: "{cm:Malayalam}"; Languages: en; ExtraDiskSpaceRequired: 8786470
Name: "Languages\Maltese"; Description: "{cm:Maltese}"; Languages: en; ExtraDiskSpaceRequired: 5118233
Name: "Languages\Marathi"; Description: "{cm:Marathi}"; Languages: en; ExtraDiskSpaceRequired: 14237379
Name: "Languages\Math"; Description: "{cm:Math}"; Languages: en; ExtraDiskSpaceRequired: 2251826
Name: "Languages\Middle_English"; Description: "{cm:Middle_English}"; Languages: en; ExtraDiskSpaceRequired: 2105888
Name: "Languages\Middle_French"; Description: "{cm:Middle_French}"; Languages: en; ExtraDiskSpaceRequired: 15831815
Name: "Languages\Modern_Greek"; Description: "{cm:Modern_Greek}"; Languages: en; ExtraDiskSpaceRequired: 5422512
Name: "Languages\Nepali"; Description: "{cm:Nepali}"; Languages: en; ExtraDiskSpaceRequired: 15862542
Name: "Languages\Norwegian"; Description: "{cm:Norwegian}"; Languages: en; ExtraDiskSpaceRequired: 8262167
Name: "Languages\Oriya"; Description: "{cm:Oriya}"; Languages: en; ExtraDiskSpaceRequired: 7900659
Name: "Languages\Panjabi"; Description: "{cm:Panjabi}"; Languages: en; ExtraDiskSpaceRequired: 10212006
Name: "Languages\Persian"; Description: "{cm:Persian}"; Languages: en; ExtraDiskSpaceRequired: 4803733
Name: "Languages\Polish"; Description: "{cm:Polish}"; Languages: en; ExtraDiskSpaceRequired: 13918058
Name: "Languages\Portuguese"; Description: "{cm:Portuguese}"; Languages: en; ExtraDiskSpaceRequired: 12914622
Name: "Languages\Pushto"; Description: "{cm:Pushto}"; Languages: en; ExtraDiskSpaceRequired: 2493826
Name: "Languages\Romanian"; Description: "{cm:Romanian}"; Languages: en; ExtraDiskSpaceRequired: 7957608
Name: "Languages\Russian"; Description: "{cm:Russian}"; Languages: en; ExtraDiskSpaceRequired: 39371802
Name: "Languages\Sanskrit"; Description: "{cm:Sanskrit}"; Languages: en; ExtraDiskSpaceRequired: 22747749
Name: "Languages\Serbian"; Description: "{cm:Serbian}"; Languages: en; ExtraDiskSpaceRequired: 4611681
Name: "Languages\Sinhala"; Description: "{cm:Sinhala}"; Languages: en; ExtraDiskSpaceRequired: 6793740
Name: "Languages\Slovak"; Description: "{cm:Slovak}"; Languages: en; ExtraDiskSpaceRequired: 9126966
Name: "Languages\Slovenian"; Description: "{cm:Slovenian}"; Languages: en; ExtraDiskSpaceRequired: 6824064
Name: "Languages\Spanish"; Description: "{cm:Spanish}"; Languages: en; ExtraDiskSpaceRequired: 39171233
Name: "Languages\Swahili"; Description: "{cm:Swahili}"; Languages: en; ExtraDiskSpaceRequired: 3861506
Name: "Languages\Swedish"; Description: "{cm:Swedish}"; Languages: en; ExtraDiskSpaceRequired: 9460295
Name: "Languages\Syriac"; Description: "{cm:Syriac}"; Languages: en; ExtraDiskSpaceRequired: 2734020
Name: "Languages\Tagalog"; Description: "{cm:Tagalog}"; Languages: en; ExtraDiskSpaceRequired: 4114554
Name: "Languages\Tajik"; Description: "{cm:Tajik}"; Languages: en; ExtraDiskSpaceRequired: 1119022
Name: "Languages\Tamil"; Description: "{cm:Tamil}"; Languages: en; ExtraDiskSpaceRequired: 5118600
Name: "Languages\Telugu"; Description: "{cm:Telugu}"; Languages: en; ExtraDiskSpaceRequired: 39318860
Name: "Languages\Thai"; Description: "{cm:Thai}"; Languages: en; ExtraDiskSpaceRequired: 13565168
Name: "Languages\Tibetan"; Description: "{cm:Tibetan}"; Languages: en; ExtraDiskSpaceRequired: 25231676
Name: "Languages\Tigrinya"; Description: "{cm:Tigrinya}"; Languages: en; ExtraDiskSpaceRequired: 1806235
Name: "Languages\Turkish"; Description: "{cm:Turkish}"; Languages: en; ExtraDiskSpaceRequired: 14069931
Name: "Languages\Uighur"; Description: "{cm:Uighur}"; Languages: en; ExtraDiskSpaceRequired: 2017575
Name: "Languages\Ukrainian"; Description: "{cm:Ukrainian}"; Languages: en; ExtraDiskSpaceRequired: 8043189
Name: "Languages\Urdu"; Description: "{cm:Urdu}"; Languages: en; ExtraDiskSpaceRequired: 4825658
Name: "Languages\Uzbek"; Description: "{cm:Uzbek}"; Languages: en; ExtraDiskSpaceRequired: 4286554
Name: "Languages\Vietnamese"; Description: "{cm:Vietnamese}"; Languages: en; ExtraDiskSpaceRequired: 6096118
Name: "Languages\Welsh"; Description: "{cm:Welsh}"; Languages: en; ExtraDiskSpaceRequired: 3789352
Name: "Languages\Yiddish"; Description: "{cm:Yiddish}"; Languages: en; ExtraDiskSpaceRequired: 4238718
Name: "Languages\Azerbaijani"; Description: "{cm:Azerbaijani}"; Languages: ru; ExtraDiskSpaceRequired: 6615244
Name: "Languages\Albanian"; Description: "{cm:Albanian}"; Languages: ru; ExtraDiskSpaceRequired: 6587325
Name: "Languages\Amharic"; Description: "{cm:Amharic}"; Languages: ru; ExtraDiskSpaceRequired: 2953500
Name: "Languages\English"; Description: "{cm:English}"; Languages: ru; Types: custom; ExtraDiskSpaceRequired: 38371506
Name: "Languages\Arabic"; Description: "{cm:Arabic}"; Languages: ru; ExtraDiskSpaceRequired: 28534834
Name: "Languages\Assamese"; Description: "{cm:Assamese}"; Languages: ru; ExtraDiskSpaceRequired: 15827072
Name: "Languages\Afrikaans"; Description: "{cm:Afrikaans}"; Languages: ru; ExtraDiskSpaceRequired: 5198548
Name: "Languages\Basque"; Description: "{cm:Basque}"; Languages: ru; ExtraDiskSpaceRequired: 4969647
Name: "Languages\Belarusian"; Description: "{cm:Belarusian}"; Languages: ru; ExtraDiskSpaceRequired: 6822594
Name: "Languages\Bengali"; Description: "{cm:Bengali}"; Languages: ru; ExtraDiskSpaceRequired: 15552533
Name: "Languages\Burmese"; Description: "{cm:Burmese}"; Languages: ru; ExtraDiskSpaceRequired: 69770179
Name: "Languages\Bulgarian"; Description: "{cm:Bulgarian}"; Languages: ru; ExtraDiskSpaceRequired: 6026234
Name: "Languages\Bosnian"; Description: "{cm:Bosnian}"; Languages: ru; ExtraDiskSpaceRequired: 5432328
Name: "Languages\Welsh"; Description: "{cm:Welsh}"; Languages: ru; ExtraDiskSpaceRequired: 3789352
Name: "Languages\Hungarian"; Description: "{cm:Hungarian}"; Languages: ru; ExtraDiskSpaceRequired: 12213770
Name: "Languages\Vietnamese"; Description: "{cm:Vietnamese}"; Languages: ru; ExtraDiskSpaceRequired: 6096118
Name: "Languages\Haitian"; Description: "{cm:Haitian}"; Languages: ru; ExtraDiskSpaceRequired: 1349947
Name: "Languages\Galician"; Description: "{cm:Galician}"; Languages: ru; ExtraDiskSpaceRequired: 5520499
Name: "Languages\Dutch"; Description: "{cm:Dutch}"; Languages: ru; ExtraDiskSpaceRequired: 17098919
Name: "Languages\Georgian"; Description: "{cm:Georgian}"; Languages: ru; ExtraDiskSpaceRequired: 6219735
Name: "Languages\Gujarati"; Description: "{cm:Gujarati}"; Languages: ru; ExtraDiskSpaceRequired: 10622356
Name: "Languages\Danish"; Description: "{cm:Danish}"; Languages: ru; ExtraDiskSpaceRequired: 7340575
Name: "Languages\Dzongkha"; Description: "{cm:Dzongkha}"; Languages: ru; ExtraDiskSpaceRequired: 3310882
Name: "Languages\Ancient_Greek"; Description: "{cm:Ancient_Greek}"; Languages: ru; ExtraDiskSpaceRequired: 5182527
Name: "Languages\Hebrew"; Description: "{cm:Hebrew}"; Languages: ru; ExtraDiskSpaceRequired: 4339016
Name: "Languages\Yiddish"; Description: "{cm:Yiddish}"; Languages: ru; ExtraDiskSpaceRequired: 4238718
Name: "Languages\Indonesian"; Description: "{cm:Indonesian}"; Languages: ru; ExtraDiskSpaceRequired: 6503178
Name: "Languages\Inuktitut"; Description: "{cm:Inuktitut}"; Languages: ru; ExtraDiskSpaceRequired: 995246
Name: "Languages\Irish"; Description: "{cm:Irish}"; Languages: ru; ExtraDiskSpaceRequired: 3482557
Name: "Languages\Icelandic"; Description: "{cm:Icelandic}"; Languages: ru; ExtraDiskSpaceRequired: 6098683
Name: "Languages\Spanish"; Description: "{cm:Spanish}"; Languages: ru; ExtraDiskSpaceRequired: 39171233
Name: "Languages\Italian"; Description: "{cm:Italian}"; Languages: ru; ExtraDiskSpaceRequired: 32720949
Name: "Languages\Kazakh"; Description: "{cm:Kazakh}"; Languages: ru; ExtraDiskSpaceRequired: 4529022
Name: "Languages\Kannada"; Description: "{cm:Kannada}"; Languages: ru; ExtraDiskSpaceRequired: 35657050
Name: "Languages\Catalan"; Description: "{cm:Catalan}"; Languages: ru; ExtraDiskSpaceRequired: 5356190
Name: "Languages\Cebuano"; Description: "{cm:Cebuano}"; Languages: ru; ExtraDiskSpaceRequired: 1686752
Name: "Languages\Kirghiz"; Description: "{cm:Kirghiz}"; Languages: ru; ExtraDiskSpaceRequired: 5502225
Name: "Languages\Chineese_traditional"; Description: "{cm:Chineese_traditional}"; Languages: ru; ExtraDiskSpaceRequired: 56692327
Name: "Languages\Chineese_simplified"; Description: "{cm:Chineese_simplified}"; Languages: ru; ExtraDiskSpaceRequired: 42089623
Name: "Languages\Korean"; Description: "{cm:Korean}"; Languages: ru; ExtraDiskSpaceRequired: 13309831
Name: "Languages\Kurdish"; Description: "{cm:Kurdish}"; Languages: ru; ExtraDiskSpaceRequired: 2020502
Name: "Languages\Khmer"; Description: "{cm:Khmer}"; Languages: ru; ExtraDiskSpaceRequired: 48851416
Name: "Languages\Lao"; Description: "{cm:Lao}"; Languages: ru; ExtraDiskSpaceRequired: 21118927
Name: "Languages\Latin"; Description: "{cm:Latin}"; Languages: ru; ExtraDiskSpaceRequired: 6028030
Name: "Languages\Latvian"; Description: "{cm:Latvian}"; Languages: ru; ExtraDiskSpaceRequired: 7802105
Name: "Languages\Lithuanian"; Description: "{cm:Lithuanian}"; Languages: ru; ExtraDiskSpaceRequired: 8916163
Name: "Languages\Macedonian"; Description: "{cm:Macedonian}"; Languages: ru; ExtraDiskSpaceRequired: 3837583
Name: "Languages\Malay"; Description: "{cm:Malay}"; Languages: ru; ExtraDiskSpaceRequired: 6495742
Name: "Languages\Malayalam"; Description: "{cm:Malayalam}"; Languages: ru; ExtraDiskSpaceRequired: 8786470
Name: "Languages\Maltese"; Description: "{cm:Maltese}"; Languages: ru; ExtraDiskSpaceRequired: 5118233
Name: "Languages\Marathi"; Description: "{cm:Marathi}"; Languages: ru; ExtraDiskSpaceRequired: 14237379
Name: "Languages\Math"; Description: "{cm:Math}"; Languages: ru; ExtraDiskSpaceRequired: 2251826
Name: "Languages\German"; Description: "{cm:German}"; Languages: ru; ExtraDiskSpaceRequired: 13367187
Name: "Languages\Nepali"; Description: "{cm:Nepali}"; Languages: ru; ExtraDiskSpaceRequired: 15862542
Name: "Languages\Modern_Greek"; Description: "{cm:Modern_Greek}"; Languages: ru; ExtraDiskSpaceRequired: 5422512
Name: "Languages\Norwegian"; Description: "{cm:Norwegian}"; Languages: ru; ExtraDiskSpaceRequired: 8262167
Name: "Languages\Oriya"; Description: "{cm:Oriya}"; Languages: ru; ExtraDiskSpaceRequired: 7900659
Name: "Languages\Panjabi"; Description: "{cm:Panjabi}"; Languages: ru; ExtraDiskSpaceRequired: 10212006
Name: "Languages\Persian"; Description: "{cm:Persian}"; Languages: ru; ExtraDiskSpaceRequired: 4803733
Name: "Languages\Polish"; Description: "{cm:Polish}"; Languages: ru; ExtraDiskSpaceRequired: 13918058
Name: "Languages\Portuguese"; Description: "{cm:Portuguese}"; Languages: ru; ExtraDiskSpaceRequired: 12914622
Name: "Languages\Pushto"; Description: "{cm:Pushto}"; Languages: ru; ExtraDiskSpaceRequired: 2493826
Name: "Languages\Romanian"; Description: "{cm:Romanian}"; Languages: ru; ExtraDiskSpaceRequired: 7957608
Name: "Languages\Russian"; Description: "{cm:Russian}"; Languages: ru; ExtraDiskSpaceRequired: 39371802
Name: "Languages\Sanskrit"; Description: "{cm:Sanskrit}"; Languages: ru; ExtraDiskSpaceRequired: 22747749
Name: "Languages\Serbian"; Description: "{cm:Serbian}"; Languages: ru; ExtraDiskSpaceRequired: 4611681
Name: "Languages\Sinhala"; Description: "{cm:Sinhala}"; Languages: ru; ExtraDiskSpaceRequired: 6793740
Name: "Languages\Syriac"; Description: "{cm:Syriac}"; Languages: ru; ExtraDiskSpaceRequired: 2734020
Name: "Languages\Slovak"; Description: "{cm:Slovak}"; Languages: ru; ExtraDiskSpaceRequired: 9126966
Name: "Languages\Slovenian"; Description: "{cm:Slovenian}"; Languages: ru; ExtraDiskSpaceRequired: 6824064
Name: "Languages\Middle_English"; Description: "{cm:Middle_English}"; Languages: ru; ExtraDiskSpaceRequired: 2105888
Name: "Languages\Middle_French"; Description: "{cm:Middle_French}"; Languages: ru; ExtraDiskSpaceRequired: 15831815
Name: "Languages\Swahili"; Description: "{cm:Swahili}"; Languages: ru; ExtraDiskSpaceRequired: 3861506
Name: "Languages\Tagalog"; Description: "{cm:Tagalog}"; Languages: ru; ExtraDiskSpaceRequired: 4114554
Name: "Languages\Tajik"; Description: "{cm:Tajik}"; Languages: ru; ExtraDiskSpaceRequired: 1119022
Name: "Languages\Thai"; Description: "{cm:Thai}"; Languages: ru; ExtraDiskSpaceRequired: 13565168
Name: "Languages\Tamil"; Description: "{cm:Tamil}"; Languages: ru; ExtraDiskSpaceRequired: 5118600
Name: "Languages\Telugu"; Description: "{cm:Telugu}"; Languages: ru; ExtraDiskSpaceRequired: 39318860
Name: "Languages\Tibetan"; Description: "{cm:Tibetan}"; Languages: ru; ExtraDiskSpaceRequired: 25231676
Name: "Languages\Tigrinya"; Description: "{cm:Tigrinya}"; Languages: ru; ExtraDiskSpaceRequired: 1806235
Name: "Languages\Turkish"; Description: "{cm:Turkish}"; Languages: ru; ExtraDiskSpaceRequired: 14069931
Name: "Languages\Uzbek"; Description: "{cm:Uzbek}"; Languages: ru; ExtraDiskSpaceRequired: 4286554
Name: "Languages\Uighur"; Description: "{cm:Uighur}"; Languages: ru; ExtraDiskSpaceRequired: 2017575
Name: "Languages\Ukrainian"; Description: "{cm:Ukrainian}"; Languages: ru; ExtraDiskSpaceRequired: 8043189
Name: "Languages\Urdu"; Description: "{cm:Urdu}"; Languages: ru; ExtraDiskSpaceRequired: 4825658
Name: "Languages\Finnish"; Description: "{cm:Finnish}"; Languages: ru; ExtraDiskSpaceRequired: 13274908
Name: "Languages\Frankish"; Description: "{cm:Frankish}"; Languages: ru; ExtraDiskSpaceRequired: 16451109
Name: "Languages\French"; Description: "{cm:French}"; Languages: ru; ExtraDiskSpaceRequired: 37350210
Name: "Languages\Hindi"; Description: "{cm:Hindi}"; Languages: ru; ExtraDiskSpaceRequired: 22717250
Name: "Languages\Croatian"; Description: "{cm:Croatian}"; Languages: ru; ExtraDiskSpaceRequired: 9135966
Name: "Languages\Cherokee"; Description: "{cm:Cherokee}"; Languages: ru; ExtraDiskSpaceRequired: 1083194
Name: "Languages\Czech"; Description: "{cm:Czech}"; Languages: ru; ExtraDiskSpaceRequired: 11896327
Name: "Languages\Swedish"; Description: "{cm:Swedish}"; Languages: ru; ExtraDiskSpaceRequired: 9460295
Name: "Languages\Esperanto"; Description: "{cm:Esperanto}"; Languages: ru; ExtraDiskSpaceRequired: 6602178
Name: "Languages\Estonian"; Description: "{cm:Estonian}"; Languages: ru; ExtraDiskSpaceRequired: 9644486
Name: "Languages\Javanese"; Description: "{cm:Javanese}"; Languages: ru; ExtraDiskSpaceRequired: 4404351
Name: "Languages\Japanese"; Description: "{cm:Japanese}"; Languages: ru; ExtraDiskSpaceRequired: 33072615

View File

@ -1,30 +0,0 @@
[Files]
Source: "tessdata\ara.*"; DestDir: "{app}\tessdata"; Components: Languages\Arabic; Flags: ignoreversion;
Source: "tessdata\chi_sim.*"; DestDir: "{app}\tessdata"; Components: Languages\Chineese_simplified; Flags: ignoreversion;
Source: "tessdata\eng.*"; DestDir: "{app}\tessdata"; Components: Languages\English; Flags: ignoreversion;
Source: "tessdata\fra.*"; DestDir: "{app}\tessdata"; Components: Languages\French; Flags: ignoreversion;
Source: "tessdata\deu.*"; DestDir: "{app}\tessdata"; Components: Languages\German; Flags: ignoreversion;
Source: "tessdata\jpn.*"; DestDir: "{app}\tessdata"; Components: Languages\Japanese; Flags: ignoreversion;
Source: "tessdata\rus.*"; DestDir: "{app}\tessdata"; Components: Languages\Russian; Flags: ignoreversion;
Source: "tessdata\spa.*"; DestDir: "{app}\tessdata"; Components: Languages\Spanish; Flags: ignoreversion;
[Components]
Name: "Languages"; Description: "{cm:Languages}"; Types: custom
Name: "Languages\Arabic"; Description: "{cm:Arabic}"; Languages: en; Types: custom; ExtraDiskSpaceRequired: 28534834
Name: "Languages\Chineese_simplified"; Description: "{cm:Chineese_simplified}"; Languages: en; Types: custom; ExtraDiskSpaceRequired: 42089623
Name: "Languages\English"; Description: "{cm:English}"; Languages: en; Types: custom; ExtraDiskSpaceRequired: 38371506
Name: "Languages\French"; Description: "{cm:French}"; Languages: en; Types: custom; ExtraDiskSpaceRequired: 37350210
Name: "Languages\German"; Description: "{cm:German}"; Languages: en; Types: custom; ExtraDiskSpaceRequired: 13367187
Name: "Languages\Japanese"; Description: "{cm:Japanese}"; Languages: en; Types: custom; ExtraDiskSpaceRequired: 33072615
Name: "Languages\Russian"; Description: "{cm:Russian}"; Languages: en; Types: custom; ExtraDiskSpaceRequired: 39371802
Name: "Languages\Spanish"; Description: "{cm:Spanish}"; Languages: en; Types: custom; ExtraDiskSpaceRequired: 39171233
Name: "Languages\English"; Description: "{cm:English}"; Languages: ru; Types: custom; ExtraDiskSpaceRequired: 38371506
Name: "Languages\Arabic"; Description: "{cm:Arabic}"; Languages: ru; Types: custom; ExtraDiskSpaceRequired: 28534834
Name: "Languages\Spanish"; Description: "{cm:Spanish}"; Languages: ru; Types: custom; ExtraDiskSpaceRequired: 39171233
Name: "Languages\Chineese_simplified"; Description: "{cm:Chineese_simplified}"; Languages: ru; Types: custom; ExtraDiskSpaceRequired: 42089623
Name: "Languages\German"; Description: "{cm:German}"; Languages: ru; Types: custom; ExtraDiskSpaceRequired: 13367187
Name: "Languages\Russian"; Description: "{cm:Russian}"; Languages: ru; Types: custom; ExtraDiskSpaceRequired: 39371802
Name: "Languages\French"; Description: "{cm:French}"; Languages: ru; Types: custom; ExtraDiskSpaceRequired: 37350210
Name: "Languages\Japanese"; Description: "{cm:Japanese}"; Languages: ru; Types: custom; ExtraDiskSpaceRequired: 33072615

28
external/gtest/LICENSE vendored Normal file
View File

@ -0,0 +1,28 @@
Copyright 2008, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

11824
external/gtest/gtest-all.cc vendored Normal file

File diff suppressed because it is too large Load Diff

14813
external/gtest/gtest.h vendored Normal file

File diff suppressed because it is too large Load Diff

22
external/miniz/LICENSE vendored Normal file
View File

@ -0,0 +1,22 @@
Copyright 2013-2014 RAD Game Tools and Valve Software
Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

7657
external/miniz/miniz.c vendored Normal file

File diff suppressed because it is too large Load Diff

1338
external/miniz/miniz.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,35 +0,0 @@
#ifdef Q_OS_LINUX
# include <locale.h>
#endif
#include <QApplication>
#include <QTranslator>
#include <qtsingleapplication.h>
#include <Manager.h>
#include <Settings.h>
int main (int argc, char *argv[]) {
QtSingleApplication a (argc, argv);
if (a.sendMessage (QString ())) {
return 0;
}
#ifdef Q_OS_LINUX
setlocale (LC_NUMERIC, "C");
#endif
a.setQuitOnLastWindowClosed (false);
a.setApplicationName (settings_values::appName);
a.setOrganizationName (settings_values::companyName);
QTranslator translator;
// Set default to english.
if (translator.load (QLocale::system (), "translation", "_", ":/translations") ||
translator.load (":/translations/translation_en")) {
a.installTranslator (&translator);
}
Manager manager;
return a.exec ();
}

16
recources.qrc Normal file
View File

@ -0,0 +1,16 @@
<RCC>
<qresource prefix="/icons">
<file alias="app.png">share/images/STIconBlue.png</file>
<file alias="st_success.png">share/images/STIconGreen.png</file>
<file alias="st_busy.png">share/images/STIconOrange.png</file>
<file alias="st_error.png">share/images/STIconRed.png</file>
<file alias="loadImages.png">share/images/loadImages.png</file>
<file alias="loadImages@2x.png">share/images/loadImages@2x.png</file>
<file alias="debug.png">share/images/debug.png</file>
<file alias="debug@2x.png">share/images/debug@2x.png</file>
</qresource>
<qresource prefix="/translations">
<file alias="screentranslator_ru.qm">share/translations/screentranslator_ru.qm</file>
<file alias="screentranslator_he.qm">share/translations/screentranslator_he.qm</file>
</qresource>
</RCC>

142
screen-translator.pro Normal file
View File

@ -0,0 +1,142 @@
QT = core gui widgets network webenginewidgets
TARGET = screen-translator
TEMPLATE = app
CONFIG += c++17
DEPS_DIR=$$(ST_DEPS_DIR)
isEmpty(DEPS_DIR):DEPS_DIR=$$PWD/../deps
INCLUDEPATH += $$DEPS_DIR/include
LIBS += -L$$DEPS_DIR/lib
LIBS += -lhunspell -lleptonica -ltesseract
win32{
LIBS += -lUser32
}
linux{
QT += x11extras
LIBS += -lX11
}
SOURCES += $$PWD/external/miniz/miniz.c
INCLUDEPATH += $$PWD/external
VER=3.3.0
DEFINES += VERSION="$$VER"
VERSION = $$VER.0
QMAKE_TARGET_COMPANY = Gres
QMAKE_TARGET_PRODUCT = Screen Translator
QMAKE_TARGET_COPYRIGHT = Copyright (c) Gres
RC_ICONS = $$PWD/share/images/icon.ico
INCLUDEPATH += src src/service src/capture src/ocr \
src/represent src/translate src/correct
HEADERS += \
src/capture/capturearea.h \
src/capture/captureareaeditor.h \
src/capture/captureareaselector.h \
src/capture/capturer.h \
src/commonmodels.h \
src/correct/corrector.h \
src/correct/correctorworker.h \
src/correct/hunspellcorrector.h \
src/languagecodes.h \
src/manager.h \
src/ocr/recognizer.h \
src/ocr/recognizerworker.h \
src/ocr/tesseract.h \
src/represent/representer.h \
src/represent/resulteditor.h \
src/represent/resultwidget.h \
src/service/apptranslator.h \
src/service/debug.h \
src/service/geometryutils.h \
src/service/globalaction.h \
src/service/keysequenceedit.h \
src/service/runatsystemstart.h \
src/service/singleapplication.h \
src/service/updates.h \
src/service/widgetstate.h \
src/settings.h \
src/settingseditor.h \
src/settingsvalidator.h \
src/stfwd.h \
src/substitutionstable.h \
src/task.h \
src/translate/translator.h \
src/translate/webpage.h \
src/translate/webpageproxy.h \
src/trayicon.h
SOURCES += \
src/capture/capturearea.cpp \
src/capture/captureareaeditor.cpp \
src/capture/captureareaselector.cpp \
src/capture/capturer.cpp \
src/commonmodels.cpp \
src/correct/corrector.cpp \
src/correct/correctorworker.cpp \
src/correct/hunspellcorrector.cpp \
src/languagecodes.cpp \
src/main.cpp \
src/manager.cpp \
src/ocr/recognizer.cpp \
src/ocr/recognizerworker.cpp \
src/ocr/tesseract.cpp \
src/represent/representer.cpp \
src/represent/resulteditor.cpp \
src/represent/resultwidget.cpp \
src/service/apptranslator.cpp \
src/service/debug.cpp \
src/service/geometryutils.cpp \
src/service/globalaction.cpp \
src/service/keysequenceedit.cpp \
src/service/runatsystemstart.cpp \
src/service/singleapplication.cpp \
src/service/updates.cpp \
src/service/widgetstate.cpp \
src/settings.cpp \
src/settingseditor.cpp \
src/settingsvalidator.cpp \
src/substitutionstable.cpp \
src/translate/translator.cpp \
src/translate/webpage.cpp \
src/translate/webpageproxy.cpp \
src/trayicon.cpp
RESOURCES += \
recources.qrc
FORMS += \
src/settingseditor.ui
OTHER_FILES += \
translators/*.js \
version.json \
updates.json
TRANSLATIONS += \
share/translations/screentranslator_ru.ts \
share/translations/screentranslator_he.ts
linux {
PREFIX = /usr
target.path = $$PREFIX/bin
shortcuts.files = $$PWD/share/screentranslator.desktop
shortcuts.path = $$PREFIX/share/applications/
pixmaps.files += $$PWD/share/images/screentranslator.png
pixmaps.path = $$PREFIX/share/icons/hicolor/128x128/apps/
INSTALLS += target shortcuts pixmaps
}
win32 {
RC_ICONS = $$PWD/share/images/icon.ico
target.path = /
INSTALLS += target
}
mac {
ICON = $$PWD/share/images/icon.icns
}

View File

@ -1,8 +0,0 @@
#!/bin/bash
source ./options.sh $@
echo "Downloading dependencies"
wget -O $DOWNLOAD_DIR/leptonica.tar.gz http://www.leptonica.com/source/leptonica-1.72.tar.gz
wget -O $DOWNLOAD_DIR/tesseract.tar.gz https://github.com/tesseract-ocr/tesseract/archive/3.04.00.tar.gz

View File

@ -1,14 +0,0 @@
#!/bin/bash
source ./options.sh $@
echo "Downloading and extracting tessdata"
wget -O $DOWNLOAD_DIR/tessdata.tar.gz https://github.com/tesseract-ocr/tessdata/archive/3.04.00.tar.gz
EXTRACT_DIR=$DOWNLOAD_DIR/tessdata
CLEAN=true
cleanupDirInNeeded $EXTRACT_DIR
tar zxf $DOWNLOAD_DIR/tessdata.tar.gz -C $EXTRACT_DIR
EXTRACTED=`ls $EXTRACT_DIR | grep tess`
mv $EXTRACT_DIR/$EXTRACTED/* $EXTRACT_DIR
rm -r $EXTRACT_DIR/$EXTRACTED

View File

@ -1,5 +0,0 @@
#!/bin/bash
sudo apt-get update -q
sudo apt-get -y install libxcb-util0-dev fakeroot libtesseract-dev libleptonica-dev qt5-qmake libqt5webkit5-dev libqt5x11extras5-dev qttools5-dev-tools g++
#sudo apt-get -y install tesseract-ocr-eng #for testing

View File

@ -1,19 +0,0 @@
#!/bin/bash
source ./options.sh $@
#cleanupDirInNeeded $WORK_DIR
echo "Running all scripts for $PLATFORM"
#./install_deps $@
#./get_tessdata.sh $@
#./get_deps.sh $@
#./make_deps.sh $@
./make_app.sh $@
if [ "$PLATFORM" == "linux" ]; then
./make_deb.sh $@
fi
if [ "$PLATFORM" == "mingw" ]; then
./make_iss.sh $@
fi
./make_sf.sh $@
echo "All scripts successfully run"

View File

@ -1,12 +0,0 @@
#!/bin/bash
source ./options.sh $@
cleanupDirInNeeded $APP_DIR
cd $APP_DIR
echo "Building app"
$QT_LRELEASE $QT_CHOOSER $SRC_DIR/ScreenTranslator.pro
$QMAKE $QT_CHOOSER "CONFIG-=debug_and_release" "CONFIG+=release" $SRC_DIR
make $JOBS

View File

@ -1,59 +0,0 @@
#!/bin/bash
source ./options.sh $@
U_VER="15.04"
for arg in ${@}; do
case "$arg" in
"15.10" ) U_VER=$arg;;
esac
done
cleanupDirInNeeded $DEB_DIR
cp -r $SRC_DISTR_DIR/deb/* $DEB_DIR
INSTALL_DIR=/opt/ScreenTranslator
function makeChangelog {
local FOUND=false
local CHANGELOG="screen-translator ($VERSION) stable; urgency=medium\n\n"
while read line; do
if [[ $line =~ [0-9]+\.[0-9]+\.[0-9]+: ]]; then #version info
if [ "$line" == "$VERSION:" ]; then
FOUND=true
continue
elif [ $FOUND == true ]; then
break;
fi
fi
if [ $FOUND == true ]; then
CHANGELOG="$CHANGELOG$line\n\n"
fi
done < $SRC_DISTR_DIR/Changelog_en.txt
CHANGELOG="$CHANGELOG--Gres <translator@gres.biz> `date -R`\n\n"
echo $CHANGELOG
}
echo "Making deb"
cp $SRC_DIR/LICENSE.md $DEB_DIR/DEBIAN/copyright
mkdir -p $DEB_DIR/usr/share/pixmaps/
cp $SRC_DIR/images/STIconBlue.png $DEB_DIR/usr/share/pixmaps/ScreenTranslator.png
mkdir -p $DEB_DIR/$INSTALL_DIR/
cp $APP_DIR/ScreenTranslator $DEB_DIR/$INSTALL_DIR/ScreenTranslator
$STRIP -s $DEB_DIR/$INSTALL_DIR/ScreenTranslator
cp -r $SRC_DIR/translators $DEB_DIR/$INSTALL_DIR/translators
VERSION=`grep "versionString" $SRC_DIR/version.json | cut -d'"' -f4`
sed "s/Version:.*\+/Version: $VERSION/" -i $DEB_DIR/DEBIAN/control
sed "s/Version=.*\+/Version=$VERSION/" -i $DEB_DIR/usr/share/applications/ScreenTranslator.desktop
SIZE=$(expr `du -bs $DEB_DIR | cut -f1` / 1024)
sed "s/Installed-Size:.*\+/Installed-Size: $SIZE/" -i $DEB_DIR/DEBIAN/control
echo -e $(makeChangelog) > $DEB_DIR/DEBIAN/changelog
if [ "$U_VER" == "15.10" ]; then
sed "s/libtesseract3/libtesseract3v5/" -i $DEB_DIR/DEBIAN/control
fi
fakeroot dpkg-deb --build $DEB_DIR $WORK_DIR/screen-translator-$VERSION-$U_VER.deb

View File

@ -1,54 +0,0 @@
#!/bin/bash
source ./options.sh $@
BUILD_LEPT=false
BUILD_TESS=false
for arg in ${@}; do
case "$arg" in
"tess" ) BUILD_TESS=true;;
"lept" ) BUILD_LEPT=true;;
esac
done
if ! $BUILD_LEPT && ! $BUILD_TESS ; then
BUILD_LEPT=true
BUILD_TESS=true
fi
cleanupDirInNeeded $DEPS_DIR
if $BUILD_LEPT ; then
echo "Building Leptonica"
tar zxf $DOWNLOAD_DIR/leptonica.tar.gz -C $DEPS_DIR
LEPT_DIR=`ls $DEPS_DIR | grep lept`
pushd .
cd $DEPS_DIR/$LEPT_DIR
$CFLAGS ./configure --prefix=$DEPS_DIR --disable-programs "$HOST_ATTR"
make $JOBS
make install
popd
fi
if $BUILD_TESS ; then
echo "Building Tesseract"
tar zxf $DOWNLOAD_DIR/tesseract.tar.gz -C $DEPS_DIR
TESS_DIR=`ls $DEPS_DIR | grep tess`
pushd .
cd $DEPS_DIR/$TESS_DIR
sed 's/vs2008/vs2010/g' -i ccutil/Makefile.in
sed 's/Windows\.h/windows\.h/g' -i opencl/openclwrapper.cpp
LIBLEPT_HEADERSDIR=$DEPS_DIR/include LIBS=-L$DEPS_DIR/lib ./configure --prefix=$DEPS_DIR --disable-tessdata-prefix "$HOST_ATTR"
make $JOBS
make install
popd
fi
if [ $PLATFORM == 'mingw' ]; then
find $DEPS_DIR -name '*.dll' -exec cp {} $DEPS_DIR/lib \;
fi
echo "Done"

View File

@ -1,49 +0,0 @@
#!/bin/bash
source ./options.sh $@
cleanupDirInNeeded $ISS_DIR
cp -r $SRC_DISTR_DIR/iss/* $ISS_DIR
CONTENT_DIR=$ISS_DIR/content
mkdir -p $CONTENT_DIR
echo "Making ISS"
TESSDATA_DIR="$DOWNLOAD_DIR/tessdata"
$(cd $ISS_DIR && ./make_tess_iss.sh $TESSDATA_DIR out="$ISS_DIR/tessdata.iss")
#setup
VERSION=`grep "versionString" $SRC_DIR/version.json | cut -d'"' -f4`
sed "s/#define MyAppVersion.*$/#define MyAppVersion \"$VERSION\"/" -i $ISS_DIR/InnoSetup.iss
cp $SRC_DIR/images/icon.ico $ISS_DIR/icon.ico
cp $SRC_DIR/LICENSE.md $ISS_DIR/LICENSE_en.md
cp $SRC_DISTR_DIR/Changelog_en.txt $ISS_DIR/Changelog_en.txt
cp $SRC_DISTR_DIR/Changelog_ru.txt $ISS_DIR/Changelog_ru.txt
#app
cp $APP_DIR/ScreenTranslator.exe $CONTENT_DIR/ScreenTranslator.exe
cp -r $SRC_DIR/translators $CONTENT_DIR/translators
#libs
QT_LIBS="Qt5WebKitWidgets Qt5Widgets Qt5WebKit Qt5Gui Qt5Network Qt5Core Qt5Sensors Qt5Positioning Qt5PrintSupport
Qt5OpenGL Qt5Sql Qt5Quick Qt5Qml Qt5WebChannel Qt5Multimedia Qt5MultimediaWidgets"
for i in $QT_LIBS; do
cp -d $QT_LIB_DIR/$i.dll $CONTENT_DIR
done
mkdir -p $CONTENT_DIR/platforms
cp -d $QT_LIB_DIR/../plugins/platforms/qwindows.dll $CONTENT_DIR/platforms
MINGW_LIBS="libgcc_s_sjlj-1 libstdc++-6 icuin55 icuuc55 icudt55 libwinpthread-1 ssleay32 libeay32"
for i in $MINGW_LIBS; do
cp -d $MINGW_DIR/lib/$i.dll $CONTENT_DIR
done
cp -d $DEPS_DIR/lib/liblept*.dll $CONTENT_DIR
cp -d $DEPS_DIR/lib/libtesseract*.dll $CONTENT_DIR
find $CONTENT_DIR -name '*.exe' -exec $STRIP -s {} \;
find $CONTENT_DIR -name '*.dll' -exec $STRIP -s {} \;
cd $ISS_DIR
wine "C:\Program Files\Inno Setup 5\iscc.exe" "InnoSetup.iss"

View File

@ -1,21 +0,0 @@
#!/bin/bash
source ./options.sh $@
cleanupDirInNeeded $SF_DIR
echo "Making SF"
function format {
local FILE=$1
sed "s/\(Changes\)/#\1/g" -i $FILE
sed "s/\(Изменения\)/#\1/g" -i $FILE
sed "s/\([0-9]\+\.[0-9]\+\.[0-9]\+:\)/##\1/g" -i $FILE
sed "s/+\s/* /g" -i $FILE
sed "s/-\s/* /g" -i $FILE
}
cp -f $SRC_DISTR_DIR/Changelog_en.txt $SF_DIR/readme.md
format $SF_DIR/readme.md
cp -f $SRC_DISTR_DIR/Changelog_ru.txt $SF_DIR/readme_ru.md
iconv -f cp1251 -t utf8 $SF_DIR/readme_ru.md -o $SF_DIR/readme_ru.md.u
mv $SF_DIR/readme_ru.md.u $SF_DIR/readme_ru.md
format $SF_DIR/readme_ru.md

View File

@ -1,58 +0,0 @@
#!/bin/bash
set -e
PLATFORM=linux
CLEAN=false
JOBS=""
QT_CHOOSER="-qt=qt5"
QMAKE=qmake
QT_LRELEASE=lrelease
QT_LIB_DIR=/usr/lib/x86_64-linux-gnu
STRIP=strip
for arg in ${@}; do
case "$arg" in
"linux" ) PLATFORM=linux;;
"mingw" ) PLATFORM=mingw;;
"clean" ) CLEAN=true;;
"-j"* ) JOBS=$arg;;
*"qmake" ) QMAKE=$arg
QT_LRELEASE=`readlink -e $(dirname $arg)/lrelease`
QT_LIB_DIR=`readlink -e $(dirname $arg)/../lib`
QT_CHOOSER=""
;;
esac
done
WORK_DIR=../../build/$PLATFORM
MINGW_DIR=/opt/mingw-4.9.3/mingw-w64-i686
if [ "$PLATFORM" == "mingw" ]; then
QT_LIB_DIR=`readlink -e $QT_LIB_DIR/../bin`
HOST=i686-w64-mingw32
HOST_ATTR="--host=$HOST"
STRIP=$HOST-strip
export PATH="$MINGW_DIR/bin:$PATH"
COMPILERS="CC=\"${HOST}-gcc\" AR=\"${HOST}-ar\" RANLIB=\"${HOST}-ranlib\""
fi
WORK_DIR=`readlink -m $WORK_DIR`
DEPS_DIR=`readlink -m $WORK_DIR/deps`
APP_DIR=`readlink -m $WORK_DIR/app`
DEB_DIR=`readlink -m $WORK_DIR/deb`
ISS_DIR=`readlink -m $WORK_DIR/iss`
SF_DIR=`readlink -m $WORK_DIR/sf`
DOWNLOAD_DIR=`readlink -m ../../`
SRC_DIR=`readlink -e ..`
SRC_DISTR_DIR=$SRC_DIR/distr
mkdir -p $WORK_DIR
function cleanupDirInNeeded {
local DIR=$1
if [[ "$CLEAN" == "true" && -d "$DIR" ]]; then
rm -rf $DIR
fi
mkdir -p $DIR
}

View File

@ -1,61 +0,0 @@
@echo off
set SELF_PATH=%~dp0
call %SELF_PATH%\env.bat
::build
rmdir /q /s build
set ROOT=%SELF_PATH%\..\..
lrelease %ROOT%\ScreenTranslator.pro
mkdir build
cd build
qmake INCLUDEPATH+=%cd%\..\installed\include LIBS+=-L%cd%\..\installed\bin LIBS+=-L%cd%\..\installed\lib %ROOT%
nmake
cd ..
if %errorlevel% neq 0 exit /b %errorlevel%
::pack
rmdir /q /s iss
mkdir iss
copy /Y %ROOT%\distr\iss\* iss
copy /Y %ROOT%\distr\Changelog_en.txt iss\
copy /Y %ROOT%\distr\Changelog_ru.txt iss\
copy /Y %ROOT%\LICENSE.md iss\LICENSE_en.md
copy /Y %ROOT%\images\icon.ico iss\icon.ico
mkdir iss\content
copy /Y build\release\ScreenTranslator.exe iss\content\ScreenTranslator.exe
copy /Y installed\bin\*.dll iss\content
copy /Y c:\OpenSSL-Win32\bin\libeay32.dll iss\content
copy /Y c:\OpenSSL-Win32\bin\ssleay32.dll iss\content
mkdir iss\content\translations
copy /Y %ROOT%\translations\*.qm iss\content\translations
mkdir iss\content\translators
copy /Y %ROOT%\translators\* iss\content\translators
windeployqt --release iss\content\ScreenTranslator.exe
for /f "delims=" %%i in ('findstr versionString %ROOT%\version.json') do set VERSION_LINE=%%i
set UNQUOTED=%VERSION_LINE:"='%
for /f "tokens=4 delims='" %%i in ("%UNQUOTED%") do set VERSION=%%i
echo #define MyAppVersion "%VERSION%" > iss\defines.iss
cd iss
iscc.exe InnoSetup.iss
cd ..
if "%WITH_TESSDATA%" == "" goto end
mkdir iss\tessdata
copy /Y download\tessdata\* iss\tessdata
cd iss
iscc.exe InnoSetupWithTessdata.iss
cd ..
:end

View File

@ -1,33 +0,0 @@
@echo off
set PATH=c:\Program Files (x86)\WinSCP\;%PATH%
set SELF_PATH=%~dp0
set ROOT=%SELF_PATH%\..\..
for /f "delims=" %%i in ('findstr versionString %ROOT%\version.json') do set VERSION_LINE=%%i
set UNQUOTED=%VERSION_LINE:"='%
for /f "tokens=4 delims='" %%i in ("%UNQUOTED%") do set VERSION=%%i
for /f "delims=" %%i in ('dir /b screen-translator-online*.exe') do set online=%%i
for /f "delims=" %%i in ('dir /b screen-translator-offline*.exe') do set offline=%%i
winscp.com /keygen %SELF_PATH%\sf_key /output=key.ppk
set folder="/home/frs/project/screen-translator/bin/v%VERSION%"
set bin_folder="/home/frs/project/screen-translator/bin"
winscp.com /command "open sftp://onemoregres@frs.sourceforge.net/ -privatekey=key.ppk -hostkey=*" ^
"mkdir %folder%" ^
"put %online% %folder%/%online%" ^
"put %offline% %folder%/%offline%" ^
"put %ROOT%\distr\Changelog_ru.txt %bin_folder%/readme_ru.md" ^
"put %ROOT%\distr\Changelog_en.txt %bin_folder%/readme.md" ^
"exit"
set url="https://sourceforge.net/projects/screen-translator/files/bin/v%VERSION%/%online%"
curl --insecure -H "Accept: application/json" -X PUT -d "default=windows" -d "api_key=%sf_api%" %url%
set url="https://sourceforge.net/projects/screen-translator/files/bin/v%VERSION%/%offline%"
curl --insecure -H "Accept: application/json" -X PUT -d "default=windows" -d "api_key=%sf_api%" %url%

View File

@ -1,19 +0,0 @@
@echo off
if "%ARCH%" == "" set ARCH=x86
if /i %ARCH% == x86 goto x86
if /i %ARCH% == x64 goto x64
goto end
:x64
call "c:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" amd64
set PATH=c:\Qt\5.5\msvc2013_64\bin\;c:\Program Files (x86)\NSIS\;C:\Program Files (x86)\Inno Setup 5;C:\Program Files\CMake\bin;%PATH%
goto end
:x86
call "c:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x86
set PATH=c:\Qt\5.5\msvc2013\bin\;c:\Program Files (x86)\NSIS\;C:\Program Files (x86)\Inno Setup 5;C:\Program Files\CMake\bin;%PATH%
goto end
:end

View File

@ -1,111 +0,0 @@
@echo off
set SELF_PATH=%~dp0
call %SELF_PATH%\env.bat
rem choco install curl cmake
mkdir download
if "%WITH_TESSDATA%" == "" goto libs
echo "Downloading tessdata"
mkdir download\tessdata
cd download\tessdata
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/ara.cube.bigrams
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/ara.cube.fold
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/ara.cube.lm
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/ara.cube.nn
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/ara.cube.params
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/ara.cube.size
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/ara.cube.word-freq
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/ara.traineddata
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/chi_sim.traineddata
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/deu.traineddata
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/eng.cube.bigrams
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/eng.cube.fold
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/eng.cube.lm
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/eng.cube.nn
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/eng.cube.params
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/eng.cube.size
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/eng.cube.word-freq
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/eng.tesseract_cube.nn
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/eng.traineddata
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/fra.cube.bigrams
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/fra.cube.fold
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/fra.cube.lm
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/fra.cube.nn
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/fra.cube.params
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/fra.cube.size
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/fra.cube.word-freq
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/fra.tesseract_cube.nn
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/fra.traineddata
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/frk.traineddata
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/frm.traineddata
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/jpn.traineddata
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/rus.cube.fold
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/rus.cube.lm
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/rus.cube.nn
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/rus.cube.params
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/rus.cube.size
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/rus.cube.word-freq
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/rus.traineddata
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/spa.cube.bigrams
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/spa.cube.fold
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/spa.cube.lm
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/spa.cube.nn
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/spa.cube.params
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/spa.cube.size
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/spa.cube.word-freq
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/spa.traineddata
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/spa_old.traineddata
cd ..\..
:libs
if "%CLEAR_CACHE%" == "" goto build-libs
echo "Clearing cache"
rmdir /s /q leptonica
rmdir /s /q leptonica-build
rmdir /s /q tesseract
rmdir /s /q leptonica-build
rmdir /s /q installed
:build-libs
if exist installed\bin\tesseract*.dll goto end
echo "Downloading dependencies"
if not exist download\leptonica.zip (
curl -fsSLk -o download\leptonica.zip https://github.com/DanBloomberg/leptonica/archive/1.74.4.zip
)
if not exist download\tesseract.zip (
curl -fsSLk -o download\tesseract.zip https://github.com/tesseract-Ocr/tesseract/archive/3.05.01.zip
)
echo "Building dependencies"
unzip -qq download\leptonica.zip
move leptonica* leptonica
mkdir leptonica-build
cd leptonica-build
cmake -DCMAKE_BUILD_TYPE=Release -DTARGET_CPU=%ARCH% -DCMAKE_INSTALL_PREFIX=..\installed ..\leptonica
cmake --build . --config Release
cmake --build . --config Release --target install
cd ..
copy /y /b installed\lib\leptonica*.lib installed\lib\lept.lib
if %errorlevel% neq 0 exit /b %errorlevel%
unzip -qq download\tesseract.zip
move tesseract* tesseract
mkdir tesseract-build
cd tesseract-build
cmake -DCMAKE_BUILD_TYPE=Release -DTARGET_CPU=%ARCH% -DCMAKE_INSTALL_PREFIX=..\installed -DCMAKE_PREFIX_PATH=..\installed ..\tesseract
cmake --build . --config Release
cmake --build . --config Release --target install
cd ..
copy /y /b installed\lib\tesseract*.lib installed\lib\tesseract.lib
if %errorlevel% neq 0 exit /b %errorlevel%
:end

Binary file not shown.

125
share/Changelog_en.md Normal file
View File

@ -0,0 +1,125 @@
# Changes
## 3.3.0
* Use single tesseract library (not optimized and compatible versions)
* Improved recognition
## 3.2.3
* Fixed translators order persistance
* Fixed multi-monitor support
* Improves result representation near monitor borders
* Updated recognition library
## 3.2.2
* Disabled hotkeys with several consecutive combinations
* Added the ability to use some service buttons for hotkeys
* Fixed multiple monitors support if the main one is not at the top left
* Automatic selection of the supported version of tesseract
## 3.2.1
* Fixed incorrect update install
## 3.2.0
* Improved vertical text recognition
* Improved incorrect settings notification
* Improved update process
## 3.1.2
* Fixed manually corrected text translation
## 3.1.1
* Fixed portable mode detection
## 3.1.0
* Added ability to choose a recognition version from the program
* Added some error messages about misconfiguration
* Fixed some errors
## 3.0.1
* Fixed some errors
* Added `compatible` version (fixes crash during recognition)
## 3.0.0
* Changed distribution model: a zip archive instead of an installer
* Required resources can now be downloaded from the program
* Added ability to capture images in saved areas (reuse selection)
* Many interface changes
* Updated libraries versions
## 2.0.2
* Added force translator rotation option.
## 2.0.1
* Fixed installer.
## 2.0.0
* Added a version for linux.
* Added support for multiple monitors.
* Added ability of recognition without translation.
* Added ability to recapture from old image.
* Added ability to recapture without closing capture window.
* Added ability to re-recognize other language.
* Added ability to display intermediate result when error occured.
* Added support for different translation services.
* Added ability to copy image to clipboard.
* Added ability to edit recognized text.
* Added ability to automatically correct common recognition mistakes.
* Added ability to use a proxy.
* Added ability to swap translation and recognition languages.
* Updated icons.
* Show progress on icon.
* Added ability to automatically update.
## 1.2.3
* Fixed possible crash.
* Added version information and some error messages.
## 1.2.2
* Added alternative translation source.
## 1.2.1
* Fixed the bug with the lack of translation.
* Fixed the bug with the use of language recognition by default when you select another one in OCR region selection mode.
## 1.2.0
* Changed installer.
* Added all available languages for recognition.
* Added ability to specify language when selecting the field of recognition using right click.
* Human readable language names.
* Reduced memory usage.
* Updated libraries.
## 1.1.3
* Added library libgcc_s_dw2-1.dll.
* Updated libraries.
## 1.1.2
* If you specify in the settings the path to tessdata characters "\" or "/" at the end of the path are no longer required.
## 1.1.1
* Fixed an issue with incorrect window size when display results.
## 1.1.0
* Displays the result in the window, along with the picture.
* Context menu expanded. Added buttons display the last result and copy it to the clipboard.

125
share/Changelog_ru.md Normal file
View File

@ -0,0 +1,125 @@
# Изменения
## 3.3.0
* Использование единой библиотеки распознавания (без оптимизированной и совместимой версий)
* Улучшено распознавание
## 3.2.3
* Исправлено сохранение порядка переводчиков в настройках
* Исправлена работа с несколькими мониторами
* Улучшено отображение результата на границе монитора
* Обновлена версия библиотеки распознавания
## 3.2.2
* Исключено задание горячих клавиш из нескольких последовательных комбинаций
* Добавлена возможность использования некоторых служебных кнопок для горячих клавиш
* Исправлена работа с несколькими мониторами, если главный находится не слева-вверху
* Автоматический выбор поддерживаемой версии tesseract
## 3.2.1
* Исправлена некорректная установка обновления
## 3.2.0
* Улучшено распознавание вертикального текста
* Улучшено информирование о некорректных настройках
* Упрощена работа с обновлениями
## 3.1.2
* Исправлен перевод исправленного вручную текста
## 3.1.1
* Исправлено определение работы в Portable режиме
## 3.1.0
* Добавлена возможность выбора версии библиотеки распознавания из программы
* Добавлены сообщения об ошибках при неправильной настройке
* Исправлены некоторые ошибки
## 3.0.1
* Исправлены некоторые ошибки
* Добавлена `совместимая` версия (исправляет падение при распознавании)
## 3.0.0
* Изменен порядок распространения: удалены установщики. Для установки достаточно распаковать папку нужного дистрибутива в желаемое место и запустить программу
* Необходимые ресурсы скачиваются из программы, а не вручную или через установщик
* Добавлена возможность захвата изображений в заранее подготовленных областях
* Много мелких изменений в интерфейсе
* Обновлены версии библиотек
## 2.0.2
* Добавлена настройка принудительной смены переводчиков.
## 2.0.1
* Исправлен установщик.
## 2.0.0
* Добавлена версия под linux.
* Добавлена поддержка нескольких мониторов.
* Добавлена возможность распознание без перевода.
* Добавлена возможность вызова старого рисунка для выделения.
* Добавлена возможность повторного выделения без закрытия окна захвата.
* Добавлена возможность повторного распознания на другом языке.
* Добавлена возможность отображения промежуточного результата при ошибке перевода.
* Добавлена поддержка разных сервисов перевода.
* Добавлена возможность копирования изображения в буфер.
* Добавлена возможность редакции распознанного текста.
* Добавлена возможность автоматической коррекции частых ошибок распознавания.
* Добавлена возможность использования прокси.
* Добавлена возможность разовой смена языка перевода и распознавания.
* Обновлены иконки.
* Добавлено отображение статуса работы на иконке.
* Добавлена возможность автоматического обновления.
## 1.2.3
* Устранена возможная причина падения.
* Добавлена информация о версии и некоторые сообщения об ошибках.
## 1.2.2
* Добавлен альтернативный источник перевода.
## 1.2.1
* Устранена ошибка отсутствия перевода.
* Устранена ошибка использования языка распознавания по умолчанию при выборе другого в окне выделения области распознавания.
## 1.2.0
* Изменен установщик.
* В установщик добавлены все доступные языки для распознавания.
* Добавлена возможность указания языка при выборе области распознавания при помощи выделения с правым кликом.
* Человекочитаемые названия языков.
* Уменьшено потребление памяти.
* Обновлены библиотеки.
## 1.1.3
* В установщик добавлена библиотека libgcc_s_dw2-1.dll.
* Обновлены библиотеки.
## 1.1.2
* При задании в настройках пути к tessdata символы «\» или «/» в конце пути теперь не обязательны.
## 1.1.1
* Пофиксен баг с неверным размером окна отображения результатов.
## 1.1.0
* Отображение результата в окошке, вместе с картинкой.
* Контекстное меню расширено. Добавлены кнопки отображения последнего результата и копирования его в буфер обмена.

65
share/ci/appimage.py Normal file
View File

@ -0,0 +1,65 @@
import common as c
from config import *
import os
import sys
import subprocess as sub
import shutil
from glob import glob
if len(sys.argv) > 1 and sys.argv[1] == 'glibc_version': # subcommand
sub.run('ldd --version | head -n 1 | grep -Po "\\d\\.\\d\\d"', shell=True)
exit(0)
tag = os.environ.get('TAG', '')
artifact_name = '{}-{}{}.AppImage'.format(app_name, app_version, tag)
if len(sys.argv) > 1 and sys.argv[1] == 'artifact_name': # subcommand
c.print(artifact_name)
exit(0)
artifact_path = os.path.abspath(artifact_name)
c.print('>> Making appimage')
base_url = 'https://github.com/probonopd/linuxdeployqt/releases/download'
continuous_url = base_url + '/continuous/linuxdeployqt-continuous-x86_64.AppImage'
tagged_url = base_url + '/6/linuxdeployqt-6-x86_64.AppImage'
linuxdeployqt_url = continuous_url
linuxdeployqt_original = os.path.basename(linuxdeployqt_url)
c.download(linuxdeployqt_url, linuxdeployqt_original)
c.run('chmod a+x {}'.format(linuxdeployqt_original))
linuxdeployqt_bin = os.path.abspath('linuxdeployqt')
c.symlink(linuxdeployqt_original, linuxdeployqt_bin)
os.chdir(build_dir)
install_dir = os.path.abspath('appdir')
c.recreate_dir(install_dir)
c.run('make INSTALL_ROOT={0} DESTDIR={0} install'.format(install_dir))
if c.is_inside_docker():
c.run('{} --appimage-extract'.format(linuxdeployqt_bin))
linuxdeployqt_bin = os.path.abspath('squashfs-root/AppRun')
os.environ['LD_LIBRARY_PATH'] = dependencies_dir + '/lib'
os.environ['VERSION'] = app_version
# debug flags: -unsupported-bundle-everything -unsupported-allow-new-glibc
flags = '' if os.getenv("DEBUG") is None else '-unsupported-allow-new-glibc'
additional_files = glob(ssl_dir + '/lib/lib*.so.*') + \
glob('/usr/lib/x86_64-linux-gnu/nss/*')
out_lib_dir = install_dir + '/usr/lib'
os.makedirs(out_lib_dir, exist_ok=True)
for f in additional_files:
c.print('>> Copying {} to {}'.format(f, out_lib_dir))
shutil.copy(f, out_lib_dir)
c.ensure_got_path('{}/usr/share/doc/libc6/copyright'.format(install_dir))
c.run('{} {}/usr/share/applications/*.desktop {} -appimage -qmake={}/bin/qmake'.format(
linuxdeployqt_bin, install_dir, flags, qt_dir))
c.run('mv {}-{}*.AppImage "{}"'.format(app_name, app_version, artifact_path))
bin_path = install_dir + '/usr/bin/' + bin_name
c.print('>> Md5 {} {}'.format(bin_path, c.md5sum(bin_path)))

26
share/ci/build.py Normal file
View File

@ -0,0 +1,26 @@
import common as c
from config import *
import os
import platform
c.print('>> Building {} on {}'.format(app_name, os_name))
c.add_to_path(os.path.abspath(qt_dir + '/bin'))
os.environ['ST_DEPS_DIR'] = dependencies_dir
if platform.system() == "Windows":
env_cmd = c.get_msvc_env_cmd(bitness=bitness, msvc_version=msvc_version)
c.apply_cmd_env(env_cmd)
c.recreate_dir(build_dir)
os.chdir(build_dir)
c.run('lupdate "{}"'.format(pro_file))
c.run('lrelease "{}"'.format(pro_file))
c.set_make_threaded()
build_type_flag = 'debug' if build_type == 'debug' else 'release'
qmake_flags = os.environ.get('QMAKE_FLAGS','') + ' CONFIG+=' + build_type_flag
c.run('qmake {} "{}"'.format(qmake_flags, pro_file))
make_cmd = c.get_make_cmd()
c.run(make_cmd)

213
share/ci/common.py Normal file
View File

@ -0,0 +1,213 @@
import os
import subprocess as sub
import urllib.request
from shutil import which
import zipfile
import tarfile
import functools
import shutil
import multiprocessing
import platform
import re
import ast
import hashlib
print = functools.partial(print, flush=True)
def run(cmd, capture_output=False, silent=False):
print('>> Running', cmd)
if capture_output:
result = sub.run(cmd, check=True, shell=True, universal_newlines=True,
stdout=sub.PIPE, stderr=sub.STDOUT)
if not silent:
print(result.stdout)
else:
if not silent:
result = sub.run(cmd, check=True, shell=True)
else:
result = sub.run(cmd, check=True, shell=True,
stdout=sub.DEVNULL, stderr=sub.DEVNULL)
return result
def download(url, out, force=False):
print('>> Downloading', url, 'as', out)
if not force and os.path.exists(out):
print('>>', out, 'already exists')
return
out_path = os.path.dirname(out)
if len(out_path) > 0:
os.makedirs(out_path, exist_ok=True)
urllib.request.urlretrieve(url, out)
def extract(src, dest):
abs_path = os.path.abspath(src)
print('>> Extracting', abs_path, 'to', dest)
if len(dest) > 0:
os.makedirs(dest, exist_ok=True)
if which('cmake'):
out = run('cmake -E tar t "{}"'.format(abs_path),
capture_output=True, silent=True)
files = out.stdout.split('\n')
already_exist = True
for file in files:
if not os.path.exists(os.path.join(dest, file)):
already_exist = False
break
if already_exist:
print('>> All files already exist')
return
sub.run('cmake -E tar xvf "{}"'.format(abs_path),
check=True, shell=True, cwd=dest)
return
is_tar_smth = src.endswith('.tar', 0, src.rfind('.'))
if which('7z'):
sub.run('7z x "{}" -o"{}"'.format(abs_path, dest),
check=True, shell=True, input=b'S\n')
if is_tar_smth:
inner_name = abs_path[:abs_path.rfind('.')]
sub.run('7z x "{}" -o"{}"'.format(inner_name, dest),
check=True, shell=True, input=b'S\n')
return
if src.endswith('.tar') or is_tar_smth:
path = abs_path if platform.system() != "Windows" else os.path.relpath(abs_path)
if which('tar'):
sub.run('tar xf "{}" --keep-newer-files -C "{}"'.format(path, dest),
check=True, shell=True)
return
raise RuntimeError('No archiver to extract {} file'.format(src))
def get_folder_files(path):
result = []
for root, _, files in os.walk(path):
for file in files:
result.append(os.path.join(root, file))
return result
def get_archive_top_dir(path):
"""Return first top level folder name in given archive or raises RuntimeError"""
with tarfile.open(path) as tar:
first = tar.next()
if not first is None:
result = os.path.dirname(first.path)
if len(result) == 0:
result = first.path
return result
raise RuntimeError('Failed to open file or empty archive ' + path)
def archive(files, out):
print('>> Archiving', files, 'into', out)
if out.endswith('.zip'):
arc = zipfile.ZipFile(out, 'w', zipfile.ZIP_DEFLATED)
for f in files:
arc.write(f)
arc.close()
return
if out.endswith('.tar.gz'):
arc = tarfile.open(out, 'w|gz')
for f in files:
arc.add(f)
arc.close()
return
raise RuntimeError('No archiver to create {} file'.format(out))
def symlink(src, dest):
print('>> Creating symlink', src, '=>', dest)
norm_src = os.path.normcase(src)
norm_dest = os.path.normcase(dest)
if os.path.lexists(norm_dest):
os.remove(norm_dest)
os.symlink(norm_src, norm_dest,
target_is_directory=os.path.isdir(norm_src))
def recreate_dir(path):
shutil.rmtree(path, ignore_errors=True)
os.mkdir(path)
def add_to_path(entry, prepend=True):
path_separator = ';' if platform.system() == "Windows" else ':'
os.environ['PATH'] = entry + path_separator + os.environ['PATH']
def get_msvc_env_cmd(bitness='64', msvc_version=''):
"""Return environment setup command for running msvc compiler for current platform"""
if platform.system() != "Windows":
return None
env_script = msvc_version + '/VC/Auxiliary/Build/vcvars{}.bat'.format(bitness)
return '"' + env_script + '"'
def get_cmake_arch_args(bitness='64'):
if platform.system() != "Windows":
return ''
return '-A {}'.format('Win32' if bitness == '32' else 'x64')
def get_make_cmd():
"""Return `make` command for current platform"""
return 'nmake' if platform.system() == "Windows" else 'make'
def set_make_threaded():
"""Adjust environment to run threaded make command"""
if platform.system() == "Windows":
os.environ['CL'] = '/MP'
else:
os.environ['MAKEFLAGS'] = '-j{}'.format(multiprocessing.cpu_count())
def is_inside_docker():
""" Return True if running in a Docker container """
with open('/proc/1/cgroup', 'rt') as f:
return 'docker' in f.read()
def ensure_got_path(path):
os.makedirs(path, exist_ok=True)
def apply_cmd_env(cmd):
"""Run cmd and apply its modified environment"""
print('>> Applying env after', cmd)
separator = 'env follows'
script = 'import os,sys;sys.stdout.buffer.write(str(dict(os.environ)).encode(\\\"utf-8\\\"))'
env = sub.run('{} && echo "{}" && python -c "{}"'.format(cmd, separator, script),
shell=True, stdout=sub.PIPE, encoding='utf-8')
stringed = env.stdout[env.stdout.index(separator) + len(separator) + 1:]
parsed = ast.literal_eval(stringed)
for key, value in parsed.items():
if key in os.environ and os.environ[key] == value:
continue
if key in os.environ:
print('>>> Changing env', key, '\nfrom\n',
os.environ[key], '\nto\n', value)
os.environ[key] = value
def md5sum(path):
if not os.path.exists(path):
return ''
md5 = hashlib.md5()
with open(path, 'rb') as f:
md5.update(f.read())
return md5.hexdigest()
return ''

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