Finish 2.0.0

This commit is contained in:
Gres 2015-11-06 23:21:01 +03:00
commit 382db2f810
96 changed files with 10173 additions and 2019 deletions

2
.gitignore vendored
View File

@ -6,3 +6,5 @@
*.exe
distr/content/
*.tar.gz

19
.travis.yml Normal file
View File

@ -0,0 +1,19 @@
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
email:
on_success: change
on_failure: change

View File

@ -0,0 +1,204 @@
/****************************************************************************
**
** 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

@ -0,0 +1,77 @@
/****************************************************************************
**
** 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

@ -0,0 +1,193 @@
/****************************************************************************
**
** 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

@ -0,0 +1,97 @@
/****************************************************************************
**
** 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

@ -0,0 +1,115 @@
/****************************************************************************
**
** 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

@ -0,0 +1,211 @@
/****************************************************************************
**
** 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

@ -0,0 +1,347 @@
/****************************************************************************
**
** 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

@ -0,0 +1,105 @@
/****************************************************************************
**
** 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

@ -0,0 +1,17 @@
#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

@ -0,0 +1,149 @@
/****************************************************************************
**
** 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

@ -0,0 +1,71 @@
/****************************************************************************
**
** 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

@ -0,0 +1,10 @@
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,92 +1,192 @@
#include "GlobalActionHelper.h"
#include <qt_windows.h>
#include <QDebug>
#include <QApplication>
QHash<QPair<quint32, quint32>, QAction*> GlobalActionHelper::actions_;
QHash<QPair<quint32, quint32>, QAction *> GlobalActionHelper::actions_;
bool GlobalActionHelper::nativeEventFilter(const QByteArray& eventType,
void* message, long* result)
{
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);
MSG* msg = static_cast<MSG*>(message);
if (msg->message == WM_HOTKEY)
{
const quint32 keycode = HIWORD(msg->lParam);
const quint32 modifiers = LOWORD(msg->lParam);
QAction* action = actions_.value (qMakePair (keycode, modifiers));
Q_CHECK_PTR (action);
action->activate (QAction::Trigger);
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;
}
void GlobalActionHelper::init()
{
qApp->installNativeEventFilter (new GlobalActionHelper);
quint32 GlobalActionHelper::nativeKeycode (Qt::Key key) {
Display *display = QX11Info::display ();
KeySym keySym = XStringToKeysym (qPrintable (QKeySequence (key).toString ()));
return XKeysymToKeycode (display, keySym);
}
bool GlobalActionHelper::makeGlobal(QAction* action)
{
QKeySequence hotKey = action->shortcut ();
if (hotKey.isEmpty ())
{
return true;
quint32 GlobalActionHelper::nativeModifiers (Qt::KeyboardModifiers modifiers) {
quint32 native = 0;
if (modifiers & Qt::ShiftModifier) {
native |= ShiftMask;
}
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;
if (modifiers & Qt::ControlModifier) {
native |= ControlMask;
}
if (modifiers & Qt::AltModifier) {
native |= Mod1Mask;
}
if (modifiers & Qt::MetaModifier) {
native |= Mod4Mask;
}
return native;
}
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;
#elif defined(Q_OS_WIN)
# include <qt_windows.h>
bool GlobalActionHelper::registerHotKey (quint32 nativeKey, quint32 nativeMods) {
return RegisterHotKey (0, nativeMods ^ nativeKey, nativeMods, nativeKey);
}
quint32 GlobalActionHelper::nativeKeycode(Qt::Key key)
{
switch (key)
{
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:
@ -191,9 +291,6 @@ quint32 GlobalActionHelper::nativeKeycode(Qt::Key key)
return VK_MEDIA_PLAY_PAUSE;
case Qt::Key_MediaStop:
return VK_MEDIA_STOP;
// couldn't find those in VK_*
//case Qt::Key_MediaLast:
//case Qt::Key_MediaRecord:
case Qt::Key_VolumeDown:
return VK_VOLUME_DOWN;
case Qt::Key_VolumeUp:
@ -248,29 +345,23 @@ quint32 GlobalActionHelper::nativeKeycode(Qt::Key key)
}
}
quint32 GlobalActionHelper::nativeModifiers(Qt::KeyboardModifiers modifiers)
{
quint32 GlobalActionHelper::nativeModifiers (Qt::KeyboardModifiers modifiers) {
// MOD_ALT, MOD_CONTROL, (MOD_KEYUP), MOD_SHIFT, MOD_WIN
quint32 native = 0;
if (modifiers & Qt::ShiftModifier)
if (modifiers & Qt::ShiftModifier) {
native |= MOD_SHIFT;
if (modifiers & Qt::ControlModifier)
}
if (modifiers & Qt::ControlModifier) {
native |= MOD_CONTROL;
if (modifiers & Qt::AltModifier)
}
if (modifiers & Qt::AltModifier) {
native |= MOD_ALT;
if (modifiers & Qt::MetaModifier)
}
if (modifiers & Qt::MetaModifier) {
native |= MOD_WIN;
}
//if (modifiers & Qt::KeypadModifier)
//if (modifiers & Qt::GroupSwitchModifier)
return native;
}
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);
}
#endif

View File

@ -6,23 +6,23 @@
#include <QAbstractNativeEventFilter>
#include <QAction>
class GlobalActionHelper : public QAbstractNativeEventFilter
{
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);
static bool makeGlobal (QAction *action);
static bool removeGlobal (QAction *action);
private:
static QHash<QPair<quint32, quint32>, QAction*> actions_;
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);
};

View File

@ -1,93 +0,0 @@
#include <QWebView>
#include <QWebFrame>
#include <QWebElement>
#include <QSettings>
#include <QNetworkReply>
#include <QTimer>
#include "GoogleWebTranslator.h"
#include "Settings.h"
#include "StAssert.h"
GoogleWebTranslator::GoogleWebTranslator()
: QObject (), view_ (new QWebView),
isLoadFinished_ (true), isTranslationFinished_ (false) {
view_->settings()->setAttribute(QWebSettings::AutoLoadImages, false);
connect (view_, SIGNAL (loadStarted()), this, SLOT (loadStarted()));
connect (view_, SIGNAL (loadFinished(bool)), this, SLOT (loadFinished(bool)));
connect (view_->page()->networkAccessManager(), SIGNAL (finished(QNetworkReply*)),
this, SLOT(replyFinished(QNetworkReply*)));
applySettings ();
}
GoogleWebTranslator::~GoogleWebTranslator() {
delete view_;
}
void GoogleWebTranslator::translate(ProcessingItem item) {
queue_.push_back (item);
if (isLoadFinished_) {
load (item);
}
}
void GoogleWebTranslator::applySettings(){
QSettings settings;
settings.beginGroup (settings_names::translationGroup);
translationLanguage_ = settings.value (settings_names::translationLanguage,
settings_values::translationLanguage).toString ();
}
void GoogleWebTranslator::loadStarted() {
isLoadFinished_ = false;
isTranslationFinished_ = false;
}
void GoogleWebTranslator::loadFinished(bool ok) {
isLoadFinished_ = true;
if (ok && !isTranslationFinished_) {
return;
}
if (!queue_.isEmpty()) {
ProcessingItem item = queue_.front();
queue_.pop_front();
if (ok) {
QWebElementCollection result = view_->page()->mainFrame()->findAllElements("#result_box > span");
item.translated = "";
foreach (const QWebElement& element, result) {
item.translated += element.toInnerXml() + " ";
}
emit translated(item, !item.translated.isEmpty());
}
else {
emit translated (item, false);
}
}
if (!queue_.isEmpty()) {
load (queue_.front());
}
}
void GoogleWebTranslator::replyFinished(QNetworkReply *reply)
{
if (reply->url().toString().contains ("/translate_a/single")) {
isTranslationFinished_ = true;
if (isLoadFinished_) {
QTimer::singleShot(2000, this, SLOT(loadFinished()));
}
}
}
void GoogleWebTranslator::load(const ProcessingItem &item) {
ST_ASSERT (!item.recognized.isEmpty ());
if (translationLanguage_.isEmpty ()) {
emit error (tr ("Неверные парметры для перевода."));
return;
}
QUrl url (QString ("https://translate.google.com/#auto/%1/%2").arg(translationLanguage_, item.recognized));
view_->setUrl(url);
}

View File

@ -1,43 +0,0 @@
#ifndef GOOGLEWEBTRANSLATOR_H
#define GOOGLEWEBTRANSLATOR_H
#include <QObject>
#include "ProcessingItem.h"
class QWebView;
class QUrl;
class QNetworkReply;
class GoogleWebTranslator : public QObject
{
Q_OBJECT
public:
GoogleWebTranslator();
~GoogleWebTranslator();
signals:
void translated (ProcessingItem item, bool success);
void error (QString text);
public slots:
void translate (ProcessingItem item);
void applySettings ();
private slots:
void loadStarted ();
void loadFinished(bool ok=true);
void replyFinished(QNetworkReply * reply);
private:
void load (const ProcessingItem& item);
private:
QVector<ProcessingItem> queue_;
QString translationLanguage_;
QWebView *view_;
bool isLoadFinished_;
bool isTranslationFinished_;
};
#endif // GOOGLEWEBTRANSLATOR_H

View File

@ -7,146 +7,150 @@
#include "ImageProcessing.h"
#include "StAssert.h"
#ifdef WIN32
#include <windows.h>
qint64 getFreeMemory ()
{
#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))
{
if (GlobalMemoryStatusEx (&statex)) {
return statex.ullAvailPhys;
}
return -1;
}
#endif
Pix *convertImage(const QImage& image)
{
Pix * convertImage (const QImage &image) {
PIX *pix;
QImage swapped = image.rgbSwapped();
int width = swapped.width();
int height = swapped.height();
int depth = swapped.depth();
int wpl = swapped.bytesPerLine() / 4;
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);
l_uint32 *outData = pix->data;
for (int y = 0; y < height; y++)
{
l_uint32 *lines = outData + y * wpl;
QByteArray a((const char*)swapped.scanLine(y), swapped.bytesPerLine());
for (int j = 0; j < a.size(); j++)
{
*((l_uint8 *)lines + j) = a[j];
}
}
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 = swapped.dotsPerMeterX() / toDPM;
int resolutionY = swapped.dotsPerMeterY() / toDPM;
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 pixEndianByteSwapNew(pix);
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(pixEndianByteSwapNew(&image));
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)
if (depth == 1) {
format = QImage::Format_Mono;
else if (depth == 8)
}
else if (depth == 8) {
format = QImage::Format_Indexed8;
else
}
else {
format = QImage::Format_RGB32;
}
QImage result((uchar*)datas, width, height, bytesPerLine, format);
QImage result ((uchar *)datas, width, height, bytesPerLine, format);
// Set resolution
l_int32 xres, yres;
pixGetResolution(&image, &xres, &yres);
pixGetResolution (&image, &xres, &yres);
const qreal toDPM = 1.0 / 0.0254;
result.setDotsPerMeterX(xres * toDPM);
result.setDotsPerMeterY(yres * toDPM);
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));
_bwCT.append (qRgb (255,255,255));
_bwCT.append (qRgb (0,0,0));
QVector<QRgb> _grayscaleCT(256);
QVector<QRgb> _grayscaleCT (256);
for (int i = 0; i < 256; i++) {
_grayscaleCT.append(qRgb(i, i, i));
_grayscaleCT.append (qRgb (i, i, i));
}
switch (depth) {
case 1:
result.setColorTable(_bwCT);
result.setColorTable (_bwCT);
break;
case 8:
result.setColorTable(_grayscaleCT);
result.setColorTable (_grayscaleCT);
break;
default:
result.setColorTable(_grayscaleCT);
result.setColorTable (_grayscaleCT);
}
if (result.isNull()) {
static QImage none(0,0,QImage::Format_Invalid);
qDebug("Invalid format!!!\n");
if (result.isNull ()) {
static QImage none (0,0,QImage::Format_Invalid);
qDebug ("Invalid format!!!\n");
return none;
}
return result.rgbSwapped();
return result;
}
Pix *prepareImage(const QImage &image, int preferredScale)
{
Pix* pix = convertImage (image);
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);
Pix *gray = pixConvertRGBToGray (pix, 0.0, 0.0, 0.0);
ST_ASSERT (gray != NULL);
pixDestroy (&pix);
Pix* scaled = gray;
if (preferredScale > 0)
{
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);
#ifdef WIN32
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);
#endif
scaled = pixScale (gray, scale, scale);
}
ST_ASSERT (scaled != NULL);
if (scaled != gray)
{
scaled = pixScale (gray, scale, scale);
if (scaled == NULL) {
scaled = gray;
}
}
if (scaled != gray) {
pixDestroy (&gray);
}
return scaled;
}
void cleanupImage(Pix **image)
{
void cleanupImage (Pix **image) {
pixDestroy (image);
}

View File

@ -6,13 +6,13 @@
class Pix;
//! Convert QImage to Leptonica's PIX.
Pix* convertImage(const QImage& image);
Pix * convertImage (const QImage &image);
//! Convert Leptonica's PIX to QImage.
QImage convertImage(Pix &image);
QImage convertImage (Pix &image);
//! Propare image for OCR.
Pix* prepareImage (const QImage& image, int preferredScale);
Pix * prepareImage (const QImage &image, int preferredScale);
//! Free allocated resources for image.
void cleanupImage (Pix** image);
void cleanupImage (Pix **image);
#endif // IMAGEPROCESSING_H

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2014 Gres (gres@gres.biz)
Copyright (c) 2015 Gres (gres@gres.biz)
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

View File

@ -3,109 +3,100 @@
#include "LanguageHelper.h"
#include "Settings.h"
#include "StAssert.h"
LanguageHelper::LanguageHelper()
{
LanguageHelper::LanguageHelper () {
init ();
}
QStringList LanguageHelper::availableOcrLanguagesUi() const
{
QStringList LanguageHelper::availableOcrLanguagesUi () const {
QStringList uiItems;
foreach (const QString& item, availableOcrLanguages_)
{
foreach (const QString &item, availableOcrLanguages_) {
uiItems << ocrCodeToUi (item);
}
uiItems.sort ();
return uiItems;
}
const QStringList &LanguageHelper::availableOcrLanguages() const
{
const QStringList &LanguageHelper::availableOcrLanguages () const {
return availableOcrLanguages_;
}
QStringList LanguageHelper::availableOcrLanguages(const QString &path) const
{
QStringList LanguageHelper::availableOcrLanguages (const QString &path) const {
QDir dir (path + "/tessdata/");
if (!dir.exists ())
{
if (!dir.exists ()) {
return QStringList ();
}
QStringList items;
QStringList files = dir.entryList (QStringList () << "*.traineddata", QDir::Files);
foreach (const QString& file, files)
{
foreach (const QString &file, files) {
QString lang = file.left (file.indexOf ("."));
items << lang;
}
return items;
}
QStringList LanguageHelper::availableOcrLanguagesUi(const QString &path) const
{
QStringList LanguageHelper::availableOcrLanguagesUi (const QString &path) const {
QStringList uiItems, items;
items = availableOcrLanguages (path);
foreach (const QString& item, items)
{
foreach (const QString &item, items) {
uiItems << ocrCodeToUi (item);
}
uiItems.sort ();
return uiItems;
}
QStringList LanguageHelper::translateLanguagesUi() const
{
QStringList LanguageHelper::translateLanguagesUi () const {
QStringList uiItems = translateLanguages_.keys ();
uiItems.sort ();
return uiItems;
}
QStringList LanguageHelper::translateLanguages() const
{
QStringList LanguageHelper::translateLanguages () const {
return translateLanguages_.values ();
}
QString LanguageHelper::translateCodeToUi(const QString &text) const
{
QString LanguageHelper::translateCodeToUi (const QString &text) const {
return translateLanguages_.key (text, text);
}
QString LanguageHelper::translateUiToCode(const QString &text) const
{
QString LanguageHelper::translateUiToCode (const QString &text) const {
return translateLanguages_.value (text, text);
}
QString LanguageHelper::ocrCodeToUi(const QString &text) const
{
QString LanguageHelper::ocrCodeToUi (const QString &text) const {
return ocrLanguages_.key (text, text);
}
QString LanguageHelper::ocrUiToCode(const QString &text) const
{
QString LanguageHelper::ocrUiToCode (const QString &text) const {
return ocrLanguages_.value (text, text);
}
QString LanguageHelper::translateForOcrCode(const QString &text) const
{
QString ocrUi = ocrUiToCode (text);
QString translate = translateCodeToUi (ocrUi);
if (translate == ocrUi)
{
translate = "auto";
QString LanguageHelper::ocrToTranslateCodes (const QString &text) const {
QString ocrUi = ocrCodeToUi (text);
QString translateCode = translateUiToCode (ocrUi);
if (translateCode == ocrUi) {
translateCode = "auto";
}
return translate;
return translateCode;
}
void LanguageHelper::init()
{
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()
{
void LanguageHelper::updateAvailableOcrLanguages () {
availableOcrLanguages_.clear ();
QSettings settings;
settings.beginGroup (settings_names::recogntionGroup);
@ -114,131 +105,197 @@ void LanguageHelper::updateAvailableOcrLanguages()
availableOcrLanguages_ = availableOcrLanguages (tessDataPlace);
}
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::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::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");
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

@ -3,28 +3,32 @@
#include <QMap>
#include <QStringList>
#include <QMenu>
class LanguageHelper
{
class LanguageHelper {
public:
LanguageHelper ();
QStringList availableOcrLanguagesUi () const;
const QStringList& availableOcrLanguages () const;
QStringList availableOcrLanguagesUi (const QString& path) 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 translateForOcrCode (const QString& text) 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;
QStringList availableOcrLanguages (const QString &path) const;
void init ();
void initTranslateLanguages ();
void initOcrLanguages ();

View File

@ -5,89 +5,105 @@
#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 "Translator.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 (QIcon (":/images/icon.png"), this)),
Manager::Manager (QObject *parent) :
QObject (parent),
trayIcon_ (new QSystemTrayIcon (this)),
dictionary_ (new LanguageHelper),
selection_ (new SelectionDialog (*dictionary_)),
resultDialog_ (new ResultDialog),
captureAction_ (NULL), repeatAction_ (NULL), clipboardAction_ (NULL),
useResultDialog_ (true)
{
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 (selection_, SIGNAL (selected (ProcessingItem)),
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);
QThread *recognizerThread = new QThread (this);
threads_ << recognizerThread;
recognizer->moveToThread (recognizerThread);
recognizerThread->start ();
connect (qApp, SIGNAL (aboutToQuit ()), recognizerThread, SLOT (quit ()));
// Translator
Translator* translator = new Translator;
connect (recognizer, SIGNAL (recognized (ProcessingItem)),
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 ()));
QThread* translatorThread = new QThread (this);
translator->moveToThread (translatorThread);
translatorThread->start ();
connect (qApp, SIGNAL (aboutToQuit ()), translatorThread, SLOT (quit ()));
connect (translator, SIGNAL (translated (ProcessingItem)),
SLOT (showResult (ProcessingItem)));
connect (this, SIGNAL (showPixmap (QPixmap)),
selection_, SLOT (setPixmap (QPixmap)));
connect (this, SIGNAL (settingsEdited ()), selection_, SLOT (updateMenu ()));
connect (this, SIGNAL (settingsEdited ()), this, SLOT (applySettings ()));
selection_->setWindowIcon (trayIcon_->icon ());
resultDialog_->setWindowIcon (trayIcon_->icon ());
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 ();
QMenu * Manager::trayContextMenu () {
QMenu *menu = new QMenu ();
captureAction_ = menu->addAction (tr ("Захват"), this, SLOT (capture ()));
QMenu* translateMenu = menu->addMenu (tr ("Перевод"));
repeatAction_ = translateMenu->addAction (tr ("Повторить"), this,
repeatCaptureAction_ = menu->addAction (tr ("Повторить захват"),
this, SLOT (repeatCapture ()));
QMenu *translateMenu = menu->addMenu (tr ("Результат"));
repeatAction_ = translateMenu->addAction (tr ("Показать"), this,
SLOT (showLast ()));
clipboardAction_ = translateMenu->addAction (tr ("Скопировать"), this,
clipboardAction_ = translateMenu->addAction (tr ("В буфер"), this,
SLOT (copyLastToClipboard ()));
menu->addAction (tr ("Настройки"), this, SLOT (settings ()));
menu->addAction (tr ("О программе"), this, SLOT (about ()));
@ -95,133 +111,347 @@ QMenu*Manager::trayContextMenu()
return menu;
}
void Manager::applySettings()
{
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);
QString captureHotkey = settings.value (settings_names::captureHotkey,
settings_values::captureHotkey).toString ();
QStringList globalActionsFailed;
Q_CHECK_PTR (captureAction_);
GlobalActionHelper::removeGlobal (captureAction_);
captureAction_->setShortcut (captureHotkey);
GlobalActionHelper::makeGlobal (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 ();
}
QString repeatHotkey = settings.value (settings_names::repeatHotkey,
settings_values::repeatHotkey).toString ();
Q_CHECK_PTR (repeatAction_);
GlobalActionHelper::removeGlobal (repeatAction_);
repeatAction_->setShortcut (repeatHotkey);
GlobalActionHelper::makeGlobal (repeatAction_);
repeatAction_->setShortcut (GET (repeatHotkey).toString ());
if (!GlobalActionHelper::makeGlobal (repeatAction_)) {
globalActionsFailed << repeatAction_->shortcut ().toString ();
}
QString clipboardHotkey = settings.value (settings_names::clipboardHotkey,
settings_values::clipboardHotkey).toString ();
Q_CHECK_PTR (clipboardAction_);
GlobalActionHelper::removeGlobal (clipboardAction_);
clipboardAction_->setShortcut (clipboardHotkey);
GlobalActionHelper::makeGlobal (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_ = settings.value (settings_names::resultShowType,
settings_values::resultShowType).toBool ();
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
}
Manager::~Manager()
{
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::capture()
{
QList<QScreen*> screens = QApplication::screens ();
ST_ASSERT (!screens.isEmpty ());
QScreen* screen = screens.first ();
Q_CHECK_PTR (screen);
WId desktopId = QApplication::desktop ()->winId ();
QPixmap pixmap = screen->grabWindow (desktopId);
ST_ASSERT (!pixmap.isNull ());
emit showPixmap (pixmap);
void Manager::checkForUpdates () {
updater_->checkForUpdates ();
scheduleUpdate (true);
}
void Manager::settings()
{
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()
{
void Manager::close () {
QApplication::quit ();
}
void Manager::about()
{
QString version = "1.2.3";
QString text = tr ("Программа для распознавания текста на экране.\n"\
void Manager::about () {
QString text = tr ("Программа для распознавания текста на экране.\n" \
"Создана с использованием Qt, tesseract-ocr, Google Translate.\n"
"Автор: Gres (translator@gres.biz)\n"
"Версия: %1 от %2 %3").arg (version)
"Версия: %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,
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)
{
void Manager::processTrayAction (QSystemTrayIcon::ActivationReason reason) {
if (reason == QSystemTrayIcon::Trigger && repeatAction_->isEnabled ()) {
showLast ();
}
else if (reason == QSystemTrayIcon::MiddleClick)
{
else if (reason == QSystemTrayIcon::MiddleClick && clipboardAction_->isEnabled ()) {
copyLastToClipboard ();
}
}
void Manager::showLast()
{
if (lastItem_.isValid ())
{
showResult (lastItem_);
}
}
void Manager::copyLastToClipboard()
{
if (lastItem_.isValid ())
{
QClipboard* clipboard = QApplication::clipboard ();
QString message = lastItem_.recognized + " - " + lastItem_.translated;
clipboard->setText (message);
trayIcon_->showMessage (tr ("Перевод"),
tr ("Последний перевод был скопирован в буфер обмена."),
trayIcon_->showMessage (tr ("Результат"),
tr ("Последний результат был скопирован в буфер обмена."),
QSystemTrayIcon::Information);
}
else if (reason == QSystemTrayIcon::DoubleClick && repeatCaptureAction_->isEnabled ()) {
repeatCapture ();
}
}
void Manager::showResult(ProcessingItem item)
{
ST_ASSERT (item.isValid ());
lastItem_ = item;
if (useResultDialog_)
{
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
{
else {
QString message = item.recognized + " - " + item.translated;
trayIcon_->showMessage (tr ("Перевод"), message, QSystemTrayIcon::Information);
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::showError(QString text)
{
qCritical () << text;
trayIcon_->showMessage (tr ("Ошибка"), text, QSystemTrayIcon::Critical);
void Manager::updateNormalIcon () {
QString fileName = itemProcessingCount_ > 0
? ":/images/STIconOrange.png" : ":/images/STIconBlue.png";
trayIcon_->setIcon (QIcon (fileName));
}

View File

@ -3,6 +3,7 @@
#include <QPixmap>
#include <QSystemTrayIcon>
#include <QMap>
#include "ProcessingItem.h"
@ -12,46 +13,72 @@ class QMenu;
class SelectionDialog;
class ResultDialog;
class LanguageHelper;
class Updater;
class Manager : public QObject
{
class Manager : public QObject {
Q_OBJECT
enum IconType {
IconTypeNormal, IconTypeWorking, IconTypeError, IconTypeSuccess
};
public:
explicit Manager(QObject *parent = 0);
explicit Manager (QObject *parent = 0);
~Manager ();
signals:
void showPixmap (QPixmap pixmap);
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);
private:
QMenu* trayContextMenu ();
void updateNormalIcon ();
private:
QSystemTrayIcon* trayIcon_;
LanguageHelper* dictionary_;
SelectionDialog* selection_;
ResultDialog* resultDialog_;
QAction* captureAction_;
QAction* repeatAction_;
QAction* clipboardAction_;
ProcessingItem lastItem_;
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,11 +1,17 @@
#include "ProcessingItem.h"
bool ProcessingItem::isValid() const
{
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 ());
valid &= (!translated.isEmpty ());
}
return valid;
}

View File

@ -3,8 +3,8 @@
#include <QPixmap>
struct ProcessingItem
{
struct ProcessingItem {
ProcessingItem ();
QPoint screenPos;
QPixmap source;
QString recognized;
@ -12,9 +12,13 @@ struct ProcessingItem
QString ocrLanguage;
QString sourceLanguage;
QString translateLanguage;
bool isValid () const;
Qt::KeyboardModifiers modifiers;
bool swapLanguages_;
bool isValid (bool checkOnlyInput = false) const;
};
Q_DECLARE_METATYPE(ProcessingItem)
Q_DECLARE_METATYPE (ProcessingItem)
#endif // PROCESSINGITEM_H

View File

@ -1,3 +1,5 @@
[![Build Status](https://travis-ci.org/OneMoreGres/ScreenTranslator.svg)](https://travis-ci.org/OneMoreGres/ScreenTranslator.svg)
Screen Translator
=================
@ -14,7 +16,7 @@ Usage
Features
--------
* Many OCR languages (can be modified dynamicly)
* Many OCR languages (can be modified dynamically)
* Global hotkeys for main actions
* Copy last translation to clipboard
* Repeat last translation
@ -27,12 +29,13 @@ Limitations
-----------
* Works only on primary screen
* Can not capture some dynamic web-pages
* Not very precise OCR (need better preprocessing steps)
* Not very precise OCR
* Not all functions are cross-platform (may be bugged on some systems)
Used software
-------------
* see [Qt 5](http://qt-project.org/)
* see [Tesseract](https://code.google.com/p/tesseract-ocr/)
* see [Leptonica](http://leptonica.com/) (Tesseract dependency)
* Google Translate
* several online translation services

View File

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

View File

@ -6,16 +6,16 @@
#include "ProcessingItem.h"
namespace tesseract
{
namespace tesseract {
class TessBaseAPI;
}
class RecognizerHelper;
class Recognizer : public QObject
{
class Recognizer : public QObject {
Q_OBJECT
public:
explicit Recognizer(QObject *parent = 0);
explicit Recognizer (QObject *parent = 0);
signals:
void recognized (ProcessingItem item);
@ -26,10 +26,11 @@ class Recognizer : public QObject
void applySettings ();
private:
bool initEngine (tesseract::TessBaseAPI*&engine, const QString &language);
bool initEngine (tesseract::TessBaseAPI * &engine, const QString &language);
private:
tesseract::TessBaseAPI* engine_;
tesseract::TessBaseAPI *engine_;
RecognizerHelper *recognizerHelper_;
QString tessDataDir_;
QString ocrLanguage_;

88
RecognizerHelper.cpp Normal file
View File

@ -0,0 +1,88 @@
#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) {
}

33
RecognizerHelper.h Normal file
View File

@ -0,0 +1,33 @@
#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

@ -2,6 +2,10 @@
<qresource prefix="/">
<file>translations/translation_en.qm</file>
<file>translations/translation_ru.qm</file>
<file>images/icon.png</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,69 +1,121 @@
#include "ResultDialog.h"
#include "ui_ResultDialog.h"
#include "StAssert.h"
#include "LanguageHelper.h"
#include <QDesktopWidget>
#include <QMouseEvent>
#include <QMenu>
ResultDialog::ResultDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::ResultDialog),
isShowAtCapturePos_ (true)
{
ui->setupUi(this);
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::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()
{
ResultDialog::~ResultDialog () {
delete contextMenu_;
delete ui;
}
bool ResultDialog::eventFilter(QObject* object, QEvent* event)
{
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::MouseButtonRelease)
{
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.source.isNull ());
ST_ASSERT (!item.recognized.isEmpty ());
ST_ASSERT (!item.translated.isEmpty ());
ST_ASSERT (!item.screenPos.isNull ());
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 ();
QDesktopWidget *desktop = QApplication::desktop ();
Q_CHECK_PTR (desktop);
if (isShowAtCapturePos_)
{
QPoint correction = QPoint (ui->frame->lineWidth (), ui->frame->lineWidth ());
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)
{
if (y () > minY) {
move (x (), minY);
}
}
else
{
QRect screenRect = desktop->availableGeometry (this);
ST_ASSERT (screenRect.isValid ());
QPoint newPos (screenRect.width () - width (), screenRect.height () - height ());
move (newPos);
}
activateWindow ();
}

View File

@ -2,30 +2,50 @@
#define RESULTDIALOG_H
#include <QDialog>
#include <QMenu>
#include "ProcessingItem.h"
namespace Ui {
class ResultDialog;
}
class LanguageHelper;
class ResultDialog : public QDialog
{
class ResultDialog : public QDialog {
Q_OBJECT
public:
explicit ResultDialog(QWidget *parent = 0);
~ResultDialog();
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;
bool isShowAtCapturePos_;
const LanguageHelper &dictionary_;
QMenu *contextMenu_;
QMenu *recognizeSubMenu_;
QMenu *translateSubMenu_;
QAction *clipboardAction_;
QAction *imageClipboardAction_;
QAction *correctAction_;
ProcessingItem item_;
};
#endif // RESULTDIALOG_H

View File

@ -14,7 +14,16 @@
<string>Результат</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="margin">
<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">
@ -29,7 +38,16 @@
<enum>QFrame::Plain</enum>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<property name="margin">
<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">
@ -49,7 +67,7 @@
</widget>
</item>
<item row="1" column="0">
<widget class="Line" name="line_2">
<widget class="Line" name="recognizeLine">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@ -69,7 +87,7 @@
</widget>
</item>
<item row="3" column="0">
<widget class="Line" name="line">
<widget class="Line" name="translateLine">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>

View File

@ -10,11 +10,21 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = ScreenTranslator
TEMPLATE = app
CONFIG += c++11
INCLUDEPATH += ../include
win32{
INCLUDEPATH += $$PWD/../build/mingw/deps/include
LIBS += -L$$PWD/../build/mingw/deps/lib -lws2_32
}
linux{
QT += x11extras
INCLUDEPATH += $$PWD/../build/linux/deps/include
LIBS += -L$$PWD/../build/linux/deps/lib -lX11 -Wl,-rpath,.
}
LIBS += -L../bin -ltesseract -llept -ltiff -lgif -ljpeg -lz
LIBS += -lWs2_32
LIBS += -ltesseract -llept
include(3rd-party/qtsingleapplication/qtsingleapplication.pri)
SOURCES += main.cpp\
Manager.cpp \
@ -22,12 +32,16 @@ SOURCES += main.cpp\
SelectionDialog.cpp \
GlobalActionHelper.cpp \
Recognizer.cpp \
Translator.cpp \
ResultDialog.cpp \
ProcessingItem.cpp \
ImageProcessing.cpp \
LanguageHelper.cpp \
GoogleWebTranslator.cpp
WebTranslator.cpp \
WebTranslatorProxy.cpp \
TranslatorHelper.cpp \
RecognizerHelper.cpp \
Utils.cpp \
Updater.cpp
HEADERS += \
Manager.h \
@ -35,14 +49,18 @@ HEADERS += \
SelectionDialog.h \
GlobalActionHelper.h \
Recognizer.h \
Translator.h \
Settings.h \
ProcessingItem.h \
ResultDialog.h \
ImageProcessing.h \
LanguageHelper.h \
GoogleWebTranslator.h \
StAssert.h
WebTranslator.h \
WebTranslatorProxy.h \
StAssert.h \
TranslatorHelper.h \
RecognizerHelper.h \
Utils.h \
Updater.h
FORMS += \
SettingsEditor.ui \
@ -56,11 +74,19 @@ TRANSLATIONS += \
translations/translation_en.ts \
translations/translation_ru.ts
win32{
RC_FILE = app.rc
}
OTHER_FILES += \
app.rc \
images/icon.ico \
README.md
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

@ -8,159 +8,115 @@
#include <QDebug>
#include <QMenu>
SelectionDialog::SelectionDialog(const LanguageHelper &dictionary, QWidget *parent) :
QDialog(parent),
ui(new Ui::SelectionDialog), dictionary_ (dictionary),
languageMenu_ (new QMenu)
{
ui->setupUi(this);
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::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
ui->label->setAutoFillBackground(false);
ui->label->setAutoFillBackground (false);
ui->label->installEventFilter (this);
updateMenu ();
applySettings ();
}
SelectionDialog::~SelectionDialog()
{
SelectionDialog::~SelectionDialog () {
delete languageMenu_;
delete ui;
}
void SelectionDialog::updateMenu()
{
Q_CHECK_PTR (languageMenu_);
languageMenu_->clear ();
QStringList languages = dictionary_.availableOcrLanguagesUi ();
if (languages.isEmpty ())
{
return;
}
const int max = 10;
if (languages.size () <= max)
{
foreach (const QString& language, languages)
{
languageMenu_->addAction (language);
}
}
else
{
int subIndex = max;
QMenu* subMenu = NULL;
QString prevLetter;
foreach (const QString& language, languages)
{
QString curLetter = language.left (1);
if (++subIndex >= max && prevLetter != curLetter)
{
if (subMenu != NULL)
{
subMenu->setTitle (subMenu->title () + " - " + prevLetter);
}
subMenu = languageMenu_->addMenu (curLetter);
subIndex = 0;
}
prevLetter = curLetter;
subMenu->addAction (language);
}
subMenu->setTitle (subMenu->title () + " - " + prevLetter);
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)
{
bool SelectionDialog::eventFilter (QObject *object, QEvent *event) {
if (object != ui->label) {
return QDialog::eventFilter (object, event);
}
if (event->type () == QEvent::Show)
{
if (event->type () == QEvent::Show) {
startSelectPos_ = currentSelectPos_ = QPoint ();
}
else if (event->type () == QEvent::MouseButtonPress)
{
QMouseEvent* mouseEvent = static_cast <QMouseEvent*> (event);
else if (event->type () == QEvent::MouseButtonPress) {
QMouseEvent *mouseEvent = static_cast <QMouseEvent *> (event);
if ((mouseEvent->button () == Qt::LeftButton ||
mouseEvent->button () == Qt::RightButton) && startSelectPos_.isNull ())
{
mouseEvent->button () == Qt::RightButton) && startSelectPos_.isNull ()) {
startSelectPos_ = mouseEvent->pos ();
}
}
else if (event->type () == QEvent::MouseMove)
{
QMouseEvent* mouseEvent = static_cast <QMouseEvent*> (event);
else if (event->type () == QEvent::MouseMove) {
QMouseEvent *mouseEvent = static_cast <QMouseEvent *> (event);
if ((mouseEvent->buttons () & Qt::LeftButton ||
mouseEvent->buttons () & Qt::RightButton) && !startSelectPos_.isNull ())
{
mouseEvent->buttons () & Qt::RightButton) && !startSelectPos_.isNull ()) {
currentSelectPos_ = mouseEvent->pos ();
ui->label->repaint ();
}
}
else if (event->type () == QEvent::Paint)
{
else if (event->type () == QEvent::Paint) {
QRect selection = QRect (startSelectPos_, currentSelectPos_).normalized ();
if (selection.isValid ())
{
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);
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 ())
{
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.isNull ())
{
ProcessingItem item;
item.source = selectedPixmap;
item.screenPos = selection.topLeft ();
if (mouseEvent->button () == Qt::RightButton &&
!languageMenu_->children ().isEmpty ())
{
QAction* action = languageMenu_->exec (QCursor::pos ());
if (action == NULL)
{
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_.translateForOcrCode (item.ocrLanguage);
item.sourceLanguage = dictionary_.ocrToTranslateCodes (item.ocrLanguage);
ST_ASSERT (!item.sourceLanguage.isEmpty ());
}
emit selected (item);
accept ();
}
emit selected (item);
}
}
return QDialog::eventFilter (object, event);
}
void SelectionDialog::setPixmap(QPixmap pixmap)
{
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->resize (pixmap.size ());
this->setGeometry (showGeometry);
show ();
setFocus ();
activateWindow ();
}

View File

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

View File

@ -3,15 +3,23 @@
#include <QString>
namespace settings_names
{
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";
@ -21,30 +29,49 @@ namespace settings_names
//! Translation
const QString translationGroup = "Translation";
const QString doTranslation = "doTranslation";
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
{
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 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,133 +1,288 @@
#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), dictionary_ (dictionary),
buttonGroup_ (new QButtonGroup (this))
{
ui->setupUi(this);
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->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()
{
SettingsEditor::~SettingsEditor () {
saveState ();
delete recognizerHelper_;
delete translatorHelper_;
delete ui;
}
void SettingsEditor::done(int result)
{
if (result == QDialog::Accepted)
{
void SettingsEditor::done (int result) {
if (result == QDialog::Accepted) {
saveSettings ();
emit settingsEdited ();
}
QDialog::done (result);
}
void SettingsEditor::saveSettings() const
{
void SettingsEditor::saveSettings () const {
using namespace settings_names;
QSettings settings;
settings.beginGroup (settings_names::guiGroup);
settings.setValue (settings_names::captureHotkey, ui->captureEdit->text ());
settings.setValue (settings_names::repeatHotkey, ui->repeatEdit->text ());
settings.setValue (settings_names::clipboardHotkey, ui->clipboardEdit->text ());
settings.setValue (settings_names::resultShowType, buttonGroup_->checkedId ());
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 (settings_names::recogntionGroup);
settings.setValue (settings_names::tessDataPlace, ui->tessdataEdit->text ());
QString ocrLanguage = dictionary_.ocrUiToCode (ui->ocrLangCombo->currentText ());
settings.setValue (settings_names::ocrLanguage, ocrLanguage);
settings.setValue (settings_names::imageScale, ui->imageScaleSpin->value ());
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 (settings_names::translationGroup);
settings.beginGroup (translationGroup);
settings.setValue (doTranslation, ui->doTranslationCheck->isChecked ());
settings.setValue (translationDebugMode, ui->translatorDebugCheck->isChecked ());
QString trLanguage = dictionary_.translateUiToCode (ui->translateLangCombo->currentText ());
settings.setValue (settings_names::translationLanguage, trLanguage);
QString sourceLanguage = dictionary_.translateForOcrCode (ocrLanguage);
settings.setValue (settings_names::sourceLanguage, sourceLanguage);
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()
{
void SettingsEditor::openTessdataDialog () {
QString path = QFileDialog::getExistingDirectory (this, tr ("Путь к tessdata"));
if (path.isEmpty ())
{
if (path.isEmpty ()) {
return;
}
QDir dir (path);
if (dir.dirName () == QString ("tessdata"))
{
if (dir.dirName () == QString ("tessdata")) {
dir.cdUp ();
}
ui->tessdataEdit->setText (dir.path ());
}
void SettingsEditor::loadSettings()
{
void SettingsEditor::loadSettings () {
#define GET(FIELD) settings.value (settings_names::FIELD, settings_values::FIELD)
QSettings settings;
settings.beginGroup (settings_names::guiGroup);
ui->captureEdit->setText (GET(captureHotkey).toString ());
ui->repeatEdit->setText (GET(repeatHotkey).toString ());
ui->clipboardEdit->setText (GET(clipboardHotkey).toString ());
QAbstractButton* button = buttonGroup_->button (GET(resultShowType).toInt ());
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->tessdataEdit->setText (GET (tessDataPlace).toString ());
QString ocrLanguage = dictionary_.ocrCodeToUi (GET (ocrLanguage).toString ());
ui->ocrLangCombo->setCurrentText (ocrLanguage);
ui->imageScaleSpin->setValue (GET(imageScale).toInt ());
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);
QString trLanguage = dictionary_.translateCodeToUi (GET(translationLanguage).toString ());
ui->doTranslationCheck->setChecked (GET (doTranslation).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
}
void SettingsEditor::saveState() const
{
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()
{
void SettingsEditor::loadState () {
QSettings settings;
settings.beginGroup (settings_names::guiGroup);
restoreGeometry (settings.value (objectName () + "_" + settings_names::geometry).toByteArray ());
}
void SettingsEditor::initOcrLangCombo(const QString &path)
{
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

@ -5,21 +5,28 @@
#include <QButtonGroup>
#include <QMap>
class QTableWidgetItem;
namespace Ui {
class SettingsEditor;
}
class LanguageHelper;
class TranslatorHelper;
class RecognizerHelper;
class SettingsEditor : public QDialog
{
class SettingsEditor : public QDialog {
Q_OBJECT
enum SubsCol {
SubsColLanguage = 0, SubsColSource, SubsColTarget
};
public:
explicit SettingsEditor(const LanguageHelper& dictionary, QWidget *parent = 0);
~SettingsEditor();
explicit SettingsEditor (const LanguageHelper &dictionary, QWidget *parent = 0);
~SettingsEditor ();
signals:
void settingsEdited ();
void updateCheckRequested ();
public slots:
void done (int result);
@ -27,17 +34,21 @@ class SettingsEditor : public QDialog
private slots:
void saveSettings () const;
void openTessdataDialog ();
void initOcrLangCombo (const QString& path);
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;
const LanguageHelper& dictionary_;
QButtonGroup* buttonGroup_;
TranslatorHelper *translatorHelper_;
RecognizerHelper *recognizerHelper_;
const LanguageHelper &dictionary_;
QButtonGroup *buttonGroup_;
};
#endif // SETTINGSEDITOR_H

View File

@ -6,14 +6,34 @@
<rect>
<x>0</x>
<y>0</y>
<width>435</width>
<height>221</height>
<width>553</width>
<height>456</height>
</rect>
</property>
<property name="windowTitle">
<string>Настройки</string>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<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">
@ -28,59 +48,230 @@
<property name="text">
<string>Захватить</string>
</property>
<property name="buddy">
<cstring>captureEdit</cstring>
</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="0" column="1" colspan="2">
<widget class="QLineEdit" name="captureEdit"/>
<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>
<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>captureEdit</cstring>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QLineEdit" name="clipboardEdit"/>
</item>
<item row="1" 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>
<property name="buddy">
<cstring>captureEdit</cstring>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QLineEdit" name="repeatEdit"/>
<item row="3" column="1">
<widget class="QKeySequenceEdit" name="clipboardEdit"/>
</item>
</layout>
</widget>
</item>
<item row="0" column="1">
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Распознавание</string>
<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://code.google.com/p/tesseract-ocr/downloads/list&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;https://code.google.com/p/tesseract-ocr/downloads/list&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<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>
@ -113,10 +304,13 @@
</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;/body&gt;&lt;/html&gt;</string>
<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>
@ -126,112 +320,163 @@
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QComboBox" name="ocrLangCombo"/>
</item>
<item row="2" column="1" colspan="2">
<widget class="QSpinBox" name="imageScaleSpin"/>
</item>
</layout>
</widget>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<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="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="resultGroup">
<property name="title">
<string>Вывод результата</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="1">
<widget class="QRadioButton" name="trayRadio">
<property name="text">
<string>Трей</string>
<string>Исправления:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QRadioButton" name="dialogRadio">
<property name="text">
<string>Окно</string>
<item row="4" column="0" colspan="3">
<widget class="QTableWidget" name="recognizerFixTable">
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="checked">
<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>
</item>
<item row="1" column="1">
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<widget class="QWidget" name="translateTab">
<attribute name="title">
<string>Перевод</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
</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="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="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="2" 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>
<string>Язык результата:</string>
</property>
<property name="buddy">
<cstring>translateLangCombo</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<item row="3" 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="2" column="1" colspan="2">
<widget class="QComboBox" name="translateLangCombo"/>
</item>
<item row="1" column="1" colspan="2">
<widget class="QSpinBox" name="translateTimeoutSpin">
<property name="suffix">
<string> сек.</string>
</property>
</widget>
</item>
<item row="4" 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>
</layout>
</widget>
</item>
<item row="2" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>1</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="1">
<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>
</layout>
</widget>
<tabstops>
<tabstop>tabWidget</tabstop>
<tabstop>captureEdit</tabstop>
<tabstop>translateLangCombo</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>buttonBox</tabstop>
<tabstop>recognizerFixTable</tabstop>
<tabstop>doTranslationCheck</tabstop>
<tabstop>translatorDebugCheck</tabstop>
<tabstop>translateTimeoutSpin</tabstop>
<tabstop>translateLangCombo</tabstop>
<tabstop>translatorList</tabstop>
</tabstops>
<resources/>
<connections>
@ -242,8 +487,8 @@
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
<x>256</x>
<y>447</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
@ -258,8 +503,8 @@
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
<x>324</x>
<y>447</y>
</hint>
<hint type="destinationlabel">
<x>286</x>

View File

@ -7,7 +7,7 @@
# if defined(ST_NO_ASSERT)
# define ST_ASSERT(CONDITION)
# else
# define ST_ASSERT(CONDITION) assert(CONDITION)
# define ST_ASSERT(CONDITION) assert (CONDITION)
# endif
#endif

View File

@ -1,121 +0,0 @@
#include "Translator.h"
#include <QDebug>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonParseError>
#include <QSettings>
#include "Settings.h"
#include "GoogleWebTranslator.h"
#include "StAssert.h"
namespace
{
const QString translateBaseUrl = "http://translate.google.com/translate_a/"
"t?client=t&text=%1&sl=%2&tl=%3";
}
Translator::Translator(QObject *parent) :
QObject(parent),
network_ (this),
useAlternativeTranslation_ (false)
{
connect (&network_, SIGNAL (finished (QNetworkReply*)),
SLOT (replyFinished (QNetworkReply*)));
GoogleWebTranslator* googleWeb = new GoogleWebTranslator;
connect (this, SIGNAL (translateAlternative (ProcessingItem)),
googleWeb, SLOT (translate (ProcessingItem)));
connect (googleWeb, SIGNAL (translated (ProcessingItem, bool)),
this, SLOT (translatedAlternative(ProcessingItem, bool)));
connect (googleWeb, SIGNAL (error (QString)), this, SIGNAL (error (QString)));
applySettings ();
}
void Translator::applySettings()
{
QSettings settings;
settings.beginGroup (settings_names::translationGroup);
translationLanguage_ = settings.value (settings_names::translationLanguage,
settings_values::translationLanguage).toString ();
sourceLanguage_ = settings.value (settings_names::sourceLanguage,
settings_values::sourceLanguage).toString ();
}
void Translator::translate(ProcessingItem item)
{
if (useAlternativeTranslation_) {
emit translateAlternative(item);
return;
}
ST_ASSERT (!item.recognized.isEmpty ());
QString sourceLanguage = item.sourceLanguage.isEmpty () ? sourceLanguage_ :
item.sourceLanguage;
if (translationLanguage_.isEmpty () || sourceLanguage.isEmpty ())
{
emit error (tr ("Неверные парметры для перевода."));
return;
}
QUrl url (translateBaseUrl.arg (item.recognized, sourceLanguage, translationLanguage_));
QNetworkReply* reply = network_.get (QNetworkRequest (url));
items_.insert (reply, item);
}
void Translator::translatedAlternative(ProcessingItem item, bool success)
{
if (success)
{
emit translated(item);
}
else
{
emit error (tr ("Ошибка альтернативного перевода текста: %1").arg (item.recognized));
}
}
void Translator::replyFinished(QNetworkReply* reply)
{
ST_ASSERT (items_.contains (reply));
ProcessingItem item = items_.take (reply);
ST_ASSERT (reply->isFinished ());
if (reply->error () != QNetworkReply::NoError)
{
useAlternativeTranslation_ = true;
emit translateAlternative(item);
reply->deleteLater ();
return;
}
QByteArray data = reply->readAll ();
reply->deleteLater ();
while (data.indexOf (",,") != -1)//make json valid
{
data.replace (",,", ",");
}
QJsonParseError parseError;
QJsonDocument document = QJsonDocument::fromJson (data, &parseError);
if (document.isEmpty ())
{
useAlternativeTranslation_ = true;
emit translateAlternative(item);
return;
}
QJsonArray answerArray = document.array ();
QJsonArray fullTranslation = answerArray.first ().toArray ();
QString translation = "";
foreach (QJsonValue part, fullTranslation)
{
QJsonArray partTranslation = part.toArray ();
if (partTranslation.isEmpty ())
{
continue;
}
translation += partTranslation.at (0).toString ();
}
item.translated = translation;
emit translated (item);
}

View File

@ -1,36 +0,0 @@
#ifndef TRANSLATOR_H
#define TRANSLATOR_H
#include <QNetworkAccessManager>
#include "ProcessingItem.h"
class Translator : public QObject
{
Q_OBJECT
public:
explicit Translator(QObject *parent = 0);
signals:
void translated (ProcessingItem item);
void translateAlternative (ProcessingItem item);
void error (QString text);
public slots:
void translate (ProcessingItem item);
void translatedAlternative (ProcessingItem item, bool success);
void applySettings ();
private slots:
void replyFinished (QNetworkReply* reply);
private:
QNetworkAccessManager network_;
QString translationLanguage_;
QString sourceLanguage_;
QHash<QNetworkReply*, ProcessingItem> items_;
bool useAlternativeTranslation_;
};
#endif // TRANSLATOR_H

76
TranslatorHelper.cpp Normal file
View File

@ -0,0 +1,76 @@
#include <QSettings>
#include <QDir>
#include <QFile>
#include <QApplication>
#include "TranslatorHelper.h"
#include "Settings.h"
TranslatorHelper::TranslatorHelper ()
: translatorsDir_ ("translators"), currentIndex_ (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 () {
currentIndex_ = 0;
}
QString TranslatorHelper::currentScript () const {
return (currentIndex_ < scripts_.size () ? scripts_.at (currentIndex_) : QString ());
}
QString TranslatorHelper::nextScript () {
++currentIndex_;
return currentScript ();
}
bool TranslatorHelper::gotScripts () const {
return !scripts_.isEmpty ();
}

27
TranslatorHelper.h Normal file
View File

@ -0,0 +1,27 @@
#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 ();
QString currentScript () const;
QString nextScript ();
bool gotScripts () const;
private:
QString translatorsDir_;
QStringList scripts_;
int currentIndex_;
};
#endif // TRANSLATORHELPER_H

264
Updater.cpp Normal file
View File

@ -0,0 +1,264 @@
#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 ();
}

65
Updater.h Normal file
View File

@ -0,0 +1,65 @@
#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

21
Utils.cpp Normal file
View File

@ -0,0 +1,21 @@
#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 Normal file
View File

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

142
WebTranslator.cpp Normal file
View File

@ -0,0 +1,142 @@
#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) {
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 *)));
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 ();
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::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);
#undef GET
}
void WebTranslator::setDebugMode (bool isOn) {
view_->setVisible (isOn);
}

53
WebTranslator.h Normal file
View File

@ -0,0 +1,53 @@
#ifndef WEBTRANSLATOR_H
#define WEBTRANSLATOR_H
#include <QObject>
#include <QMap>
#include <QTimer>
#include "ProcessingItem.h"
class QWebView;
class QNetworkReply;
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);
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_;
QTimer translationTimeout_;
};
#endif // WEBTRANSLATOR_H

25
WebTranslatorProxy.cpp Normal file
View File

@ -0,0 +1,25 @@
#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_;
}

37
WebTranslatorProxy.h Normal file
View File

@ -0,0 +1,37 @@
#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

1
app.rc
View File

@ -1 +0,0 @@
IDI_ICON1 ICON DISCARDABLE "images/icon.ico"

View File

@ -1,4 +1,21 @@
Changes.
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.

View File

@ -1,4 +1,21 @@
Изменения.
2.0.0:
* Добавлена версия под linux.
* Добавлена поддержка нескольких мониторов.
* Добавлеа возможность распознание без перевода.
* Добавлена возможность вызова старого рисунка для выделения.
* Добавлена возможность повторного выделения без закрытия окна захвата.
* Добавлена возможность повторного распознания на другом языке.
* Добавлена возможность отображения промежуточного результата при ошибке перевода.
* Добавлена поддержка разных сервисов перевода.
* Добавлена возможность копирования изображения в буфер.
* Добавлена возможность редакции распознанного текста.
* Добавлена возможность автоматической коррекции частых ошибок распознавания.
* Добавлена возможность использования прокси.
* Добавлена возможность разовой смена языка перевода и распознавания.
* Обновлены иконки.
* Добавлено отображение статуса работы на иконке.
* Добавлена возможность автоматического обновления.
1.2.3:
* Устранена возможная причина падения.
* Добавлена информация о версии и некоторые сообщения об ошибках.

Binary file not shown.

View File

@ -1,269 +0,0 @@
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "Screen Translator"
#define MyAppVersion "1.2.3"
#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=ScreenTranslator-{#MyAppVersion}
SetupIconFile=..\images\icon.ico
SolidCompression=yes
RestartIfNeededByRun=False
ShowLanguageDialog=auto
VersionInfoCompany={#MyAppPublisher}
VersionInfoDescription={#MyAppDescription}
VersionInfoProductName={#MyAppName}
VersionInfoProductVersion={#MyAppVersion}
VersionInfoVersion={#MyAppVersion}
Compression=lzma2/ultra64
InternalCompressLevel=max
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"; InfoBeforeFile: "eng\Changelog.txt"
Name: "russian"; MessagesFile: "compiler:Languages\Russian.isl,ru\Russian.isl"; InfoBeforeFile: "ru\Changelog.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
[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\tessdata\afr.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Afrikaans
Source: "content\tessdata\sqi.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Albanian
Source: "content\tessdata\grc.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\AncientGreek
Source: "content\tessdata\ara.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Arabic
Source: "content\tessdata\aze.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Azerbaijani
Source: "content\tessdata\eus.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Basque
Source: "content\tessdata\bel.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Belarusian
Source: "content\tessdata\ben.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Bengali
Source: "content\tessdata\bul.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Bulgarian
Source: "content\tessdata\cat.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Catalan
Source: "content\tessdata\chr.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Cherokee
Source: "content\tessdata\chi_sim.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\ChineseSimplified
Source: "content\tessdata\chi_tra.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\ChineseTraditional
Source: "content\tessdata\hrv.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Croatian
Source: "content\tessdata\ces.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Czech
Source: "content\tessdata\dan.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Danish
Source: "content\tessdata\nld.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Dutch
Source: "content\tessdata\eng.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\English
Source: "content\tessdata\epo.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Esperanto
Source: "content\tessdata\epo_alt.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Esperantoalternative
Source: "content\tessdata\est.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Estonian
Source: "content\tessdata\fin.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Finnish
Source: "content\tessdata\frk.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Frankish
Source: "content\tessdata\fra.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\French
Source: "content\tessdata\glg.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Galician
Source: "content\tessdata\deu.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\German
Source: "content\tessdata\ell.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Greek
Source: "content\tessdata\heb.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Hebrew
Source: "content\tessdata\hin.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Hindi
Source: "content\tessdata\hun.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Hungarian
Source: "content\tessdata\isl.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Icelandic
Source: "content\tessdata\ind.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Indonesian
Source: "content\tessdata\ita.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Italian
Source: "content\tessdata\jpn.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Japanese
Source: "content\tessdata\kan.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Kannada
Source: "content\tessdata\kor.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Korean
Source: "content\tessdata\lav.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Latvian
Source: "content\tessdata\lit.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Lithuanian
Source: "content\tessdata\mkd.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Macedonian
Source: "content\tessdata\msa.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Malay
Source: "content\tessdata\mal.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Malayalam
Source: "content\tessdata\mlt.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Maltese
Source: "content\tessdata\equ.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\MathEquation
Source: "content\tessdata\enm.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\MiddleEnglish
Source: "content\tessdata\frm.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\MiddleFrench
Source: "content\tessdata\nor.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Norwegian
Source: "content\tessdata\pol.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Polish
Source: "content\tessdata\por.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Portuguese
Source: "content\tessdata\ron.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Romanian
Source: "content\tessdata\rus.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Russian
Source: "content\tessdata\srp.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Serbian
Source: "content\tessdata\slk.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Slovakian
Source: "content\tessdata\slv.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Slovenian
Source: "content\tessdata\spa.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Spanish
Source: "content\tessdata\swa.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Swahili
Source: "content\tessdata\swe.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Swedish
Source: "content\tessdata\tgl.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Tagalog
Source: "content\tessdata\tam.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Tamil
Source: "content\tessdata\tel.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Telugu
Source: "content\tessdata\tha.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Thai
Source: "content\tessdata\tur.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Turkish
Source: "content\tessdata\ukr.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Ukrainian
Source: "content\tessdata\vie.*"; DestDir: "{app}\tessdata"; Flags: ignoreversion; Components: Languages\Vietnamese
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[CustomMessages]
english.CreateStartupIcon=Create autostart icon
english.Executables=Executables
english.Libraries=Libraries
english.Languages=OCR Languages
english.Afrikaans=Afrikaans
english.Albanian=Albanian
english.AncientGreek=AncientGreek
english.Arabic=Arabic
english.Azerbaijani=Azerbaijani
english.Basque=Basque
english.Belarusian=Belarusian
english.Bengali=Bengali
english.Bulgarian=Bulgarian
english.Catalan=Catalan
english.Cherokee=Cherokee
english.ChineseSimplified=ChineseSimplified
english.ChineseTraditional=ChineseTraditional
english.Croatian=Croatian
english.Czech=Czech
english.Danish=Danish
english.Dutch=Dutch
english.English=English
english.Esperanto=Esperanto
english.Esperantoalternative=Esperantoalternative
english.Estonian=Estonian
english.Finnish=Finnish
english.Frankish=Frankish
english.French=French
english.Galician=Galician
english.German=German
english.Greek=Greek
english.Hebrew=Hebrew
english.Hindi=Hindi
english.Hungarian=Hungarian
english.Icelandic=Icelandic
english.Indonesian=Indonesian
english.Italian=Italian
english.Japanese=Japanese
english.Kannada=Kannada
english.Korean=Korean
english.Latvian=Latvian
english.Lithuanian=Lithuanian
english.Macedonian=Macedonian
english.Malay=Malay
english.Malayalam=Malayalam
english.Maltese=Maltese
english.MathEquation=MathEquation
english.MiddleEnglish=MiddleEnglish
english.MiddleFrench=MiddleFrench
english.Norwegian=Norwegian
english.Polish=Polish
english.Portuguese=Portuguese
english.Romanian=Romanian
english.Russian=Russian
english.Serbian=Serbian
english.Slovakian=Slovakian
english.Slovenian=Slovenian
english.Spanish=Spanish
english.Swahili=Swahili
english.Swedish=Swedish
english.Tagalog=Tagalog
english.Tamil=Tamil
english.Telugu=Telugu
english.Thai=Thai
english.Turkish=Turkish
english.Ukrainian=Ukrainian
english.Vietnamese=Vietnamese
[Components]
Name: "Executable"; Description: "{cm:Executables}"; Types: compact custom full; Flags: fixed;
Name: "Libraries"; Description: "{cm:Libraries}"; Types: compact custom full; Flags: fixed;
Name: "Languages"; Description: "{cm:Languages}"; Types: custom full
Name: "Languages\Afrikaans"; Description: "{cm:Afrikaans}"; Types: full
Name: "Languages\Albanian"; Description: "{cm:Albanian}"; Types: full
Name: "Languages\AncientGreek"; Description: "{cm:AncientGreek}"; Types: full
Name: "Languages\Arabic"; Description: "{cm:Arabic}"; Types: full
Name: "Languages\Azerbaijani"; Description: "{cm:Azerbaijani}"; Types: full
Name: "Languages\Basque"; Description: "{cm:Basque}"; Types: full
Name: "Languages\Belarusian"; Description: "{cm:Belarusian}"; Types: full
Name: "Languages\Bengali"; Description: "{cm:Bengali}"; Types: full
Name: "Languages\Bulgarian"; Description: "{cm:Bulgarian}"; Types: full
Name: "Languages\Catalan"; Description: "{cm:Catalan}"; Types: full
Name: "Languages\Cherokee"; Description: "{cm:Cherokee}"; Types: full
Name: "Languages\ChineseSimplified"; Description: "{cm:ChineseSimplified}"; Types: full
Name: "Languages\ChineseTraditional"; Description: "{cm:ChineseTraditional}"; Types: compact custom full
Name: "Languages\Croatian"; Description: "{cm:Croatian}"; Types: full
Name: "Languages\Czech"; Description: "{cm:Czech}"; Types: full
Name: "Languages\Danish"; Description: "{cm:Danish}"; Types: full
Name: "Languages\Dutch"; Description: "{cm:Dutch}"; Types: full
Name: "Languages\English"; Description: "{cm:English}"; Types: compact custom full
Name: "Languages\Esperanto"; Description: "{cm:Esperanto}"; Types: full
Name: "Languages\Esperantoalternative"; Description: "{cm:Esperantoalternative}"; Types: full
Name: "Languages\Estonian"; Description: "{cm:Estonian}"; Types: full
Name: "Languages\Finnish"; Description: "{cm:Finnish}"; Types: full
Name: "Languages\Frankish"; Description: "{cm:Frankish}"; Types: full
Name: "Languages\French"; Description: "{cm:French}"; Types: compact custom full
Name: "Languages\Galician"; Description: "{cm:Galician}"; Types: full
Name: "Languages\German"; Description: "{cm:German}"; Types: compact custom full
Name: "Languages\Greek"; Description: "{cm:Greek}"; Types: full
Name: "Languages\Hebrew"; Description: "{cm:Hebrew}"; Types: full
Name: "Languages\Hindi"; Description: "{cm:Hindi}"; Types: full
Name: "Languages\Hungarian"; Description: "{cm:Hungarian}"; Types: full
Name: "Languages\Icelandic"; Description: "{cm:Icelandic}"; Types: full
Name: "Languages\Indonesian"; Description: "{cm:Indonesian}"; Types: full
Name: "Languages\Italian"; Description: "{cm:Italian}"; Types: full
Name: "Languages\Japanese"; Description: "{cm:Japanese}"; Types: compact custom full
Name: "Languages\Kannada"; Description: "{cm:Kannada}"; Types: full
Name: "Languages\Korean"; Description: "{cm:Korean}"; Types: compact custom full
Name: "Languages\Latvian"; Description: "{cm:Latvian}"; Types: full
Name: "Languages\Lithuanian"; Description: "{cm:Lithuanian}"; Types: full
Name: "Languages\Macedonian"; Description: "{cm:Macedonian}"; Types: full
Name: "Languages\Malay"; Description: "{cm:Malay}"; Types: full
Name: "Languages\Malayalam"; Description: "{cm:Malayalam}"; Types: full
Name: "Languages\Maltese"; Description: "{cm:Maltese}"; Types: full
Name: "Languages\MathEquation"; Description: "{cm:MathEquation}"; Types: compact custom full
Name: "Languages\MiddleEnglish"; Description: "{cm:MiddleEnglish}"; Types: full
Name: "Languages\MiddleFrench"; Description: "{cm:MiddleFrench}"; Types: full
Name: "Languages\Norwegian"; Description: "{cm:Norwegian}"; Types: full
Name: "Languages\Polish"; Description: "{cm:Polish}"; Types: full
Name: "Languages\Portuguese"; Description: "{cm:Portuguese}"; Types: full
Name: "Languages\Romanian"; Description: "{cm:Romanian}"; Types: full
Name: "Languages\Russian"; Description: "{cm:Russian}"; Types: compact custom full
Name: "Languages\Serbian"; Description: "{cm:Serbian}"; Types: full
Name: "Languages\Slovakian"; Description: "{cm:Slovakian}"; Types: full
Name: "Languages\Slovenian"; Description: "{cm:Slovenian}"; Types: full
Name: "Languages\Spanish"; Description: "{cm:Spanish}"; Types: compact custom full
Name: "Languages\Swahili"; Description: "{cm:Swahili}"; Types: full
Name: "Languages\Swedish"; Description: "{cm:Swedish}"; Types: full
Name: "Languages\Tagalog"; Description: "{cm:Tagalog}"; Types: full
Name: "Languages\Tamil"; Description: "{cm:Tamil}"; Types: full
Name: "Languages\Telugu"; Description: "{cm:Telugu}"; Types: full
Name: "Languages\Thai"; Description: "{cm:Thai}"; Types: full
Name: "Languages\Turkish"; Description: "{cm:Turkish}"; Types: full
Name: "Languages\Ukrainian"; Description: "{cm:Ukrainian}"; Types: full
Name: "Languages\Vietnamese"; Description: "{cm:Vietnamese}"; Types: full

16
distr/deb/DEBIAN/control Normal file
View File

@ -0,0 +1,16 @@
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

@ -0,0 +1,9 @@
[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;

145
distr/iss/InnoSetup.iss Normal file
View File

@ -0,0 +1,145 @@
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "Screen Translator"
#define MyAppVersion "2.0.0"
#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-{#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"; LicenseFile: "LICENSE_en.md"; InfoBeforeFile: "Changelog_en.txt"
Name: "ru"; MessagesFile: "compiler:Languages\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
[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
[Components]
Name: "Executable"; Description: "{cm:Executables}"; Types: compact custom full; Flags: fixed;
Name: "Libraries"; Description: "{cm:Libraries}"; Types: compact custom full; Flags: fixed;
Name: "Translators"; Description: "{cm:Translators}"; Types: compact custom full; Flags: fixed;
[CustomMessages]
en.CreateStartupIcon=Create autostart icon
en.Executables=Executables
en.Libraries=Libraries
en.Translators=Translators
ru.CreateStartupIcon=Äîáàâèòü â àâòîçàïóñê
ru.Executables=Èñïîëíÿåìûå ôàéëû
ru.Libraries=Áèáëèîòåêè
ru.Translators=Ïåðåâîä÷èêè
#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;
[CustomMessages]
ru.DwinsHs_PageCaption =Çàãðóçêà ôàéëîâ
ru.DwinsHs_PageDescription =Ïîæàëóéñòà, äîæäèòåñü îêîí÷àíèÿ çàãðóçêè...
ru.DwinsHs_TotalProgress =Îáùèé ïðîãðåññ:
ru.DwinsHs_CurrentFile =Òåêóùèé ôàéë:
ru.DwinsHs_File =Ôàéë:
ru.DwinsHs_Speed =Ñêîðîñòü:
ru.DwinsHs_Status =Ñòàòóñ:
ru.DwinsHs_ElapsedTime =Çàòðà÷åííîå âðåìÿ:
ru.DwinsHs_RemainingTime =Îñòàâøååñÿ âðåìÿ:
ru.DwinsHs_Status_GetFileInformation =Ïîëó÷åíèÿ ðàçìåðà ôàéëà
ru.DwinsHs_Status_StartingDownload =Íà÷àëî çàãðóçêè
ru.DwinsHs_Status_Downloading =Çàãðóçêà
ru.DwinsHs_Status_DownlaodComplete =Çàãðóçêà çàâåðøåíà

9
distr/iss/LICENSE_ru.md Normal file
View File

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

109
distr/iss/code2langTr.txt Normal file
View File

@ -0,0 +1,109 @@
#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 Идиш

1266
distr/iss/dwinshs.iss Normal file

File diff suppressed because it is too large Load Diff

230
distr/iss/make_tess_iss.sh Executable file
View File

@ -0,0 +1,230 @@
#!/bin/bash
TESSDATA_DIR="../../../tessdata"
TESSDATA_TAG="3.04.00"
for arg in ${@}; do
case "$arg" in
"tessdata" ) TESSDATA_DIR="$arg";;
"tag="* ) TESSDATA_TAG=${arg:4};;
esac
done
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 full\n"
MESSAGES_EN="\n[CustomMessages]\nen.Languages=OCR Languages\n"
MESSAGES_RU="\n[CustomMessages]\nru.Languages=Языки распознавания\n"
PREV_LANG=""
COMPACT_LANGS="eng rus deu spa chi_sim fra jpn"
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="full"
if [[ $COMPACT_LANGS =~ $FNAME ]]; then
TYPES="compact custom $TYPES"
fi
COMPONENTS=$COMPONENTS"Name: \"Languages\\\\$LANG_EN\"; Description: \"{cm:$LANG_EN}\"; Languages: $COMPONENT_LANG;
Types: $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://cdn.rawgit.com/tesseract-ocr/tessdata/$TESSDATA_TAG/$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
exit 0
function fillIss {
local ORDER=$1
local FIELD=$2
local ONLY_COMPONENTS=$3
local FILES=""
for i in $ORDER; do
local CUR_LANG_FILES=`find $TESSDATA_DIR -name \"$i.*\"`
if [ -z "$CUR_LANG_FILES" ]; then
continue
fi
FILES=$FILES" `find $TESSDATA_DIR -name \"$i.*\"`"
done
for i in $FILES; do
local fName=$(basename "$i")
local LANG=$(echo "$fName" | cut -d'.' -f1)
LANG_LINE=$(grep "$lang " $LANGS_FILE)
if [[ -z "$LANG_LINE" || "${LANG_LINE:0:1}" == "#" ]]; then
continue;
fi
LANG_EN=$(echo "$LANG_LINE" | cut -d' ' -f2)
LANG_RU=$(echo "$LANG_LINE" | cut -d' ' -f3)
if ! $ONLY_COMP; then
FILES=$FILES"Source: \"{tmp}\\\\$fName\"; DestDir: \"{app}\\\\tessdata\"; Components: Languages\\\\$LANG_EN;
Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\\\\$fName'),
'https://cdn.rawgit.com/tesseract-ocr/tessdata/$TESSDATA_TAG/$fName', 'ST_setup', 'Get', 0);\n"
fi
if [ "$PREV_LANG" != "$LANG_EN" ]; then
PREV_LANG="$LANG_EN"
SIZE=0
for s in `find $TESSDATA_DIR -name "$lang.*" -exec wc -c {} \; | cut -d' ' -f1`; do
SIZE=$(expr $SIZE + $s)
done
TYPES="full"
if [[ $COMPACT_LANGS =~ $lang ]]; then
TYPES="compact custom $TYPES"
fi
COMPONENTS=$COMPONENTS"Name: \"Languages\\\\$LANG_EN\"; Description: \"{cm:$LANG_EN}\"; Languages: $LLANG; Types: $TYPES; ExtraDiskSpaceRequired: $SIZE\n"
if ! $ONLY_COMP; then
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"
fi
fi
done
}
echo $(fillIss "$(getLangsOrder 2)" "en" false)
function doJob {
LLANG=$2
ONLY_COMP=$3
for fff in $1; do
for f in `find $TESSDATA_DIR -name "$fff.*"`; do
f=$(basename "$f")
lang=$(echo "$f" | cut -d'.' -f1)
LANG_LINE=$(grep "$lang " $LANGS_FILE)
if [[ -z "$LANG_LINE" || "${LANG_LINE:0:1}" == "#" ]]; then
continue;
fi
LANG_EN=$(echo "$LANG_LINE" | cut -d' ' -f2)
LANG_RU=$(echo "$LANG_LINE" | cut -d' ' -f3)
if ! $ONLY_COMP; then
FILES=$FILES"Source: \"{tmp}\\\\$f\"; DestDir: \"{app}\\\\tessdata\"; Components: Languages\\\\$LANG_EN;
Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\\\\$f'),
'https://cdn.rawgit.com/tesseract-ocr/tessdata/$TESSDATA_TAG/$f', 'ST_setup', 'Get', 0);\n"
fi
if [ "$PREV_LANG" != "$LANG_EN" ]; then
PREV_LANG="$LANG_EN"
SIZE=0
for s in `find $TESSDATA_DIR -name "$lang.*" -exec wc -c {} \; | cut -d' ' -f1`; do
SIZE=$(expr $SIZE + $s)
done
TYPES="full"
if [[ $COMPACT_LANGS =~ $lang ]]; then
TYPES="compact custom $TYPES"
fi
COMPONENTS=$COMPONENTS"Name: \"Languages\\\\$LANG_EN\"; Description: \"{cm:$LANG_EN}\"; Languages: $LLANG; Types: $TYPES; ExtraDiskSpaceRequired: $SIZE\n"
if ! $ONLY_COMP; then
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"
fi
fi
done
done
}
doJob "$(getOrder 2)" "en" false
doJob "$(getOrder 3)" "ru" true
echo $COMPONENTS
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
exit 0
for f in `ls $TESSDATA_DIR | sort`; do
lang=$(echo "$f" | cut -d'.' -f1)
LANG_LINE=$(grep "$lang " $LANGS_FILE)
if [[ -z "$LANG_LINE" || "${LANG_LINE:0:1}" == "#" ]]; then
continue;
fi
LANG_EN=$(echo "$LANG_LINE" | cut -d' ' -f2)
LANG_RU=$(echo "$LANG_LINE" | cut -d' ' -f3)
FILES=$FILES"Source: \"{tmp}\\\\$f\"; DestDir: \"{app}\\\\tessdata\"; Components: Languages\\\\$LANG_EN;
Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\\\\$f'),
'https://cdn.rawgit.com/tesseract-ocr/tessdata/$TESSDATA_TAG/$f', 'ST_setup', 'Get', 0);\n"
if [ "$PREV_LANG" != "$LANG_EN" ]; then
PREV_LANG="$LANG_EN"
SIZE=0
for s in `find $TESSDATA_DIR -name "$lang.*" -exec wc -c {} \; | cut -d' ' -f1`; do
SIZE=$(expr $SIZE + $s)
done
TYPES="full"
if [[ $COMPACT_LANGS =~ $lang ]]; then
TYPES="compact custom $TYPES"
fi
COMPONENTS=$COMPONENTS"Name: \"Languages\\\\$LANG_EN\"; Description: \"{cm:$LANG_EN}\"; Types: $TYPES; ExtraDiskSpaceRequired: $SIZE\n"
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"
fi
done
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

551
distr/iss/tessdata.iss Normal file
View File

@ -0,0 +1,551 @@
[Files]
Source: "{tmp}\afr.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Afrikaans; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\afr.traineddata'), 'https://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/grc.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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/ara.cube.lm', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/ara.cube.params', 'ST_setup', 'Get', 0);
Source: "{tmp}\ara.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Arabic; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ara.traineddata'), 'https://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/ara.traineddata', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/ara.cube.size', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/ara.cube.bigrams', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/ara.cube.nn', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/ara.cube.word-freq', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/ara.cube.fold', 'ST_setup', 'Get', 0);
Source: "{tmp}\asm.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Assamese; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\asm.traineddata'), 'https://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/dzo.traineddata', '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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/eng.cube.lm', 'ST_setup', 'Get', 0);
Source: "{tmp}\eng.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\English; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\eng.traineddata'), 'https://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/eng.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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/eng.cube.word-freq', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/eng.cube.nn', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/eng.cube.fold', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/eng.cube.bigrams', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/eng.cube.params', 'ST_setup', 'Get', 0);
Source: "{tmp}\epo.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Esperanto; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\epo.traineddata'), 'https://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/frk.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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/fra.cube.size', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/fra.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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/fra.cube.params', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/fra.tesseract_cube.nn', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/fra.cube.fold', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/fra.cube.lm', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/fra.cube.word-freq', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/fra.cube.bigrams', 'ST_setup', 'Get', 0);
Source: "{tmp}\fra.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\French; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\fra.traineddata'), 'https://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/fra.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\glg.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Galician; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\glg.traineddata'), 'https://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/heb.traineddata', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/hin.cube.fold', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/hin.cube.lm', 'ST_setup', 'Get', 0);
Source: "{tmp}\hin.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Hindi; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\hin.traineddata'), 'https://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/hin.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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/hin.cube.nn', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/hin.tesseract_cube.nn', '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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/hin.cube.word-freq', '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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/gle.traineddata', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/ita.cube.fold', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/ita.cube.size', '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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/ita.cube.params', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/ita.cube.lm', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/ita.cube.bigrams', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/ita.tesseract_cube.nn', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/ita.cube.nn', 'ST_setup', 'Get', 0);
Source: "{tmp}\ita.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Italian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ita.traineddata'), 'https://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/ita.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\jpn.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Japanese; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\jpn.traineddata'), 'https://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/rus.traineddata', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/rus.cube.nn', '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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/rus.cube.lm', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/rus.cube.size', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/rus.cube.params', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/rus.cube.word-freq', 'ST_setup', 'Get', 0);
Source: "{tmp}\san.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Sanskrit; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\san.traineddata'), 'https://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/slv.traineddata', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/spa.cube.fold', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/spa.cube.nn', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/spa.cube.lm', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/spa.cube.bigrams', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/spa.cube.size', '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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/spa.cube.word-freq', '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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/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://cdn.rawgit.com/tesseract-ocr/tessdata/3.04.00/yid.traineddata', 'ST_setup', 'Get', 0);
[Components]
Name: "Languages"; Description: "{cm:Languages}"; Types: custom full
Name: "Languages\Afrikaans"; Description: "{cm:Afrikaans}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 5198548
Name: "Languages\Albanian"; Description: "{cm:Albanian}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 6587325
Name: "Languages\Amharic"; Description: "{cm:Amharic}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 2953500
Name: "Languages\Ancient_Greek"; Description: "{cm:Ancient_Greek}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 5182527
Name: "Languages\Arabic"; Description: "{cm:Arabic}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 28534834
Name: "Languages\Assamese"; Description: "{cm:Assamese}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 15827072
Name: "Languages\Azerbaijani"; Description: "{cm:Azerbaijani}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 6615244
Name: "Languages\Basque"; Description: "{cm:Basque}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 4969647
Name: "Languages\Belarusian"; Description: "{cm:Belarusian}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 6822594
Name: "Languages\Bengali"; Description: "{cm:Bengali}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 15552533
Name: "Languages\Bosnian"; Description: "{cm:Bosnian}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 5432328
Name: "Languages\Bulgarian"; Description: "{cm:Bulgarian}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 6026234
Name: "Languages\Burmese"; Description: "{cm:Burmese}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 69770179
Name: "Languages\Catalan"; Description: "{cm:Catalan}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 5356190
Name: "Languages\Cebuano"; Description: "{cm:Cebuano}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 1686752
Name: "Languages\Cherokee"; Description: "{cm:Cherokee}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 1083194
Name: "Languages\Chineese_simplified"; Description: "{cm:Chineese_simplified}"; Languages: en; Types: compact custom full; ExtraDiskSpaceRequired: 42089623
Name: "Languages\Chineese_traditional"; Description: "{cm:Chineese_traditional}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 56692327
Name: "Languages\Croatian"; Description: "{cm:Croatian}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 9135966
Name: "Languages\Czech"; Description: "{cm:Czech}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 11896327
Name: "Languages\Danish"; Description: "{cm:Danish}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 7340575
Name: "Languages\Dutch"; Description: "{cm:Dutch}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 17098919
Name: "Languages\Dzongkha"; Description: "{cm:Dzongkha}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 3310882
Name: "Languages\English"; Description: "{cm:English}"; Languages: en; Types: compact custom full; ExtraDiskSpaceRequired: 38371506
Name: "Languages\Esperanto"; Description: "{cm:Esperanto}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 6602178
Name: "Languages\Estonian"; Description: "{cm:Estonian}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 9644486
Name: "Languages\Finnish"; Description: "{cm:Finnish}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 13274908
Name: "Languages\Frankish"; Description: "{cm:Frankish}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 16451109
Name: "Languages\French"; Description: "{cm:French}"; Languages: en; Types: compact custom full; ExtraDiskSpaceRequired: 37350210
Name: "Languages\Galician"; Description: "{cm:Galician}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 5520499
Name: "Languages\Georgian"; Description: "{cm:Georgian}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 6219735
Name: "Languages\German"; Description: "{cm:German}"; Languages: en; Types: compact custom full; ExtraDiskSpaceRequired: 13367187
Name: "Languages\Gujarati"; Description: "{cm:Gujarati}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 10622356
Name: "Languages\Haitian"; Description: "{cm:Haitian}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 1349947
Name: "Languages\Hebrew"; Description: "{cm:Hebrew}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 4339016
Name: "Languages\Hindi"; Description: "{cm:Hindi}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 22717250
Name: "Languages\Hungarian"; Description: "{cm:Hungarian}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 12213770
Name: "Languages\Icelandic"; Description: "{cm:Icelandic}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 6098683
Name: "Languages\Indonesian"; Description: "{cm:Indonesian}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 6503178
Name: "Languages\Inuktitut"; Description: "{cm:Inuktitut}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 995246
Name: "Languages\Irish"; Description: "{cm:Irish}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 3482557
Name: "Languages\Italian"; Description: "{cm:Italian}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 32720949
Name: "Languages\Japanese"; Description: "{cm:Japanese}"; Languages: en; Types: compact custom full; ExtraDiskSpaceRequired: 33072615
Name: "Languages\Javanese"; Description: "{cm:Javanese}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 4404351
Name: "Languages\Kannada"; Description: "{cm:Kannada}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 35657050
Name: "Languages\Kazakh"; Description: "{cm:Kazakh}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 4529022
Name: "Languages\Khmer"; Description: "{cm:Khmer}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 48851416
Name: "Languages\Kirghiz"; Description: "{cm:Kirghiz}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 5502225
Name: "Languages\Korean"; Description: "{cm:Korean}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 13309831
Name: "Languages\Kurdish"; Description: "{cm:Kurdish}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 2020502
Name: "Languages\Lao"; Description: "{cm:Lao}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 21118927
Name: "Languages\Latin"; Description: "{cm:Latin}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 6028030
Name: "Languages\Latvian"; Description: "{cm:Latvian}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 7802105
Name: "Languages\Lithuanian"; Description: "{cm:Lithuanian}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 8916163
Name: "Languages\Macedonian"; Description: "{cm:Macedonian}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 3837583
Name: "Languages\Malay"; Description: "{cm:Malay}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 6495742
Name: "Languages\Malayalam"; Description: "{cm:Malayalam}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 8786470
Name: "Languages\Maltese"; Description: "{cm:Maltese}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 5118233
Name: "Languages\Marathi"; Description: "{cm:Marathi}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 14237379
Name: "Languages\Math"; Description: "{cm:Math}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 2251826
Name: "Languages\Middle_English"; Description: "{cm:Middle_English}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 2105888
Name: "Languages\Middle_French"; Description: "{cm:Middle_French}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 15831815
Name: "Languages\Modern_Greek"; Description: "{cm:Modern_Greek}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 5422512
Name: "Languages\Nepali"; Description: "{cm:Nepali}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 15862542
Name: "Languages\Norwegian"; Description: "{cm:Norwegian}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 8262167
Name: "Languages\Oriya"; Description: "{cm:Oriya}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 7900659
Name: "Languages\Panjabi"; Description: "{cm:Panjabi}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 10212006
Name: "Languages\Persian"; Description: "{cm:Persian}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 4803733
Name: "Languages\Polish"; Description: "{cm:Polish}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 13918058
Name: "Languages\Portuguese"; Description: "{cm:Portuguese}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 12914622
Name: "Languages\Pushto"; Description: "{cm:Pushto}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 2493826
Name: "Languages\Romanian"; Description: "{cm:Romanian}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 7957608
Name: "Languages\Russian"; Description: "{cm:Russian}"; Languages: en; Types: compact custom full; ExtraDiskSpaceRequired: 39371802
Name: "Languages\Sanskrit"; Description: "{cm:Sanskrit}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 22747749
Name: "Languages\Serbian"; Description: "{cm:Serbian}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 4611681
Name: "Languages\Sinhala"; Description: "{cm:Sinhala}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 6793740
Name: "Languages\Slovak"; Description: "{cm:Slovak}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 9126966
Name: "Languages\Slovenian"; Description: "{cm:Slovenian}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 6824064
Name: "Languages\Spanish"; Description: "{cm:Spanish}"; Languages: en; Types: compact custom full; ExtraDiskSpaceRequired: 39171233
Name: "Languages\Swahili"; Description: "{cm:Swahili}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 3861506
Name: "Languages\Swedish"; Description: "{cm:Swedish}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 9460295
Name: "Languages\Syriac"; Description: "{cm:Syriac}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 2734020
Name: "Languages\Tagalog"; Description: "{cm:Tagalog}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 4114554
Name: "Languages\Tajik"; Description: "{cm:Tajik}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 1119022
Name: "Languages\Tamil"; Description: "{cm:Tamil}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 5118600
Name: "Languages\Telugu"; Description: "{cm:Telugu}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 39318860
Name: "Languages\Thai"; Description: "{cm:Thai}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 13565168
Name: "Languages\Tibetan"; Description: "{cm:Tibetan}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 25231676
Name: "Languages\Tigrinya"; Description: "{cm:Tigrinya}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 1806235
Name: "Languages\Turkish"; Description: "{cm:Turkish}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 14069931
Name: "Languages\Uighur"; Description: "{cm:Uighur}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 2017575
Name: "Languages\Ukrainian"; Description: "{cm:Ukrainian}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 8043189
Name: "Languages\Urdu"; Description: "{cm:Urdu}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 4825658
Name: "Languages\Uzbek"; Description: "{cm:Uzbek}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 4286554
Name: "Languages\Vietnamese"; Description: "{cm:Vietnamese}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 6096118
Name: "Languages\Welsh"; Description: "{cm:Welsh}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 3789352
Name: "Languages\Yiddish"; Description: "{cm:Yiddish}"; Languages: en; Types: full; ExtraDiskSpaceRequired: 4238718
Name: "Languages\Azerbaijani"; Description: "{cm:Azerbaijani}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 6615244
Name: "Languages\Albanian"; Description: "{cm:Albanian}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 6587325
Name: "Languages\Amharic"; Description: "{cm:Amharic}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 2953500
Name: "Languages\English"; Description: "{cm:English}"; Languages: ru; Types: compact custom full; ExtraDiskSpaceRequired: 38371506
Name: "Languages\Arabic"; Description: "{cm:Arabic}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 28534834
Name: "Languages\Assamese"; Description: "{cm:Assamese}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 15827072
Name: "Languages\Afrikaans"; Description: "{cm:Afrikaans}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 5198548
Name: "Languages\Basque"; Description: "{cm:Basque}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 4969647
Name: "Languages\Belarusian"; Description: "{cm:Belarusian}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 6822594
Name: "Languages\Bengali"; Description: "{cm:Bengali}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 15552533
Name: "Languages\Burmese"; Description: "{cm:Burmese}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 69770179
Name: "Languages\Bulgarian"; Description: "{cm:Bulgarian}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 6026234
Name: "Languages\Bosnian"; Description: "{cm:Bosnian}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 5432328
Name: "Languages\Welsh"; Description: "{cm:Welsh}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 3789352
Name: "Languages\Hungarian"; Description: "{cm:Hungarian}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 12213770
Name: "Languages\Vietnamese"; Description: "{cm:Vietnamese}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 6096118
Name: "Languages\Haitian"; Description: "{cm:Haitian}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 1349947
Name: "Languages\Galician"; Description: "{cm:Galician}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 5520499
Name: "Languages\Dutch"; Description: "{cm:Dutch}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 17098919
Name: "Languages\Georgian"; Description: "{cm:Georgian}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 6219735
Name: "Languages\Gujarati"; Description: "{cm:Gujarati}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 10622356
Name: "Languages\Danish"; Description: "{cm:Danish}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 7340575
Name: "Languages\Dzongkha"; Description: "{cm:Dzongkha}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 3310882
Name: "Languages\Ancient_Greek"; Description: "{cm:Ancient_Greek}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 5182527
Name: "Languages\Hebrew"; Description: "{cm:Hebrew}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 4339016
Name: "Languages\Yiddish"; Description: "{cm:Yiddish}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 4238718
Name: "Languages\Indonesian"; Description: "{cm:Indonesian}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 6503178
Name: "Languages\Inuktitut"; Description: "{cm:Inuktitut}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 995246
Name: "Languages\Irish"; Description: "{cm:Irish}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 3482557
Name: "Languages\Icelandic"; Description: "{cm:Icelandic}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 6098683
Name: "Languages\Spanish"; Description: "{cm:Spanish}"; Languages: ru; Types: compact custom full; ExtraDiskSpaceRequired: 39171233
Name: "Languages\Italian"; Description: "{cm:Italian}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 32720949
Name: "Languages\Kazakh"; Description: "{cm:Kazakh}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 4529022
Name: "Languages\Kannada"; Description: "{cm:Kannada}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 35657050
Name: "Languages\Catalan"; Description: "{cm:Catalan}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 5356190
Name: "Languages\Cebuano"; Description: "{cm:Cebuano}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 1686752
Name: "Languages\Kirghiz"; Description: "{cm:Kirghiz}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 5502225
Name: "Languages\Chineese_traditional"; Description: "{cm:Chineese_traditional}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 56692327
Name: "Languages\Chineese_simplified"; Description: "{cm:Chineese_simplified}"; Languages: ru; Types: compact custom full; ExtraDiskSpaceRequired: 42089623
Name: "Languages\Korean"; Description: "{cm:Korean}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 13309831
Name: "Languages\Kurdish"; Description: "{cm:Kurdish}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 2020502
Name: "Languages\Khmer"; Description: "{cm:Khmer}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 48851416
Name: "Languages\Lao"; Description: "{cm:Lao}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 21118927
Name: "Languages\Latin"; Description: "{cm:Latin}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 6028030
Name: "Languages\Latvian"; Description: "{cm:Latvian}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 7802105
Name: "Languages\Lithuanian"; Description: "{cm:Lithuanian}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 8916163
Name: "Languages\Macedonian"; Description: "{cm:Macedonian}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 3837583
Name: "Languages\Malay"; Description: "{cm:Malay}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 6495742
Name: "Languages\Malayalam"; Description: "{cm:Malayalam}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 8786470
Name: "Languages\Maltese"; Description: "{cm:Maltese}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 5118233
Name: "Languages\Marathi"; Description: "{cm:Marathi}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 14237379
Name: "Languages\Math"; Description: "{cm:Math}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 2251826
Name: "Languages\German"; Description: "{cm:German}"; Languages: ru; Types: compact custom full; ExtraDiskSpaceRequired: 13367187
Name: "Languages\Nepali"; Description: "{cm:Nepali}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 15862542
Name: "Languages\Modern_Greek"; Description: "{cm:Modern_Greek}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 5422512
Name: "Languages\Norwegian"; Description: "{cm:Norwegian}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 8262167
Name: "Languages\Oriya"; Description: "{cm:Oriya}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 7900659
Name: "Languages\Panjabi"; Description: "{cm:Panjabi}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 10212006
Name: "Languages\Persian"; Description: "{cm:Persian}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 4803733
Name: "Languages\Polish"; Description: "{cm:Polish}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 13918058
Name: "Languages\Portuguese"; Description: "{cm:Portuguese}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 12914622
Name: "Languages\Pushto"; Description: "{cm:Pushto}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 2493826
Name: "Languages\Romanian"; Description: "{cm:Romanian}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 7957608
Name: "Languages\Russian"; Description: "{cm:Russian}"; Languages: ru; Types: compact custom full; ExtraDiskSpaceRequired: 39371802
Name: "Languages\Sanskrit"; Description: "{cm:Sanskrit}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 22747749
Name: "Languages\Serbian"; Description: "{cm:Serbian}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 4611681
Name: "Languages\Sinhala"; Description: "{cm:Sinhala}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 6793740
Name: "Languages\Syriac"; Description: "{cm:Syriac}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 2734020
Name: "Languages\Slovak"; Description: "{cm:Slovak}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 9126966
Name: "Languages\Slovenian"; Description: "{cm:Slovenian}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 6824064
Name: "Languages\Middle_English"; Description: "{cm:Middle_English}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 2105888
Name: "Languages\Middle_French"; Description: "{cm:Middle_French}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 15831815
Name: "Languages\Swahili"; Description: "{cm:Swahili}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 3861506
Name: "Languages\Tagalog"; Description: "{cm:Tagalog}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 4114554
Name: "Languages\Tajik"; Description: "{cm:Tajik}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 1119022
Name: "Languages\Thai"; Description: "{cm:Thai}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 13565168
Name: "Languages\Tamil"; Description: "{cm:Tamil}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 5118600
Name: "Languages\Telugu"; Description: "{cm:Telugu}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 39318860
Name: "Languages\Tibetan"; Description: "{cm:Tibetan}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 25231676
Name: "Languages\Tigrinya"; Description: "{cm:Tigrinya}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 1806235
Name: "Languages\Turkish"; Description: "{cm:Turkish}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 14069931
Name: "Languages\Uzbek"; Description: "{cm:Uzbek}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 4286554
Name: "Languages\Uighur"; Description: "{cm:Uighur}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 2017575
Name: "Languages\Ukrainian"; Description: "{cm:Ukrainian}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 8043189
Name: "Languages\Urdu"; Description: "{cm:Urdu}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 4825658
Name: "Languages\Finnish"; Description: "{cm:Finnish}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 13274908
Name: "Languages\Frankish"; Description: "{cm:Frankish}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 16451109
Name: "Languages\French"; Description: "{cm:French}"; Languages: ru; Types: compact custom full; ExtraDiskSpaceRequired: 37350210
Name: "Languages\Hindi"; Description: "{cm:Hindi}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 22717250
Name: "Languages\Croatian"; Description: "{cm:Croatian}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 9135966
Name: "Languages\Cherokee"; Description: "{cm:Cherokee}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 1083194
Name: "Languages\Czech"; Description: "{cm:Czech}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 11896327
Name: "Languages\Swedish"; Description: "{cm:Swedish}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 9460295
Name: "Languages\Esperanto"; Description: "{cm:Esperanto}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 6602178
Name: "Languages\Estonian"; Description: "{cm:Estonian}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 9644486
Name: "Languages\Javanese"; Description: "{cm:Javanese}"; Languages: ru; Types: full; ExtraDiskSpaceRequired: 4404351
Name: "Languages\Japanese"; Description: "{cm:Japanese}"; Languages: ru; Types: compact custom full; ExtraDiskSpaceRequired: 33072615
[CustomMessages]
en.Languages=OCR Languages
en.Afrikaans=Afrikaans
en.Albanian=Albanian
en.Amharic=Amharic
en.Ancient_Greek=Ancient Greek
en.Arabic=Arabic
en.Assamese=Assamese
en.Azerbaijani=Azerbaijani
en.Basque=Basque
en.Belarusian=Belarusian
en.Bengali=Bengali
en.Bosnian=Bosnian
en.Bulgarian=Bulgarian
en.Burmese=Burmese
en.Catalan=Catalan
en.Cebuano=Cebuano
en.Cherokee=Cherokee
en.Chineese_simplified=Chineese simplified
en.Chineese_traditional=Chineese traditional
en.Croatian=Croatian
en.Czech=Czech
en.Danish=Danish
en.Dutch=Dutch
en.Dzongkha=Dzongkha
en.English=English
en.Esperanto=Esperanto
en.Estonian=Estonian
en.Finnish=Finnish
en.Frankish=Frankish
en.French=French
en.Galician=Galician
en.Georgian=Georgian
en.German=German
en.Gujarati=Gujarati
en.Haitian=Haitian
en.Hebrew=Hebrew
en.Hindi=Hindi
en.Hungarian=Hungarian
en.Icelandic=Icelandic
en.Indonesian=Indonesian
en.Inuktitut=Inuktitut
en.Irish=Irish
en.Italian=Italian
en.Japanese=Japanese
en.Javanese=Javanese
en.Kannada=Kannada
en.Kazakh=Kazakh
en.Khmer=Khmer
en.Kirghiz=Kirghiz
en.Korean=Korean
en.Kurdish=Kurdish
en.Lao=Lao
en.Latin=Latin
en.Latvian=Latvian
en.Lithuanian=Lithuanian
en.Macedonian=Macedonian
en.Malay=Malay
en.Malayalam=Malayalam
en.Maltese=Maltese
en.Marathi=Marathi
en.Math=Math
en.Middle_English=Middle English
en.Middle_French=Middle French
en.Modern_Greek=Modern Greek
en.Nepali=Nepali
en.Norwegian=Norwegian
en.Oriya=Oriya
en.Panjabi=Panjabi
en.Persian=Persian
en.Polish=Polish
en.Portuguese=Portuguese
en.Pushto=Pushto
en.Romanian=Romanian
en.Russian=Russian
en.Sanskrit=Sanskrit
en.Serbian=Serbian
en.Sinhala=Sinhala
en.Slovak=Slovak
en.Slovenian=Slovenian
en.Spanish=Spanish
en.Swahili=Swahili
en.Swedish=Swedish
en.Syriac=Syriac
en.Tagalog=Tagalog
en.Tajik=Tajik
en.Tamil=Tamil
en.Telugu=Telugu
en.Thai=Thai
en.Tibetan=Tibetan
en.Tigrinya=Tigrinya
en.Turkish=Turkish
en.Uighur=Uighur
en.Ukrainian=Ukrainian
en.Urdu=Urdu
en.Uzbek=Uzbek
en.Vietnamese=Vietnamese
en.Welsh=Welsh
en.Yiddish=Yiddish
[CustomMessages]
ru.Languages=ßçûêè ðàñïîçíàâàíèÿ
ru.Afrikaans=Àôðèêààíñ
ru.Albanian=Àëáàíñêèé
ru.Amharic=Àìõàðñêèé
ru.Ancient_Greek=Äðåâíåãðå÷åñêèé
ru.Arabic=Àðàáñêèé
ru.Assamese=Àññàìñêèé
ru.Azerbaijani=Àçåðáàéäæàíñêèé
ru.Basque=Áàñêîâ
ru.Belarusian=Áåëîðóññêèé
ru.Bengali=Áåíãàëüñêèé
ru.Bosnian=Áîñíèéñêèé
ru.Bulgarian=Áîëãàðèè
ru.Burmese=Áèðìàíñêèé
ru.Catalan=Êàòàëîíñêèé
ru.Cebuano=Êåáóàíî
ru.Cherokee=×åðîêè
ru.Chineese_simplified=Êèòàéñêèé óïðîùåííûé
ru.Chineese_traditional=Êèòàéñêèé òðàäèöèîííûé
ru.Croatian=Õîðâàòñêèé
ru.Czech=×åøñêèé
ru.Danish=Äàòñêèé
ru.Dutch=Ãîëëàíäñêèé
ru.Dzongkha=Äæîíãêõà
ru.English=Àíãëèéñêèé
ru.Esperanto=Ýñïåðàíòî
ru.Estonian=Ýñòîíñêèé
ru.Finnish=Ôèíñêèé
ru.Frankish=Ôðàíêñêèé
ru.French=Ôðàíöóçñêèé
ru.Galician=Ãàëèñèéñêèé
ru.Georgian=Ãðóçèíñêèé
ru.German=Íåìåöêèé
ru.Gujarati=Ãóäæàðàòè
ru.Haitian=Ãàèòè
ru.Hebrew=Èâðèò
ru.Hindi=Õèíäè
ru.Hungarian=Âåíãåðñêèé
ru.Icelandic=Èñëàíäñêèé
ru.Indonesian=Èíäîíåçèéñêèé
ru.Inuktitut=Èíóêòèòóò
ru.Irish=Èðëàíäñêèé
ru.Italian=Èòàëüÿíñêèé
ru.Japanese=ßïîíñêèé
ru.Javanese=ßâàíñêèé
ru.Kannada=Êàííàäà
ru.Kazakh=Êàçàõñêèé
ru.Khmer=Êõìåðñêèé
ru.Kirghiz=Êèðãèçñêèé
ru.Korean=Êîðåéñêèé
ru.Kurdish=Êóðäñêèé
ru.Lao=Ëàî
ru.Latin=Ëàòèíñêèé
ru.Latvian=Ëàòûøñêèé
ru.Lithuanian=Ëèòîâñêèé
ru.Macedonian=Ìàêåäîíñêèé
ru.Malay=Ìàëàéñêèé
ru.Malayalam=Ìàëàÿëàì
ru.Maltese=Ìàëüòèéñêèé
ru.Marathi=Ìàðàòõè
ru.Math=Ìàòåìàòèêà
ru.Middle_English=Ñðåäíåâåêîâûé àíãëèéñêèé
ru.Middle_French=Ñðåäíåâåêîâûé ôðàíöóçñêèé
ru.Modern_Greek=Íîâîãðå÷åñêèé
ru.Nepali=Íåïàëüñêèé
ru.Norwegian=Íîðâåæñêèé
ru.Oriya=Îðèÿ
ru.Panjabi=Ïàíäæàáè
ru.Persian=Ïåðñèäñêèé
ru.Polish=Ïîëüñêèé
ru.Portuguese=Ïîðòóãàëüñêèé
ru.Pushto=Ïóøòó
ru.Romanian=Ðóìûíñêèé
ru.Russian=Ðóññêèé
ru.Sanskrit=Ñàíñêðèò
ru.Serbian=Ñåðáñêèé
ru.Sinhala=Ñèíãàëüñêèé
ru.Slovak=Ñëîâàöêèé
ru.Slovenian=Ñëîâåíñêèé
ru.Spanish=Èñïàíñêèé
ru.Swahili=Ñóàõèëè
ru.Swedish=Øâåäñêèé
ru.Syriac=Ñèðèéñêèé
ru.Tagalog=Òàãàëüñêèé
ru.Tajik=Òàäæèêèñêèé
ru.Tamil=Òàìèë
ru.Telugu=Òåëóãó
ru.Thai=Òàéñêèé
ru.Tibetan=Òèáåòñêèé
ru.Tigrinya=Òèãðàè
ru.Turkish=Òóðåöêèé
ru.Uighur=Óéãóðñêèé
ru.Ukrainian=Óêðàèíñêèé
ru.Urdu=Óðäó
ru.Uzbek=Óçáåêñêèé
ru.Vietnamese=Âüåòíàìñêèé
ru.Welsh=Âàëëèéñêèé
ru.Yiddish=Èäèø

View File

@ -1,78 +0,0 @@
[LangOptions]
LanguageName=<0420><0443><0441><0441><043A><0438><0439>
LanguageID=$0419
LanguageCodePage=1251
[CustomMessages]
; *** Components
CreateStartupIcon=Äîáàâèòü â àâòîçàïóñê
Executables=Èñïîëíÿåìûå ôàéëû
Libraries=Áèáëèîòåêè
Languages=ßçûêè
AncientGreek=Äðåâíåãðå÷åñêèé
Esperantoalternative=Ýñïåðàíòî àëüòåðíàòèâíûé
English=Àíãëèéñêèé
Ukrainian=Óêðàèíñêèé
Turkish=Òóðåöêèé
Thai=Òàéñêèé
Tagalog=Òàãàëüñêèé
Telugu=Òåëóãó
Tamil=Òàìèëüñêèé
Swedish=Øâåäñêèé
Swahili=Ñóàõèëè
Serbian=Ñåðáñêèé
Albanian=Àëáàíñêèé
Spanish=Èñïàíñêèé
Slovenian=Ñëîâåíñêèé
Slovakian=Ñëîâàöêèé
Romanian=Ðóìûíñêèé
Portuguese=Ïîðòóãàëüñêèé
Polish=Ïîëüñêèé
Norwegian=Íîðâåæñêèé
Dutch=Ãîëëàíäñêèé
Malay=Ìàëàéñêèé
Maltese=Ìàëüòèéñêèé
Macedonian=Ìàêåäîíñêèé
Malayalam=Ìàëàÿëàì
Lithuanian=Ëèòîâñêèé
Latvian=Ëàòûøñêèé
Korean=Êîðåéñêèé
Kannada=Êàííàäà
Italian=Èòàëüÿíñêèé
Icelandic=Èñëàíäñêèé
Indonesian=Èíäîíåçèéñêèé
Cherokee=×åðîêè
Hungarian=Âåíãåðñêèé
Croatian=Õîðâàòñêèé
Hindi=Õèíäè
Hebrew=Èâðèò
Galician=Ãàëèöêèé
MiddleFrench=Ñðåäíåâåêîâûé Ôðàíöóçñêèé
Frankish=Ôðàíêñêèé
French=Ôðàíöóçñêèé
Finnish=Ôèíñêèé
Basque=Áàñêñêèé
Estonian=Ýñòîíñêèé
MathEquation=Ìàòåìàòèêà / óðàâíåíèå
Esperanto=Ýñïåðàíòî
MiddleEnglish=Ñðåäíåâåêîâûé Àíãëèéñêèé
Greek=Ãðå÷åñêèé
German=Íåìåöêèé
Danish=Äàòñêèé
Czech=×åøñêèé
Catalan=Êàòàëîíñêèé
Bulgarian=Áîëãàðñêèé
Bengali=Áåíãàëüñêèé
Belarusian=Áåëîðóññêèé
Azerbaijani=Àçåðáàéäæàíñêèé
Arabic=Àðàáñêèé
Afrikaans=Àôðèêààíñ
Japanese=ßïîíñêèé
ChineseSimplified=Êèòàéñêèé (óïðîùåííûé)
ChineseTraditional=Êèòàéñêèé (òðàäèöèîííûé)
Russian=Ðóññêèé
Vietnamese=Âüåòíàìñêèé

View File

@ -1,26 +0,0 @@
#Changes.
## 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.

BIN
images/STIcon.xcf Normal file

Binary file not shown.

BIN
images/STIconBlue.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
images/STIconGreen.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
images/STIconOrange.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
images/STIconRed.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

View File

@ -1,12 +1,23 @@
#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[])
{
QApplication a(argc, argv);
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);
@ -14,12 +25,11 @@ int main(int argc, char *argv[])
QTranslator translator;
// Set default to english.
if (translator.load (QLocale::system (), "translation", "_", ":/translations") ||
translator.load (":/translations/translation_en"))
{
a.installTranslator(&translator);
translator.load (":/translations/translation_en")) {
a.installTranslator (&translator);
}
Manager manager;
return a.exec();
return a.exec ();
}

8
scripts/get_deps.sh Executable file
View File

@ -0,0 +1,8 @@
#!/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

14
scripts/get_tessdata.sh Executable file
View File

@ -0,0 +1,14 @@
#!/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

5
scripts/install_deps.sh Executable file
View File

@ -0,0 +1,5 @@
#!/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

19
scripts/make_all.sh Executable file
View File

@ -0,0 +1,19 @@
#!/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"

12
scripts/make_app.sh Executable file
View File

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

59
scripts/make_deb.sh Executable file
View File

@ -0,0 +1,59 @@
#!/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

54
scripts/make_deps.sh Executable file
View File

@ -0,0 +1,54 @@
#!/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"

49
scripts/make_iss.sh Executable file
View File

@ -0,0 +1,49 @@
#!/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"

21
scripts/make_sf.sh Executable file
View File

@ -0,0 +1,21 @@
#!/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

56
scripts/options.sh Executable file
View File

@ -0,0 +1,56 @@
#!/bin/bash
set -e
PLATFORM=linux
CLEAN=false
JOBS=""
QT_CHOOSER="-qt=qt5"
QMAKE=qmake
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_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
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

33
translators/bing.js Normal file
View File

@ -0,0 +1,33 @@
var isPageLoaded = false;
var isTranslationFinished = false; // async translation request
var isScheduled = false;
function checkFinished () {
if (!isPageLoaded || !isTranslationFinished || isScheduled) return;
isScheduled = true;
setTimeout(function () {
var spans = [].slice.call (document.querySelectorAll ('#OutputText span'));
var text = spans.reduce (function (res, i) {
return res + i.innerText;
}, '');
st_wtp.translated (text);
}, 2000); // wait for gui fill
}
function onResourceLoad (url) {
if (url.indexOf ('/api.microsofttranslator.com/') > -1) {
isTranslationFinished = true;
checkFinished ();
}
}
st_wtp.resourceLoaded.connect (onResourceLoad);
function onPageLoad () {
isPageLoaded = true;
checkFinished ();
}
window.onload = onPageLoad();
function translate (){
var url = 'https://bing.com/translator/?text=' + st_wtp.sourceText + '#auto/' +
st_wtp.resultLanguage;
window.location = encodeURI (url);
}

34
translators/google.js Normal file
View File

@ -0,0 +1,34 @@
var isPageLoaded = false;
var isTranslationFinished = false; // async translation request
var isScheduled = false;
function checkFinished () {
if (!isPageLoaded || !isTranslationFinished || isScheduled) return;
isScheduled = true;
setTimeout(function () {
var spans = [].slice.call (document.querySelectorAll ('#result_box > span'));
var text = spans.reduce (function (res, i) {
return res + ' ' + i.innerText;
}, '');
st_wtp.translated (text);
isTranslationFinished = isScheduled = false;
}, 2000); // wait for gui fill
}
function onResourceLoad (url) {
if (url.indexOf ('/translate_a/single') > -1) {
isTranslationFinished = true;
checkFinished ();
}
}
st_wtp.resourceLoaded.connect (onResourceLoad);
function onPageLoad () {
isPageLoaded = true;
checkFinished ();
}
window.onload = onPageLoad();
function translate (){
var url = 'https://translate.google.com/#auto/' +
st_wtp.resultLanguage + '/' + st_wtp.sourceText;
window.location = encodeURI (url);
}

31
translators/yandex.js Normal file
View File

@ -0,0 +1,31 @@
var isPageLoaded = false;
var isTranslationFinished = true; // async translation request
var isScheduled = false;
function checkFinished () {
if (!isPageLoaded || !isTranslationFinished || isScheduled) return;
isScheduled = true;
setTimeout(function () {
var spans = [].slice.call (document.querySelectorAll ('#translation > span'));
var text = spans.reduce (function (res, i) {
return res + i.innerText;
}, '');
st_wtp.translated (text);
}, 2000); // wait for gui fill
}
function onResourceLoad (url) {
}
st_wtp.resourceLoaded.connect (onResourceLoad);
function onPageLoad () {
isPageLoaded = true;
checkFinished ();
}
window.onload = onPageLoad();
function translate (){
var url = 'https://translate.yandex.ru/?text=' + st_wtp.sourceText + '&lang=auto-' +
st_wtp.resultLanguage;
url = url.replace(new RegExp(' ','g') , '%20')
console.log(encodeURI(url));
window.location = (url);
}

1578
uncrustify.cfg Normal file

File diff suppressed because it is too large Load Diff

31
version.json Normal file
View File

@ -0,0 +1,31 @@
{
"version": 1,
"url": "https://cdn.rawgit.com/OneMoreGres/ScreenTranslator/master/version.json",
"Application": {
"version": 1,
"compatibleVersion": 1,
"compatibleVersion_linux": 999,
"built_in": true,
"versionString": "2.0.0",
"permissions": "0x7755",
"url_win": "https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/releases/2.0.0/ScreenTranslator.exe",
"path_win": "ScreenTranslator.exe",
"url_linux": "disabled",
"path_linux": "ScreenTranslator"
},
"Bing translator": {
"version": 1,
"url": "https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/bing.js",
"path": "translators/bing.js"
},
"Google translator": {
"version": 1,
"url": "https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/google.js",
"path": "translators/google.js"
},
"Yandex translator": {
"version": 1,
"url": "https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/yandex.js",
"path": "translators/yandex.js"
}
}