diff --git a/.gitignore b/.gitignore index a6f318a..571c6b0 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,6 @@ *.user *.exe -distr/content/ \ No newline at end of file +distr/content/ + +*.tar.gz diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..e981e6c --- /dev/null +++ b/.travis.yml @@ -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 diff --git a/3rd-party/qtsingleapplication/qtlocalpeer.cpp b/3rd-party/qtsingleapplication/qtlocalpeer.cpp new file mode 100644 index 0000000..c7ce527 --- /dev/null +++ b/3rd-party/qtsingleapplication/qtlocalpeer.cpp @@ -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 +#include +#include + +#if defined(Q_OS_WIN) +#include +#include +typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*); +static PProcessIdToSessionId pProcessIdToSessionId = 0; +#endif +#if defined(Q_OS_UNIX) +#include +#include +#include +#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) +} diff --git a/3rd-party/qtsingleapplication/qtlocalpeer.h b/3rd-party/qtsingleapplication/qtlocalpeer.h new file mode 100644 index 0000000..1b533b1 --- /dev/null +++ b/3rd-party/qtsingleapplication/qtlocalpeer.h @@ -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 +#include +#include + +#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 diff --git a/3rd-party/qtsingleapplication/qtlockedfile.cpp b/3rd-party/qtsingleapplication/qtlockedfile.cpp new file mode 100644 index 0000000..c142a86 --- /dev/null +++ b/3rd-party/qtsingleapplication/qtlockedfile.cpp @@ -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. +*/ diff --git a/3rd-party/qtsingleapplication/qtlockedfile.h b/3rd-party/qtsingleapplication/qtlockedfile.h new file mode 100644 index 0000000..84c18e5 --- /dev/null +++ b/3rd-party/qtsingleapplication/qtlockedfile.h @@ -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 +#ifdef Q_OS_WIN +#include +#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 rmutexes; + QString mutexname; + + Qt::HANDLE getMutexHandle(int idx, bool doCreate); + bool waitMutex(Qt::HANDLE mutex, bool doBlock); + +#endif + LockMode m_lock_mode; +}; +} +#endif diff --git a/3rd-party/qtsingleapplication/qtlockedfile_unix.cpp b/3rd-party/qtsingleapplication/qtlockedfile_unix.cpp new file mode 100644 index 0000000..976c1b9 --- /dev/null +++ b/3rd-party/qtsingleapplication/qtlockedfile_unix.cpp @@ -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 +#include +#include +#include + +#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(); +} + diff --git a/3rd-party/qtsingleapplication/qtlockedfile_win.cpp b/3rd-party/qtsingleapplication/qtlockedfile_win.cpp new file mode 100644 index 0000000..5e21262 --- /dev/null +++ b/3rd-party/qtsingleapplication/qtlockedfile_win.cpp @@ -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 +#include + +#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); +} diff --git a/3rd-party/qtsingleapplication/qtsingleapplication.cpp b/3rd-party/qtsingleapplication/qtsingleapplication.cpp new file mode 100644 index 0000000..d0fb15d --- /dev/null +++ b/3rd-party/qtsingleapplication/qtsingleapplication.cpp @@ -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 + + +/*! + \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 +*/ diff --git a/3rd-party/qtsingleapplication/qtsingleapplication.h b/3rd-party/qtsingleapplication/qtsingleapplication.h new file mode 100644 index 0000000..049406f --- /dev/null +++ b/3rd-party/qtsingleapplication/qtsingleapplication.h @@ -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 + +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 diff --git a/3rd-party/qtsingleapplication/qtsingleapplication.pri b/3rd-party/qtsingleapplication/qtsingleapplication.pri new file mode 100644 index 0000000..51f30cc --- /dev/null +++ b/3rd-party/qtsingleapplication/qtsingleapplication.pri @@ -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 +} diff --git a/3rd-party/qtsingleapplication/qtsinglecoreapplication.cpp b/3rd-party/qtsingleapplication/qtsinglecoreapplication.cpp new file mode 100644 index 0000000..5634537 --- /dev/null +++ b/3rd-party/qtsingleapplication/qtsinglecoreapplication.cpp @@ -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() +*/ diff --git a/3rd-party/qtsingleapplication/qtsinglecoreapplication.h b/3rd-party/qtsingleapplication/qtsinglecoreapplication.h new file mode 100644 index 0000000..b87fffe --- /dev/null +++ b/3rd-party/qtsingleapplication/qtsinglecoreapplication.h @@ -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 + +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 diff --git a/3rd-party/qtsingleapplication/qtsinglecoreapplication.pri b/3rd-party/qtsingleapplication/qtsinglecoreapplication.pri new file mode 100644 index 0000000..d2d6cc3 --- /dev/null +++ b/3rd-party/qtsingleapplication/qtsinglecoreapplication.pri @@ -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) +} diff --git a/GlobalActionHelper.cpp b/GlobalActionHelper.cpp index 349265e..22eac9f 100644 --- a/GlobalActionHelper.cpp +++ b/GlobalActionHelper.cpp @@ -1,92 +1,192 @@ #include "GlobalActionHelper.h" -#include - #include #include -QHash, QAction*> GlobalActionHelper::actions_; +QHash, 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 +# include +# include + +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(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(message); + if (event->response_type == XCB_KEY_PRESS) { + xcb_key_press_event_t *keyEvent = static_cast(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 + + +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(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: @@ -201,7 +298,7 @@ quint32 GlobalActionHelper::nativeKeycode(Qt::Key key) case Qt::Key_VolumeMute: return VK_VOLUME_MUTE; - // numbers + // numbers case Qt::Key_0: case Qt::Key_1: case Qt::Key_2: @@ -214,7 +311,7 @@ quint32 GlobalActionHelper::nativeKeycode(Qt::Key key) case Qt::Key_9: return key; - // letters + // letters case Qt::Key_A: case Qt::Key_B: case Qt::Key_C: @@ -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 diff --git a/GlobalActionHelper.h b/GlobalActionHelper.h index 05e2826..7924e51 100644 --- a/GlobalActionHelper.h +++ b/GlobalActionHelper.h @@ -6,23 +6,23 @@ #include #include -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, QAction*> actions_; + static QHash, 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); }; diff --git a/GoogleWebTranslator.cpp b/GoogleWebTranslator.cpp deleted file mode 100644 index 74fc54f..0000000 --- a/GoogleWebTranslator.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#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); -} diff --git a/GoogleWebTranslator.h b/GoogleWebTranslator.h deleted file mode 100644 index b48cc82..0000000 --- a/GoogleWebTranslator.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef GOOGLEWEBTRANSLATOR_H -#define GOOGLEWEBTRANSLATOR_H - -#include - -#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 queue_; - QString translationLanguage_; - QWebView *view_; - bool isLoadFinished_; - bool isTranslationFinished_; -}; - -#endif // GOOGLEWEBTRANSLATOR_H diff --git a/ImageProcessing.cpp b/ImageProcessing.cpp index e329674..2e25dff 100644 --- a/ImageProcessing.cpp +++ b/ImageProcessing.cpp @@ -7,146 +7,150 @@ #include "ImageProcessing.h" #include "StAssert.h" -#ifdef WIN32 -#include -qint64 getFreeMemory () -{ +#if defined(Q_OS_LINUX) +# include +# include +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 +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); + l_int32 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 _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 _grayscaleCT(256); - for (int i = 0; i < 256; i++) { - _grayscaleCT.append(qRgb(i, i, i)); + QVector _grayscaleCT (256); + for (int i = 0; i < 256; 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; - qint32 actualSize = gray->w * gray->h * gray->d / 8; - float maxScaleMemory = float (availableMemory) / actualSize; - scale = std::min (scale, maxScaleMemory); -#endif - + if (availableMemory > 0) { + qint32 actualSize = gray->w * gray->h * gray->d / 8; + float maxScaleMemory = float (availableMemory) / actualSize; + scale = std::min (scale, maxScaleMemory); + } scaled = pixScale (gray, scale, scale); + if (scaled == NULL) { + scaled = gray; + } } - ST_ASSERT (scaled != NULL); - if (scaled != gray) - { + if (scaled != gray) { pixDestroy (&gray); } return scaled; } -void cleanupImage(Pix **image) -{ +void cleanupImage (Pix **image) { pixDestroy (image); } diff --git a/ImageProcessing.h b/ImageProcessing.h index e8c3dc3..61c8c1c 100644 --- a/ImageProcessing.h +++ b/ImageProcessing.h @@ -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 diff --git a/LICENSE.md b/LICENSE.md index e06e546..22dbc5c 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -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 diff --git a/LanguageHelper.cpp b/LanguageHelper.cpp index 11c180e..883c4f0 100644 --- a/LanguageHelper.cpp +++ b/LanguageHelper.cpp @@ -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"); + } diff --git a/LanguageHelper.h b/LanguageHelper.h index b9599e9..ac04d86 100644 --- a/LanguageHelper.h +++ b/LanguageHelper.h @@ -3,28 +3,32 @@ #include #include +#include -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 (); diff --git a/Manager.cpp b/Manager.cpp index 213c47c..7f3a6f9 100644 --- a/Manager.cpp +++ b/Manager.cpp @@ -5,89 +5,105 @@ #include #include #include +#include #include #include #include #include +#include +#include #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(); // 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 actions; + actions << captureAction_ << repeatCaptureAction_ << repeatAction_ << clipboardAction_; + QList 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 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 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 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 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) - .arg (__DATE__).arg (__TIME__); + "ВерÑиÑ: %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)); } diff --git a/Manager.h b/Manager.h index 443f01c..74bb66a 100644 --- a/Manager.h +++ b/Manager.h @@ -3,6 +3,7 @@ #include #include +#include #include "ProcessingItem.h" @@ -12,46 +13,72 @@ class QMenu; class SelectionDialog; class ResultDialog; class LanguageHelper; +class Updater; + +class Manager : public QObject { + Q_OBJECT + + enum IconType { + IconTypeNormal, IconTypeWorking, IconTypeError, IconTypeSuccess + }; -class Manager : public QObject -{ - Q_OBJECT 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 selections_; + ResultDialog *resultDialog_; + Updater *updater_; + QTimer *updateTimer_; + QAction *captureAction_; + QAction *repeatCaptureAction_; + QAction *repeatAction_; + QAction *clipboardAction_; bool useResultDialog_; + //! Used threads. For proper termination. + QList threads_; + QString defaultTranslationLanguage_; + QString defaultOrcLanguage_; + bool doTranslation_; + int itemProcessingCount_; }; #endif // MANAGER_H diff --git a/ProcessingItem.cpp b/ProcessingItem.cpp index f0f4102..df08fb1 100644 --- a/ProcessingItem.cpp +++ b/ProcessingItem.cpp @@ -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 &= (!recognized.isEmpty ()); - valid &= (!translated.isEmpty ()); + valid &= (!ocrLanguage.isEmpty ()); + if (!checkOnlyInput) { + valid &= (!recognized.isEmpty ()); + } return valid; } diff --git a/ProcessingItem.h b/ProcessingItem.h index 3d43da7..c5b7576 100644 --- a/ProcessingItem.h +++ b/ProcessingItem.h @@ -3,18 +3,22 @@ #include -struct ProcessingItem -{ - QPoint screenPos; - QPixmap source; - QString recognized; - QString translated; +struct ProcessingItem { + ProcessingItem (); + QPoint screenPos; + QPixmap source; + QString recognized; + QString translated; - QString ocrLanguage; - QString sourceLanguage; + 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 diff --git a/README.md b/README.md index df927c9..1aa8631 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/Recognizer.cpp b/Recognizer.cpp index b99031a..ce94ace 100644 --- a/Recognizer.cpp +++ b/Recognizer.cpp @@ -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) - { - QString language = (isCustomLanguage) ? item.ocrLanguage : ocrLanguage_; - if (!initEngine (engine, language)) - { +void Recognizer::recognize (ProcessingItem item) { + if (!item.isValid (true)) { + emit recognized (item); + return; + } + bool isCustomLanguage = (item.ocrLanguage != ocrLanguage_); + tesseract::TessBaseAPI *engine = (isCustomLanguage) ? NULL : engine_; + QString language = (isCustomLanguage) ? item.ocrLanguage : ocrLanguage_; + if (engine == NULL) { + if (!initEngine (engine, language)) { + emit recognized (item); return; } } - Pix* image = prepareImage (item.source.toImage (), imageScale_); + 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); } diff --git a/Recognizer.h b/Recognizer.h index e2c9eb5..b7e5760 100644 --- a/Recognizer.h +++ b/Recognizer.h @@ -6,16 +6,16 @@ #include "ProcessingItem.h" -namespace tesseract -{ +namespace tesseract { class TessBaseAPI; } +class RecognizerHelper; + +class Recognizer : public QObject { + Q_OBJECT -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_; diff --git a/RecognizerHelper.cpp b/RecognizerHelper.cpp new file mode 100644 index 0000000..8510e14 --- /dev/null +++ b/RecognizerHelper.cpp @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include + +#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) { +} diff --git a/RecognizerHelper.h b/RecognizerHelper.h new file mode 100644 index 0000000..eff2e15 --- /dev/null +++ b/RecognizerHelper.h @@ -0,0 +1,33 @@ +#ifndef RECOGNIZERHELPER_H +#define RECOGNIZERHELPER_H + +#include + +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 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 diff --git a/Recources.qrc b/Recources.qrc index 920e5ba..e636270 100644 --- a/Recources.qrc +++ b/Recources.qrc @@ -2,6 +2,10 @@ translations/translation_en.qm translations/translation_ru.qm - images/icon.png + images/STIconBlue.png + images/STIconGreen.png + images/STIconOrange.png + images/STIconRed.png + version.json diff --git a/ResultDialog.cpp b/ResultDialog.cpp index aeb8ef3..3ed3420 100644 --- a/ResultDialog.cpp +++ b/ResultDialog.cpp @@ -1,69 +1,121 @@ #include "ResultDialog.h" #include "ui_ResultDialog.h" #include "StAssert.h" +#include "LanguageHelper.h" #include +#include +#include -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(event)->button (); + if (button == Qt::RightButton) { + QAction *action = contextMenu_->exec (QCursor::pos ()); + if (recognizeSubMenu_->findChildren ().contains (action)) { + ProcessingItem item = item_; + item.translated = item.recognized = QString (); + item.ocrLanguage = dictionary_.ocrUiToCode (action->text ()); + emit requestRecognize (item); + } + else if (translateSubMenu_->findChildren ().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 ()); - move (item.screenPos - correction); - QRect screenRect = desktop->screenGeometry (this); - int minY = screenRect.bottom () - height (); - 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); + QPoint correction = QPoint ((width () - item.source.width ()) / 2, ui->frame->lineWidth ()); + move (item.screenPos - correction); + QRect screenRect = desktop->screenGeometry (this); + int minY = screenRect.bottom () - height (); + if (y () > minY) { + move (x (), minY); } + activateWindow (); } diff --git a/ResultDialog.h b/ResultDialog.h index f4bcd15..efb54d4 100644 --- a/ResultDialog.h +++ b/ResultDialog.h @@ -2,30 +2,50 @@ #define RESULTDIALOG_H #include +#include #include "ProcessingItem.h" namespace Ui { class ResultDialog; } +class LanguageHelper; -class ResultDialog : public QDialog -{ - Q_OBJECT +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 diff --git a/ResultDialog.ui b/ResultDialog.ui index 92329f9..f7c8044 100644 --- a/ResultDialog.ui +++ b/ResultDialog.ui @@ -14,7 +14,16 @@ Результат - + + 0 + + + 0 + + + 0 + + 0 @@ -29,7 +38,16 @@ QFrame::Plain - + + 0 + + + 0 + + + 0 + + 0 @@ -49,7 +67,7 @@ - + Qt::Horizontal @@ -69,7 +87,7 @@ - + Qt::Horizontal diff --git a/ScreenTranslator.pro b/ScreenTranslator.pro index 8048c03..c7a1ec7 100644 --- a/ScreenTranslator.pro +++ b/ScreenTranslator.pro @@ -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 diff --git a/SelectionDialog.cpp b/SelectionDialog.cpp index ebb77e3..56daed3 100644 --- a/SelectionDialog.cpp +++ b/SelectionDialog.cpp @@ -8,159 +8,115 @@ #include #include -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 (event); + else if (event->type () == QEvent::MouseButtonPress) { + QMouseEvent *mouseEvent = static_cast (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 (event); + else if (event->type () == QEvent::MouseMove) { + QMouseEvent *mouseEvent = static_cast (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 (event); + else if (event->type () == QEvent::MouseButtonRelease) { + QMouseEvent *mouseEvent = static_cast (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 (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 (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 (); } diff --git a/SelectionDialog.h b/SelectionDialog.h index 18fa890..b126658 100644 --- a/SelectionDialog.h +++ b/SelectionDialog.h @@ -12,30 +12,32 @@ namespace Ui { } class LanguageHelper; -class SelectionDialog : public QDialog -{ - Q_OBJECT +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 diff --git a/Settings.h b/Settings.h index 3761466..013cd70 100644 --- a/Settings.h +++ b/Settings.h @@ -3,15 +3,23 @@ #include -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 diff --git a/SettingsEditor.cpp b/SettingsEditor.cpp index 1a44ac7..72b75c7 100644 --- a/SettingsEditor.cpp +++ b/SettingsEditor.cpp @@ -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 #include +#include +#include +#include #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 proxyTypeNames; + proxyTypeNames.insert (QNetworkProxy::NoProxy, tr ("Ðет")); + proxyTypeNames.insert (QNetworkProxy::Socks5Proxy, tr ("SOCKS 5")); + proxyTypeNames.insert (QNetworkProxy::HttpProxy, tr ("HTTP")); + QList 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(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); + } +} diff --git a/SettingsEditor.h b/SettingsEditor.h index 20b7d39..8b6f669 100644 --- a/SettingsEditor.h +++ b/SettingsEditor.h @@ -5,21 +5,28 @@ #include #include +class QTableWidgetItem; namespace Ui { class SettingsEditor; } class LanguageHelper; +class TranslatorHelper; +class RecognizerHelper; -class SettingsEditor : public QDialog -{ - Q_OBJECT +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 diff --git a/SettingsEditor.ui b/SettingsEditor.ui index 3f43331..d7a1fab 100644 --- a/SettingsEditor.ui +++ b/SettingsEditor.ui @@ -6,213 +6,15 @@ 0 0 - 435 - 221 + 553 + 456 ÐаÑтройки - - - - - ГорÑчие клавиши - - - - - - <html><head/><body><p>Сочетание клавиш Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´Ð° в режим захвата.</p></body></html> - - - Захватить - - - captureEdit - - - - - - - - - - <html><head/><body><p>Сочетание клавиш Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´Ð° в режим захвата.</p></body></html> - - - Скопировать - - - captureEdit - - - - - - - - - - <html><head/><body><p>Сочетание клавиш Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´Ð° в режим захвата.</p></body></html> - - - Повторить - - - captureEdit - - - - - - - - - - - - - РаÑпознавание - - - - - - <html><head/><body><p>Ðеобходимо Ð´Ð»Ñ Ñ€Ð°ÑпознаваниÑ.</p><p>СкачиваетÑÑ Ð¾Ñ‚Ñюда: <a href="https://code.google.com/p/tesseract-ocr/downloads/list"><span style=" text-decoration: underline; color:#0000ff;">https://code.google.com/p/tesseract-ocr/downloads/list</span></a></p></body></html> - - - Путь к tessdata - - - tessdataEdit - - - - - - - - - - ... - - - - - - - <html><head/><body><p>ЗаполнÑетÑÑ Ð½Ð° оÑновании ÑÐ¾Ð´ÐµÑ€Ð¶Ð°Ð½Ð¸Ñ tessdata</p></body></html> - - - Язык раÑÐ¿Ð¾Ð·Ð½Ð°Ð²Ð°Ð½Ð¸Ñ - - - ocrLangCombo - - - - - - - <html><head/><body><p>МаÑштабирование Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð´Ð»Ñ ÑƒÐ»ÑƒÑ‡ÑˆÐµÐ½Ð¸Ñ Ñ€Ð°ÑпознаниÑ. Больше - лучше (до определенных пределов), но медленнее.</p></body></html> - - - Увеличение маÑштаба - - - imageScaleSpin - - - - - - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - Вывод результата - - - - - - Трей - - - - - - - Окно - - - true - - - - - - - - - - Перевод - - - - - - <html><head/><body><p>Язык, на который оÑущеÑтвлÑетÑÑ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´.</p></body></html> - - - Язык результата - - - translateLangCombo - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 1 - - - - - + + Qt::Horizontal @@ -222,16 +24,459 @@ + + + + 0 + + + + Общее + + + + + + ГорÑчие клавиши + + + + + + <html><head/><body><p>Сочетание клавиш Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´Ð° в режим захвата.</p></body></html> + + + Захватить + + + + + + + + + + <html><head/><body><p>Сочетание клавиш Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´Ð° в режим захвата, но Ñ Ð¸Ñпользованием поÑледнего иÑпользованного, а не текущего, изображениÑ.</p></body></html> + + + Захватить повторно + + + + + + + + + + <html><head/><body><p>Сочетание клавиш Ð´Ð»Ñ Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€Ð½Ð¾Ð³Ð¾ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ð¾Ñледнего результата.</p></body></html> + + + Показать + + + + + + + + + + <html><head/><body><p>Сочетание клавиш Ð´Ð»Ñ ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¿Ð¾Ñледнего результата в буфер обмена.</p></body></html> + + + Скопировать + + + + + + + + + + + + + ПрокÑи + + + + + + Тип: + + + + + + + + + + Пользователь: + + + + + + + + + + ÐдреÑ: + + + + + + + + + + Пароль: + + + + + + + + + + Порт: + + + + + + + 1 + + + 65535 + + + + + + + СохранÑÑ‚ÑŒ пароль (небезопаÑно) + + + + + + + + + + + + + 0 + 0 + + + + Вывод результата + + + + + + + 0 + 0 + + + + Трей + + + + + + + + 0 + 0 + + + + Окно + + + true + + + + + + + + + + Обновление + + + + + + ПроверÑÑ‚ÑŒ обновлениÑ: + + + + + + + + + + + 0 + 0 + + + + Проверить + + + + + + + + + + + + Qt::Vertical + + + + 20 + 270 + + + + + + + + + РаÑпознавание + + + + + + <html><head/><body><p>Ðеобходимо Ð´Ð»Ñ Ñ€Ð°ÑпознаваниÑ.</p><p>СкачиваетÑÑ Ð¾Ñ‚Ñюда: <a href="https://github.com/tesseract-ocr/tessdata"><span style=" text-decoration: underline; color:#7593bc;">https://github.com/tesseract-ocr/tessdata</span></a></p><p>&quot;./&quot; означает, что папка &quot;tessdata&quot; находитÑÑ Ð² одной директории Ñ Ð¸ÑполнÑемым файлом программы.</p></body></html> + + + Путь к tessdata + + + tessdataEdit + + + + + + + + + + ... + + + + + + + <html><head/><body><p>ЗаполнÑетÑÑ Ð½Ð° оÑновании ÑÐ¾Ð´ÐµÑ€Ð¶Ð°Ð½Ð¸Ñ tessdata</p></body></html> + + + Язык раÑÐ¿Ð¾Ð·Ð½Ð°Ð²Ð°Ð½Ð¸Ñ + + + ocrLangCombo + + + + + + + + + + <html><head/><body><p>МаÑштабирование Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð´Ð»Ñ ÑƒÐ»ÑƒÑ‡ÑˆÐµÐ½Ð¸Ñ Ñ€Ð°ÑпознаниÑ. Больше - лучше (до определенных пределов), но медленнее и потреблÑет больше памÑти.</p><p>Рекомендуемые Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¾Ñ‚ 5 до 10.</p></body></html> + + + Увеличение маÑштаба + + + imageScaleSpin + + + + + + + + + + <html><head/><body><p>Символы, регулÑрно раÑпознаваемые Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°Ð¼Ð¸. При обнаружении будут заменены на указанные.</p></body></html> + + + ИÑправлениÑ: + + + Qt::AlignCenter + + + + + + + QAbstractItemView::SelectRows + + + true + + + + Язык + + + + + ИÑходный текÑÑ‚ + + + + + ИÑправление + + + + + + + + + Перевод + + + + + + <html><head/><body><p>Ðеобходимо ли переводить (вкл) раÑпознанный текÑÑ‚.</p></body></html> + + + Переводить текÑÑ‚ + + + + + + + <html><head/><body><p>Отображает окно переводчика. Следует иÑпользовать только Ð´Ð»Ñ Ñ€Ð°Ð·Ñ€Ð°Ð±Ð¾Ñ‚ÐºÐ¸ переводчиков.</p></body></html> + + + Режим отладки + + + + + + + <html><head/><body><p>МакÑимальное времÑ, которое может быть затрачено на перевод, чтобы он не ÑчиталÑÑ &quot;завиÑшим&quot;.</p></body></html> + + + МакÑимальное Ð²Ñ€ÐµÐ¼Ñ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´Ð°: + + + + + + + <html><head/><body><p>Язык, на который оÑущеÑтвлÑетÑÑ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´.</p></body></html> + + + Язык результата: + + + translateLangCombo + + + + + + + Переводчики: + + + Qt::AlignCenter + + + + + + + + + + Ñек. + + + + + + + <html><head/><body><p>Отображены в порÑдке ÑƒÐ±Ñ‹Ð²Ð°Ð½Ð¸Ñ Ð¿Ñ€Ð¸Ð¾Ñ€Ð¸Ñ‚ÐµÑ‚Ð°.</p></body></html> + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::InternalMove + + + Qt::MoveAction + + + + + + + + tabWidget captureEdit - translateLangCombo + repeatCaptureEdit + repeatEdit + clipboardEdit + trayRadio + dialogRadio + proxyTypeCombo + proxyHostEdit + proxyPortSpin + proxyUserEdit + proxyPassEdit + proxySaveCheck tessdataEdit tessdataButton ocrLangCombo imageScaleSpin - buttonBox + recognizerFixTable + doTranslationCheck + translatorDebugCheck + translateTimeoutSpin + translateLangCombo + translatorList @@ -242,8 +487,8 @@ accept() - 248 - 254 + 256 + 447 157 @@ -258,8 +503,8 @@ reject() - 316 - 260 + 324 + 447 286 diff --git a/StAssert.h b/StAssert.h index edeab86..d330cee 100644 --- a/StAssert.h +++ b/StAssert.h @@ -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 diff --git a/Translator.cpp b/Translator.cpp deleted file mode 100644 index f4c8ff0..0000000 --- a/Translator.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include "Translator.h" - -#include -#include -#include -#include -#include -#include -#include - -#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); -} diff --git a/Translator.h b/Translator.h deleted file mode 100644 index 8ef0ff7..0000000 --- a/Translator.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef TRANSLATOR_H -#define TRANSLATOR_H - -#include - -#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 items_; - bool useAlternativeTranslation_; - -}; - -#endif // TRANSLATOR_H diff --git a/TranslatorHelper.cpp b/TranslatorHelper.cpp new file mode 100644 index 0000000..cabb379 --- /dev/null +++ b/TranslatorHelper.cpp @@ -0,0 +1,76 @@ +#include +#include +#include +#include + +#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 (); +} diff --git a/TranslatorHelper.h b/TranslatorHelper.h new file mode 100644 index 0000000..40370d8 --- /dev/null +++ b/TranslatorHelper.h @@ -0,0 +1,27 @@ +#ifndef TRANSLATORHELPER_H +#define TRANSLATORHELPER_H + +#include + +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 diff --git a/Updater.cpp b/Updater.cpp new file mode 100644 index 0000000..c4fa829 --- /dev/null +++ b/Updater.cpp @@ -0,0 +1,264 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#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 (); +} diff --git a/Updater.h b/Updater.h new file mode 100644 index 0000000..8b5d17a --- /dev/null +++ b/Updater.h @@ -0,0 +1,65 @@ +#ifndef UPDATER_H +#define UPDATER_H + +#include +#include +#include + +/*! + * \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 diff --git a/Utils.cpp b/Utils.cpp new file mode 100644 index 0000000..1af0e1d --- /dev/null +++ b/Utils.cpp @@ -0,0 +1,21 @@ +#include + +#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 proxyTypeOrder () { + QList proxyOrder; + proxyOrder << QNetworkProxy::NoProxy << QNetworkProxy::Socks5Proxy << QNetworkProxy::HttpProxy; + return proxyOrder; +} diff --git a/Utils.h b/Utils.h new file mode 100644 index 0000000..680c36a --- /dev/null +++ b/Utils.h @@ -0,0 +1,10 @@ +#ifndef UTILS_H +#define UTILS_H + +#include + +QString encode (const QString &source); + +QList proxyTypeOrder (); + +#endif // UTILS_H diff --git a/WebTranslator.cpp b/WebTranslator.cpp new file mode 100644 index 0000000..1a9b166 --- /dev/null +++ b/WebTranslator.cpp @@ -0,0 +1,142 @@ +#include +#include +#include +#include +#include + +#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); +} diff --git a/WebTranslator.h b/WebTranslator.h new file mode 100644 index 0000000..8cb60ba --- /dev/null +++ b/WebTranslator.h @@ -0,0 +1,53 @@ +#ifndef WEBTRANSLATOR_H +#define WEBTRANSLATOR_H + +#include +#include +#include + +#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 queue_; + bool isReady_; + QTimer translationTimeout_; +}; + +#endif // WEBTRANSLATOR_H diff --git a/WebTranslatorProxy.cpp b/WebTranslatorProxy.cpp new file mode 100644 index 0000000..b298baa --- /dev/null +++ b/WebTranslatorProxy.cpp @@ -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_; +} + diff --git a/WebTranslatorProxy.h b/WebTranslatorProxy.h new file mode 100644 index 0000000..20ee7f8 --- /dev/null +++ b/WebTranslatorProxy.h @@ -0,0 +1,37 @@ +#ifndef WEBTRANSLATORPROXY_H +#define WEBTRANSLATORPROXY_H + +#include + +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 diff --git a/app.rc b/app.rc deleted file mode 100644 index b48038f..0000000 --- a/app.rc +++ /dev/null @@ -1 +0,0 @@ -IDI_ICON1 ICON DISCARDABLE "images/icon.ico" \ No newline at end of file diff --git a/distr/eng/Changelog.txt b/distr/Changelog_en.txt similarity index 56% rename from distr/eng/Changelog.txt rename to distr/Changelog_en.txt index 746894b..c77f70b 100644 --- a/distr/eng/Changelog.txt +++ b/distr/Changelog_en.txt @@ -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. @@ -23,4 +40,4 @@ Changes. * 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. \ No newline at end of file ++ Context menu expanded. Added buttons display the last result and copy it to the clipboard. diff --git a/distr/ru/Changelog.txt b/distr/Changelog_ru.txt similarity index 52% rename from distr/ru/Changelog.txt rename to distr/Changelog_ru.txt index c17b51b..02b4321 100644 --- a/distr/ru/Changelog.txt +++ b/distr/Changelog_ru.txt @@ -1,4 +1,21 @@ Èçìåíåíèÿ. +2.0.0: +* Äîáàâëåíà âåðñèÿ ïîä linux. +* Äîáàâëåíà ïîääåðæêà íåñêîëüêèõ ìîíèòîðîâ. +* Äîáàâëåà âîçìîæíîñòü ðàñïîçíàíèå áåç ïåðåâîäà. +* Äîáàâëåíà âîçìîæíîñòü âûçîâà ñòàðîãî ðèñóíêà äëÿ âûäåëåíèÿ. +* Äîáàâëåíà âîçìîæíîñòü ïîâòîðíîãî âûäåëåíèÿ áåç çàêðûòèÿ îêíà çàõâàòà. +* Äîáàâëåíà âîçìîæíîñòü ïîâòîðíîãî ðàñïîçíàíèÿ íà äðóãîì ÿçûêå. +* Äîáàâëåíà âîçìîæíîñòü îòîáðàæåíèÿ ïðîìåæóòî÷íîãî ðåçóëüòàòà ïðè îøèáêå ïåðåâîäà. +* Äîáàâëåíà ïîääåðæêà ðàçíûõ ñåðâèñîâ ïåðåâîäà. +* Äîáàâëåíà âîçìîæíîñòü êîïèðîâàíèÿ èçîáðàæåíèÿ â áóôåð. +* Äîáàâëåíà âîçìîæíîñòü ðåäàêöèè ðàñïîçíàííîãî òåêñòà. +* Äîáàâëåíà âîçìîæíîñòü àâòîìàòè÷åñêîé êîððåêöèè ÷àñòûõ îøèáîê ðàñïîçíàâàíèÿ. +* Äîáàâëåíà âîçìîæíîñòü èñïîëüçîâàíèÿ ïðîêñè. +* Äîáàâëåíà âîçìîæíîñòü ðàçîâîé ñìåíà ÿçûêà ïåðåâîäà è ðàñïîçíàâàíèÿ. +* Îáíîâëåíû èêîíêè. +* Äîáàâëåíî îòîáðàæåíèå ñòàòóñà ðàáîòû íà èêîíêå. +* Äîáàâëåíà âîçìîæíîñòü àâòîìàòè÷åñêîãî îáíîâëåíèÿ. 1.2.3: * Óñòðàíåíà âîçìîæíàÿ ïðè÷èíà ïàäåíèÿ. * Äîáàâëåíà èíôîðìàöèÿ î âåðñèè è íåêîòîðûå ñîîáùåíèÿ îá îøèáêàõ. @@ -23,4 +40,4 @@ - Ïîôèêñåí áàã ñ íåâåðíûì ðàçìåðîì îêíà îòîáðàæåíèÿ ðåçóëüòàòîâ. 1.1.0: - Îòîáðàæåíèå ðåçóëüòàòà â îêîøêå, âìåñòå ñ êàðòèíêîé. -- Êîíòåêñòíîå ìåíþ ðàñøèðåíî. Äîáàâëåíû êíîïêè îòîáðàæåíèÿ ïîñëåäíåãî ðåçóëüòàòà è êîïèðîâàíèÿ åãî â áóôåð îáìåíà. \ No newline at end of file +- Êîíòåêñòíîå ìåíþ ðàñøèðåíî. Äîáàâëåíû êíîïêè îòîáðàæåíèÿ ïîñëåäíåãî ðåçóëüòàòà è êîïèðîâàíèÿ åãî â áóôåð îáìåíà. diff --git a/distr/Files.xlsx b/distr/Files.xlsx deleted file mode 100644 index afbd7a4..0000000 Binary files a/distr/Files.xlsx and /dev/null differ diff --git a/distr/InnoSetup.iss b/distr/InnoSetup.iss deleted file mode 100644 index ed9f114..0000000 --- a/distr/InnoSetup.iss +++ /dev/null @@ -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 diff --git a/distr/deb/DEBIAN/control b/distr/deb/DEBIAN/control new file mode 100644 index 0000000..864145a --- /dev/null +++ b/distr/deb/DEBIAN/control @@ -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 +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. + + diff --git a/distr/deb/usr/share/applications/ScreenTranslator.desktop b/distr/deb/usr/share/applications/ScreenTranslator.desktop new file mode 100644 index 0000000..f71d72e --- /dev/null +++ b/distr/deb/usr/share/applications/ScreenTranslator.desktop @@ -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; diff --git a/distr/iss/InnoSetup.iss b/distr/iss/InnoSetup.iss new file mode 100644 index 0000000..b71bae3 --- /dev/null +++ b/distr/iss/InnoSetup.iss @@ -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 =Çàãðóçêà çàâåðøåíà diff --git a/distr/iss/LICENSE_ru.md b/distr/iss/LICENSE_ru.md new file mode 100644 index 0000000..d09a322 --- /dev/null +++ b/distr/iss/LICENSE_ru.md @@ -0,0 +1,9 @@ +Ëèöåíçèÿ MIT + +Copyright (c) 2015 Gres (gres@gres.biz) + +Äàííàÿ ëèöåíçèÿ ðàçðåøàåò ëèöàì, ïîëó÷èâøèì êîïèþ äàííîãî ïðîãðàììíîãî îáåñïå÷åíèÿ è ñîïóòñòâóþùåé äîêóìåíòàöèè (â äàëüíåéøåì èìåíóåìûìè «Ïðîãðàììíîå Îáåñïå÷åíèå»), áåçâîçìåçäíî èñïîëüçîâàòü Ïðîãðàììíîå Îáåñïå÷åíèå áåç îãðàíè÷åíèé, âêëþ÷àÿ íåîãðàíè÷åííîå ïðàâî íà èñïîëüçîâàíèå, êîïèðîâàíèå, èçìåíåíèå, äîáàâëåíèå, ïóáëèêàöèþ, ðàñïðîñòðàíåíèå, ñóáëèöåíçèðîâàíèå è/èëè ïðîäàæó êîïèé Ïðîãðàììíîãî Îáåñïå÷åíèÿ, à òàêæå ëèöàì, êîòîðûì ïðåäîñòàâëÿåòñÿ äàííîå Ïðîãðàììíîå Îáåñïå÷åíèå, ïðè ñîáëþäåíèè ñëåäóþùèõ óñëîâèé: + +Óêàçàííîå âûøå óâåäîìëåíèå îá àâòîðñêîì ïðàâå è äàííûå óñëîâèÿ äîëæíû áûòü âêëþ÷åíû âî âñå êîïèè èëè çíà÷èìûå ÷àñòè äàííîãî Ïðîãðàììíîãî Îáåñïå÷åíèÿ. + +ÄÀÍÍÎÅ ÏÐÎÃÐÀÌÌÍÎÅ ÎÁÅÑÏÅ×ÅÍÈÅ ÏÐÅÄÎÑÒÀÂËßÅÒÑß «ÊÀÊ ÅÑÒÜ», ÁÅÇ ÊÀÊÈÕ-ËÈÁÎ ÃÀÐÀÍÒÈÉ, ßÂÍÎ ÂÛÐÀÆÅÍÍÛÕ ÈËÈ ÏÎÄÐÀÇÓÌÅÂÀÅÌÛÕ, ÂÊËÞ×Àß ÃÀÐÀÍÒÈÈ ÒÎÂÀÐÍÎÉ ÏÐÈÃÎÄÍÎÑÒÈ, ÑÎÎÒÂÅÒÑÒÂÈß ÏÎ ÅÃÎ ÊÎÍÊÐÅÒÍÎÌÓ ÍÀÇÍÀ×ÅÍÈÞ È ÎÒÑÓÒÑÒÂÈß ÍÀÐÓØÅÍÈÉ, ÍÎ ÍÅ ÎÃÐÀÍÈ×ÈÂÀßÑÜ ÈÌÈ. ÍÈ Â ÊÀÊÎÌ ÑËÓ×ÀÅ ÀÂÒÎÐÛ ÈËÈ ÏÐÀÂÎÎÁËÀÄÀÒÅËÈ ÍÅ ÍÅÑÓÒ ÎÒÂÅÒÑÒÂÅÍÍÎÑÒÈ ÏÎ ÊÀÊÈÌ-ËÈÁÎ ÈÑÊÀÌ, ÇÀ ÓÙÅÐÁ ÈËÈ ÏÎ ÈÍÛÌ ÒÐÅÁÎÂÀÍÈßÌ,  ÒÎÌ ×ÈÑËÅ, ÏÐÈ ÄÅÉÑÒÂÈÈ ÊÎÍÒÐÀÊÒÀ, ÄÅËÈÊÒÅ ÈËÈ ÈÍÎÉ ÑÈÒÓÀÖÈÈ, ÂÎÇÍÈÊØÈÌ ÈÇ-ÇÀ ÈÑÏÎËÜÇÎÂÀÍÈß ÏÐÎÃÐÀÌÌÍÎÃÎ ÎÁÅÑÏÅ×ÅÍÈß ÈËÈ ÈÍÛÕ ÄÅÉÑÒÂÈÉ Ñ ÏÐÎÃÐÀÌÌÍÛÌ ÎÁÅÑÏÅ×ÅÍÈÅÌ. \ No newline at end of file diff --git a/distr/iss/code2langTr.txt b/distr/iss/code2langTr.txt new file mode 100644 index 0000000..b33c48b --- /dev/null +++ b/distr/iss/code2langTr.txt @@ -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 Идиш + diff --git a/distr/iss/dwinshs.iss b/distr/iss/dwinshs.iss new file mode 100644 index 0000000..5bb1e34 --- /dev/null +++ b/distr/iss/dwinshs.iss @@ -0,0 +1,1266 @@ +// ===================================================================================================================== +// DwinsHs +// +// Author: HAN-SOFT +// E-Mail: support@han-soft.com +// WebURL: http://www.han-soft.com +// Copyright (C) 2001, 2015 Han-soft Corporation. All rights reserved. +// ===================================================================================================================== +// $Rev: 113 $ $Id: dwinshs.iss 113 2015-07-23 07:30:14Z hanjy $ +// ===================================================================================================================== + +#define Use_DwinsHs + +[Code] + +type + TCancelDownload = (cdNone, cdBack, cdExit); + TProxyMode = (pmDefault, pmDirect, pmProxy); + TProxyProtocol = (ppHttp, ppSocks); + TDwinsHs_Proxy = record + Mode: TProxyMode; + Protocol: TProxyProtocol; + Host: AnsiString; + Port: Integer; + Username: AnsiString; + Password: AnsiString; + end; + +var + DwinsHs_CancelDownload: TCancelDownload; + DwinsHs_Proxy: TDwinsHs_Proxy; + +const + PM_NOREMOVE = $0000; + PM_REMOVE = $0001; + PM_NOYIELD = $0002; + WM_QUIT = $0012; + +type + TMsg = record + hWnd: HWnd; + Msg: LongInt; + wParam: LongInt; + lParam: LongInt; + Time: LongInt; + Pt: TPoint; + end; + +function PeekMessage(var Msg: TMsg; Wnd: HWnd; MsgFilterMin, MsgFilterMax, wRemoveMsg: LongInt): BOOL; +external 'PeekMessageA@user32.dll stdcall delayload setuponly'; + +function TranslateMessage(var Msg: TMsg): BOOL; +external 'TranslateMessage@user32.dll stdcall delayload setuponly'; + +function DispatchMessage(var Msg: TMsg): LongInt; +external 'DispatchMessageA@user32.dll stdcall delayload setuponly'; + +procedure DwinsHs_ProcessMessages(); +var + Msg: TMsg; +begin + while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do + if Msg.Msg <> WM_QUIT then + begin + TranslateMessage(Msg); + DispatchMessage(Msg); + end + else + begin + DwinsHs_CancelDownload := cdExit; + end; +end; + +// ===================================================================================================================== + +type + Pointer = Cardinal; + HINTERNET = Pointer; + PLPSTR = Pointer; + LPDWORD = DWORD_PTR; + +function InternetOpen(lpszAgent: PAnsiChar; dwAccessType: DWORD; lpszProxy, lpszProxyBypass: PAnsiChar; + dwFlags: DWORD): HINTERNET; +external 'InternetOpenA@wininet.dll stdcall delayload setuponly'; + +function InternetSetOption(hInet: HINTERNET; dwOption: DWORD; lpBuffer: PAnsiChar; dwBufferLength: DWORD): BOOL; +external 'InternetSetOptionA@wininet.dll stdcall delayload setuponly'; + +function InternetConnect(hInet: HINTERNET; lpszServerName: PAnsiChar; nServerPort: Word; lpszUsername: PAnsiChar; + lpszPassword: PAnsiChar; dwService: DWORD; dwFlags: DWORD; dwContext: DWORD_PTR): HINTERNET; +external 'InternetConnectA@wininet.dll stdcall delayload setuponly'; + +function HttpOpenRequest(hConnect: HINTERNET; lpszVerb: PAnsiChar; lpszObjectName: PAnsiChar; lpszVersion: PAnsiChar; + lpszReferrer: PAnsiChar; lplpszAcceptTypes: PLPSTR; dwFlags: DWORD; dwContext: DWORD_PTR): HINTERNET; +external 'HttpOpenRequestA@wininet.dll stdcall delayload setuponly'; + +function HttpSendRequest(hRequest: HINTERNET; lpszHeaders: PAnsiChar; dwHeadersLength: DWORD; lpOptional: PAnsiChar; + dwOptionalLength: DWORD): BOOL; +external 'HttpSendRequestA@wininet.dll stdcall delayload setuponly'; + +function HttpQueryInfo(hRequest: HINTERNET; dwInfoLevel: DWORD; lpvBuffer: PAnsiChar; var lpdwBufferLength: DWORD; + var lpdwReserved: DWORD): BOOL; +external 'HttpQueryInfoA@wininet.dll stdcall delayload setuponly'; + +function FtpOpenFile(hConnect: HINTERNET; lpszFileName: PAnsiChar; dwAccess: DWORD; dwFlags: DWORD; + dwContext: DWORD): HINTERNET; +external 'FtpOpenFileA@wininet.dll stdcall delayload setuponly'; + +function FtpGetFileSize(hFile: HINTERNET; lpdwFileSizeHigh: DWORD): DWORD; +external 'FtpGetFileSize@wininet.dll stdcall delayload setuponly'; + +function InternetReadFile(hFile: HINTERNET; lpBuffer: PAnsiChar; dwNumberOfBytesToRead: DWORD; + var lpdwNumberOfBytesRead: DWORD): BOOL; +external 'InternetReadFile@wininet.dll stdcall delayload setuponly'; + +function InternetCloseHandle(hInet: HINTERNET): BOOL; +external 'InternetCloseHandle@wininet.dll stdcall delayload setuponly'; + +function InternetGetConnectedState(lpdwFlags: PAnsiChar; dwReserved: DWORD): BOOL; +external 'InternetGetConnectedState@wininet.dll stdcall delayload setuponly'; + +const + INTERNET_CONNECTION_OFFLINE = 32; + INTERNET_OPEN_TYPE_PRECONFIG = 0; + INTERNET_OPEN_TYPE_DIRECT = 1; + INTERNET_OPEN_TYPE_PROXY = 3; + INTERNET_OPTION_PROXY_USERNAME = 43; + INTERNET_OPTION_PROXY_PASSWORD = 44; + INTERNET_SERVICE_FTP = 1; + INTERNET_SERVICE_HTTP = 3; + INTERNET_FLAG_RELOAD = $80000000; + INTERNET_FLAG_SECURE = $00800000; + INTERNET_FLAG_IGNORE_CERT_CN_INVALID = $00001000; + INTERNET_FLAG_IGNORE_CERT_DATE_INVALID = $00002000; + INTERNET_FLAG_EXISTING_CONNECT = $20000000; + INTERNET_FLAG_PASSIVE = $08000000; + GENERIC_READ = $80000000; + FTP_TRANSFER_TYPE_BINARY = $00000002; + HTTP_HEADER = 'Content-Type: application/x-www-form-urlencoded'; + HTTP_QUERY_CONTENT_LENGTH = 5; + HTTP_QUERY_STATUS_CODE = 19; + + #ifndef DwinsHs_Data_Buffer_Length + #define DwinsHs_Data_Buffer_Length 4096 + #endif + READ_BUFFER_LENGTH = {#DwinsHs_Data_Buffer_Length}; + + CONNECT_OK = 0; + CONNECT_ERROR_NETWORK = 1; + CONNECT_ERROR_OFFLINE = 2; + CONNECT_ERROR_INITIALIZE = 3; + CONNECT_ERROR_OPENSESSION = 4; + CONNECT_ERROR_CREATEREQUEST = 5; + CONNECT_ERROR_SENDREQUEST = 6; + + READ_OK = 0; + READ_ERROR_DELETEFILE = 7; + READ_ERROR_SAVEFILE = 8; + READ_ERROR_CANCELED = 9; + READ_ERROR_READDATA = 10; + +type + TReadScheme = (rpHttp, rpHttps, rpFtp); + TReadMethod = (rmGet, rmPost, rmActive, rmPassive); + TOnRead = function(URL, Agent: AnsiString; Method: TReadMethod; Index, TotalSize, ReadSize, CurrentSize: LongInt; + var ReadStr: AnsiString): Boolean; + +procedure ParseURL(URL: AnsiString; var Scheme: TReadScheme; var Host, Path, Data, Username, Password: AnsiString; + var Port: Integer); +var + i: Integer; +begin + URL := Trim(URL); + Scheme := rpHttp; + Port := 80; + i := Pos('://', URL); + if i > 0 then + begin + case LowerCase(Trim(Copy(URL, 1, i - 1))) of + 'http': + begin + Port := 80; + Scheme := rpHttp; + end; + 'https': + begin + Port := 443; + Scheme := rpHttps; + end; + 'ftp': + begin + Port := 21; + Scheme := rpFtp; + end; + end; + URL := Trim(Copy(URL, i + 3, 65535)); + end; + + i := Pos('/', URL); + if i > 0 then + begin + Host := Trim(Copy(URL, 1, i - 1)); + Path := Trim(Copy(URL, i, 65535)); + end + else + begin + Host := URL; + Path := ''; + end; + + i := Pos('@', Host); + if i > 0 then + begin + Username := Trim(Copy(Host, 1, i - 1)); + Host := Trim(Copy(Host, i + 1, 65535)); + end + else + begin + Username := ''; + end; + + i := Pos(':', Username); + if i > 0 then + begin + Password := Trim(Copy(Username, i + 1, 65535)); + Username := Trim(Copy(Username, 1, i - 1)); + end + else + begin + Password := ''; + end; + + i := Pos(':', Host); + if i > 0 then + begin + Port := StrToIntDef(Trim(Copy(Host, i + 1, 65535)), Port); + Host := Trim(Copy(Host, 1, i -1)); + end; + + i := Pos('?', Path); + if i > 0 then + begin + Data := Trim(Copy(Path, i + 1, 65536)); + Path := Trim(Copy(Path, 1, i - 1)); + end + else + Data := ''; + Host := LowerCase(Host); +end; + +procedure DwinsHs_SetProxy(Mode: TProxyMode; Protocol: TProxyProtocol; Host: AnsiString; Port: Integer; + Username, Password: AnsiString); +begin + DwinsHs_Proxy.Mode := Mode; + DwinsHs_Proxy.Protocol := Protocol; + DwinsHs_Proxy.Host := Host; + DwinsHs_Proxy.Port := Port; + DwinsHs_Proxy.Username := Username; + DwinsHs_Proxy.Password := Password; +end; + +function CreateConnect(URL, Agent: AnsiString; Method: TReadMethod; var hSession, hConnect, hRequest: HINTERNET; + var Size: LongInt): Integer; +var + Scheme: TReadScheme; + ProxyProtocolName, Host, Path, Data, Username, Password: AnsiString; + Port, i: Integer; + Buffer: AnsiString; + Flag, Bytes: DWord; + Sended: Boolean; +begin + ParseUrl(URL, Scheme, Host, Path, Data, Username, Password, Port); + Size := -1; + + Result := CONNECT_ERROR_NETWORK; + Buffer := '0000'; + if not InternetGetConnectedState(PAnsiChar(Buffer), 0) then Exit; + Result := CONNECT_ERROR_OFFLINE; + Flag := Ord(Buffer[1]) + Ord(Buffer[2]) * 256 + Ord(Buffer[3]) * 65536 + Ord(Buffer[4]) * 16777216; + if (Flag and INTERNET_CONNECTION_OFFLINE) <> 0 then Exit; + + Result := CONNECT_ERROR_INITIALIZE; + case DwinsHs_Proxy.Mode of + pmDefault: + hSession := InternetOpen(Agent, INTERNET_OPEN_TYPE_PRECONFIG, '', '', 0); + pmDirect: + hSession := InternetOpen(Agent, INTERNET_OPEN_TYPE_DIRECT, '', '', 0); + pmProxy: + begin + case DwinsHs_Proxy.Protocol of + ppHttp: ProxyProtocolName := 'HTTP'; + ppSocks: ProxyProtocolName := 'SOCKS'; + end; + hSession := InternetOpen(Agent, INTERNET_OPEN_TYPE_PROXY, PAnsiChar(ProxyProtocolName + '=' + ProxyProtocolName + + '://' + DwinsHs_Proxy.Host + ':' + IntToStr(DwinsHs_Proxy.Port)), '', 0); + if DwinsHs_Proxy.Username <> '' then + InternetSetOption(hSession, INTERNET_OPTION_PROXY_USERNAME, PAnsiChar(DwinsHs_Proxy.Username), + Length(DwinsHs_Proxy.Username)); + if DwinsHs_Proxy.Password <> '' then + InternetSetOption(hSession, INTERNET_OPTION_PROXY_PASSWORD, PAnsiChar(DwinsHs_Proxy.Password), + Length(DwinsHs_Proxy.Password)); + end; + end; + if hSession = 0 then Exit; + + Result := CONNECT_ERROR_OPENSESSION; + case Scheme of + rpHttp, rpHttps: + hConnect := InternetConnect(hSession, PAnsiChar(Host), Port, PAnsiChar(Username), PAnsiChar(Password), + INTERNET_SERVICE_HTTP, 0, 0); + rpFtp: + begin + if Method = rmPassive then Flag := INTERNET_FLAG_PASSIVE else Flag := 0; + hConnect := InternetConnect(hSession, PAnsiChar(Host), Port, PAnsiChar(Username), PAnsiChar(Password), + INTERNET_SERVICE_FTP, INTERNET_FLAG_EXISTING_CONNECT or Flag, 0); + end; + end; + if hConnect = 0 then + begin + InternetCloseHandle(hSession); + Exit; + end; + + Result := CONNECT_ERROR_CREATEREQUEST; + case Scheme of + rpHttp, rpHttps: + begin + Flag := INTERNET_FLAG_RELOAD; + if Scheme = rpHttps then + Flag := Flag or INTERNET_FLAG_SECURE or INTERNET_FLAG_IGNORE_CERT_CN_INVALID or + INTERNET_FLAG_IGNORE_CERT_DATE_INVALID; + case Method of + rmGet: + begin + if Data <> '' then Path := Path + '?' + Data; + hRequest := HttpOpenRequest(hConnect, 'GET', PAnsiChar(Path), 'HTTP/1.0', '', 0, Flag, 0); + end; + rmPost: + hRequest := HttpOpenRequest(hConnect, 'POST', PAnsiChar(Path), 'HTTP/1.0', '', 0, Flag, 0); + end; + if hRequest = 0 then + begin + InternetCloseHandle(hConnect); + InternetCloseHandle(hSession); + Exit; + end; + Result := CONNECT_ERROR_SENDREQUEST; + case Method of + rmGet: Sended := HttpSendRequest(hRequest, HTTP_HEADER, Length(HTTP_HEADER), '', 0); + rmPost: Sended := HttpSendRequest(hRequest, HTTP_HEADER, Length(HTTP_HEADER), PAnsiChar(Data), Length(Data)); + end; + if Sended then + begin + SetLength(Buffer, READ_BUFFER_LENGTH + 1); + try + Bytes := READ_BUFFER_LENGTH; + Flag := 0; + if HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE, PAnsiChar(Buffer), Bytes, Flag) then + begin + Flag := 0; + for i := 1 to Bytes do Flag := Flag * 10 + Ord(Buffer[i]) - 48; + end; + if Flag >= 400 then + begin + Result := Flag; + end + else + begin + Bytes := READ_BUFFER_LENGTH; + Flag := 0; + if HttpQueryInfo(hRequest, HTTP_QUERY_CONTENT_LENGTH, PAnsiChar(Buffer), Bytes, Flag) then + begin + Size := 0; + for i := 1 to Bytes do Size := Size * 10 + Ord(Buffer[i]) - 48; + end; + Result := CONNECT_OK; + end; + finally + SetLength(Buffer, 0); + end; + end; + if Result <> CONNECT_OK then + begin + InternetCloseHandle(hConnect); + InternetCloseHandle(hSession); + InternetCloseHandle(hRequest); + Exit; + end; + end; + rpFtp: + begin + hRequest := + FtpOpenFile(hConnect, PAnsiChar(Path), GENERIC_READ, FTP_TRANSFER_TYPE_BINARY or INTERNET_FLAG_RELOAD, 0); + if hRequest = 0 then + begin + InternetCloseHandle(hConnect); + InternetCloseHandle(hSession); + Exit; + end; + Size := FtpGetFileSize(hRequest, 0); + Result := CONNECT_OK; + end; + end; +end; + +function DwinsHs_GetRemoteSize(URL, Agent: AnsiString; Method: TReadMethod): LongInt; +var + hSession, hConnect, hRequest: HINTERNET; + Status: Integer; +begin + Status := CreateConnect(URL, Agent, Method, hSession, hConnect, hRequest, Result); + if Status <> CONNECT_OK then + begin + Result := - Status; + Exit; + end; + InternetCloseHandle(hConnect); + InternetCloseHandle(hSession); + InternetCloseHandle(hRequest); +end; + +function DwinsHs_ReadRemoteURL(URL, Agent: AnsiString; Method: TReadMethod; var Response: AnsiString; var Size: LongInt; + SaveFilename: string; OnRead: TOnRead): Integer; +var + hSession, hConnect, hRequest: HINTERNET; + Buffer, ReadStr: AnsiString; + ToContinue: Boolean; + Bytes: DWORD; + Readed, Index: LongInt; +begin + Result := CreateConnect(URL, Agent, Method, hSession, hConnect, hRequest, Size); + if Result <> CONNECT_OK then Exit; + SetLength(Buffer, READ_BUFFER_LENGTH + 1); + try + Index := 0; + Readed := 0; + ToContinue := True; + while ToContinue do + begin + if InternetReadFile(hRequest, PAnsiChar(Buffer), READ_BUFFER_LENGTH, Bytes) then + begin + if Bytes > 0 then + begin + Readed := Readed + Bytes; + ReadStr := Copy(Buffer, 1, Bytes); + if SaveFilename <> '' then + begin + if (Index = 0) and FileExists(SaveFilename) then + begin + Result := READ_ERROR_DELETEFILE; + if not DeleteFile(SaveFilename) then Break; + end; + Result := READ_ERROR_SAVEFILE; + if not SaveStringToFile(SaveFilename, ReadStr, Index <> 0) then Break; + end; + if OnRead <> nil then ToContinue := OnRead(URL, Agent, Method, Index, Size, Readed, Bytes, ReadStr); + Response := Response + ReadStr; + Result := READ_OK; + end + else + begin + ReadStr := ''; + if OnRead <> nil then ToContinue := OnRead(URL, Agent, Method, Index, Size, Readed, 0, ReadStr); + Response := Response + ReadStr; + Break; + end; + if (not ToContinue) or (DwinsHs_CancelDownload <> cdNone) then + begin + ToContinue := False; + Result := READ_ERROR_CANCELED; + end; + DwinsHs_ProcessMessages(); + end + else + begin + ReadStr := ''; + Response := ''; + if SaveFilename <> '' then DeleteFile(SaveFilename); + if OnRead <> nil then ToContinue := OnRead(URL, Agent, Method, -1, Size, Readed, 0, ReadStr); + Result := READ_ERROR_READDATA; + Break; + end; + Index := Index + 1; + end; + finally + SetLength(Buffer, 0); + InternetCloseHandle(hConnect); + InternetCloseHandle(hSession); + InternetCloseHandle(hRequest); + end; +end; + +// ===================================================================================================================== + +#ifdef DwinsHs_Use_Predefined_Downloading_WizardPage + +[CustomMessages] + +#ifndef DwinsHs_Disable_Default_CustomMessages + +DwinsHs_PageCaption =Downloading additional files +DwinsHs_PageDescription =Please wait while setup downloads additional files... +DwinsHs_TotalProgress =Total progress: +DwinsHs_CurrentFile =Current file: +DwinsHs_File =File: +DwinsHs_Speed =Speed: +DwinsHs_Status =Status: +DwinsHs_ElapsedTime =Elapsed time: +DwinsHs_RemainingTime =Remaining time: +DwinsHs_Status_ButtonRetry =&Retry +DwinsHs_Status_ButtonNext =&Next > + +DwinsHs_SizeInBytes =%d Bytes +DwinsHs_SizeInKB =%.2f KB +DwinsHs_SizeInMB =%.2f MB +DwinsHs_ProgressValue = %s of %s (%d%%%) +DwinsHs_SpeedInBytes =%d Bytes/s +DwinsHs_SpeedInKB =%.2f KB/s +DwinsHs_SpeedInMB =%.2f MB/s +DwinsHs_TimeInHour =%d hour(s), %d minute(s), %d second(s) +DwinsHs_TimeInMinute =%d minute(s), %d second(s) +DwinsHs_TimeInSecond =%d second(s) + +DwinsHs_Status_GetFileInformation =Fetch file size +DwinsHs_Status_StartingDownload =Starting to download +DwinsHs_Status_Downloading =Downloading +DwinsHs_Status_DownlaodComplete =Download completes + +DwinsHs_Error_Network =No active Internet connection +DwinsHs_Error_Offline =The computer is in offline mode +DwinsHs_Error_Initialize =Failed to initialize the setup +DwinsHs_Error_OpenSession =Failed to open the FTP or HTTP session +DwinsHs_Error_CreateRequest =Failed to create an HTTP request handle +DwinsHs_Error_SendRequest =Failed to send request to the HTTP server +DwinsHs_Error_DeleteFile =The old file cannot be deleted +DwinsHs_Error_SaveFile =Failed to save data +DwinsHs_Error_Canceled =Download canceled +DwinsHs_Error_ReadData =Failed to read data + +DwinsHs_Status_HTTPError =HTTP error %d: %s +DwinsHs_Status_HTTP400 =Bad request +DwinsHs_Status_HTTP401 =Unauthorized +DwinsHs_Status_HTTP404 =Not found +DwinsHs_Status_HTTP407 =Proxy authentication required +DwinsHs_Status_HTTP500 =Internal error +DwinsHs_Status_HTTP502 =Bad gateway +DwinsHs_Status_HTTP503 =Service unavailable +DwinsHs_Status_HTTPxxx =Other error + +#endif + +[Code] + +function FormatURL(URL: AnsiString): AnsiString; +var + Scheme: TReadScheme; + SchemeTxt, Host, Path, Username, Password, Data: AnsiString; + Port: Integer; +begin + ParseURL(URL, Scheme, Host, Path, Data, Username, Password, Port); + case Scheme of + rpHttp: SchemeTxt := 'http'; + rpHttps: SchemeTxt := 'https'; + rpFtp: SchemeTxt := 'ftp'; + end; + Result := SchemeTxt + '://'; + if (Username <> '') or (Password <> '') then + begin + Host := '@' + Host; + if Username <> '' then Result := Result + Username; + if Password <> '' then Result := Result + ':' + Password; + end; + Result := Result + Host + ':' + IntToStr(Port) + Path; + if (Data <> '') and ((Scheme = rpHttp) or (Scheme = rpHttps)) then Result := Result + '?' + Data; +end; + +function FormatSize(Size: LongInt): string; +begin + if Size < 1024 then + Result := Format(ExpandConstant('{cm:DwinsHs_SizeInBytes}'), [Size]) + else if Size < 1048576 then + Result := Format(ExpandConstant('{cm:DwinsHs_SizeInKB}'), [Double(Size)/1024]) + else + Result := Format(ExpandConstant('{cm:DwinsHs_SizeInMB}'), [Double(Size)/1048576]) +end; + +function FormatSpeed(Speed: LongInt): string; +begin + if Speed < 1024 then + Result := Format(ExpandConstant('{cm:DwinsHs_SpeedInBytes}'), [Speed]) + else if Speed < 1048576 then + Result := Format(ExpandConstant('{cm:DwinsHs_SpeedInKB}'), [Double(Speed)/1024]) + else + Result := Format(ExpandConstant('{cm:DwinsHs_SpeedInMB}'), [Double(Speed)/1048576]) +end; + +function FormatTime(Seconds: LongInt): string; +begin + if Seconds >= 3600 then + Result := Format(ExpandConstant('{cm:DwinsHs_TimeInHour}'), [Seconds div 3600, (Seconds mod 3600) div 60, + Seconds mod 60]) + else if Seconds >= 60 then + Result := Format(ExpandConstant('{cm:DwinsHs_TimeInMinute}'), [Seconds div 60, Seconds mod 60]) + else + Result := Format(ExpandConstant('{cm:DwinsHs_TimeInSecond}'), [Seconds]); +end; + +function DecodeDateTimeString(DateTime: string): LongInt; +var + Year, Month, Day, Hour, Minute, Second: Integer; + a, y, m: Integer; +begin + Year := StrToIntDef(Copy(DateTime, 1, 4), 0); + Month := StrToIntDef(Copy(DateTime, 6, 2), 0); + Day := StrToIntDef(Copy(DateTime, 9, 2), 0); + Hour := StrToIntDef(Copy(DateTime, 12, 2), 0); + Minute := StrToIntDef(Copy(DateTime, 15, 2), 0); + Second := StrToIntDef(Copy(DateTime, 18, 2), 0); + a := (14 - Month) div 12; + y := Year + 4800 - a; + m := Month + 12 * a - 3; + Result := (Day + (153 * m + 2) div 5 + 365 * y + y div 4 - y div 100 + y div 400 - 32045 - 2400000) * 86400 - 43200 + + Hour * 3600 + Minute * 60 + Second; +end; + +#ifndef Hs_CreateLabel +#define Hs_CreateLabel +function CreateLabel(OwnerControl: TComponent; Caption: string; Left, Top, Width: Integer; Wrap, + RightAlignment: Boolean): TLabel; +begin + Result := TLabel.Create(OwnerControl); + if OwnerControl = WizardForm then + Result.Parent := WizardForm + else + Result.Parent := TWizardPage(OwnerControl).Surface; + Result.Caption := Caption; + Result.Left := Left; + Result.Top := Top; + if Wrap or RightAlignment then Result.Width := Width; + if RightAlignment then Result.Alignment := taRightJustify; + Result.WordWrap := Wrap; + Result.AutoSize := True; +end; +#endif + +function CreateProgressBar(OwnerControl: TComponent; Left, Top, Width, Height, MinValue, MaxValue, CurValue: Integer): + TNewProgressBar; +begin + Result := TNewProgressBar.Create(OwnerControl); + if OwnerControl = WizardForm then + Result.Parent := WizardForm + else + Result.Parent := TWizardPage(OwnerControl).Surface; + Result.Left := Left; + Result.Top := Top; + Result.Width := Width; + Result.Height := Height; + Result.Min := MinValue; + Result.Max := MaxValue; + Result.Position := CurValue; +end; + +#ifndef Hs_ClickButton +#define Hs_ClickButton + +const + WM_LBUTTONDOWN = 513; + WM_LBUTTONUP = 514; + +procedure ClickNext(); +begin + PostMessage(WizardForm.NextButton.Handle, WM_LBUTTONDOWN,0,0); + PostMessage(WizardForm.NextButton.Handle, WM_LBUTTONUP,0,0); +end; + +procedure ClickCancel(); +begin + PostMessage(WizardForm.CancelButton.Handle, WM_LBUTTONDOWN,0,0); + PostMessage(WizardForm.CancelButton.Handle, WM_LBUTTONUP,0,0); +end; + +#endif + +Const + FILESIZE_QUERY_SERVER = 0; + FILESIZE_UNKNOWN = -1; + FILESIZE_KEEP_FORMER = -2; + +type + TDownloadWizardDefine = record + DownloadingPage: TWizardPage; + TotalProgress, CurrentProgress: TLabel; + DownloadFile, DownloadSpeed, DownloadStatus, DownloadElapsedTime, DownloadRemainingTime: TLabel; + TotalProgressBar, CurrentProgressBar: TNewProgressBar; + PreviousPageId: Integer; + BeginTime, AllFilesSize, DownloadedSize: LongInt; + DownloadError: Boolean; + end; + + TDownloadItem = record + Filename: string; + URL: AnsiString; + Agent: AnsiString; + Method: TReadMethod; + FileSize: LongInt; + RealSize: LongInt; + Required: Boolean; + Downloaded: Boolean; + end; + + TMirrorItem = record + Filename: string; + URL: AnsiString; + Agent: AnsiString; + Method: TReadMethod; + Required: boolean; + end; + +var + DwinsHs_DownloadWizardDefine: TDownloadWizardDefine; + DwinsHs_DownloadsList: array of TDownloadItem; + DwinsHs_MirrorsList: array of TMirrorItem; + +function UpdateDownloadingPage(URL, Agent: AnsiString; Method: TReadMethod; Index, TotalSize, ReadSize, + CurrentSize: LongInt; var ReadStr: AnsiString): Boolean; +var + ElapsedTime: LongInt; +begin + if Index >= 0 then + begin + DwinsHs_DownloadWizardDefine.DownloadStatus.Caption := ExpandConstant('{cm:DwinsHs_Status_Downloading}'); + DwinsHs_DownloadWizardDefine.DownloadStatus.Repaint; + end; + DwinsHs_DownloadWizardDefine.CurrentProgressBar.Position := ReadSize; + DwinsHs_DownloadWizardDefine.CurrentProgressBar.Repaint; + DwinsHs_DownloadWizardDefine.DownloadedSize := DwinsHs_DownloadWizardDefine.DownloadedSize + CurrentSize; + DwinsHs_DownloadWizardDefine.TotalProgressBar.Position := DwinsHs_DownloadWizardDefine.DownloadedSize; + DwinsHs_DownloadWizardDefine.TotalProgressBar.Repaint; + if TotalSize > 0 then + begin + DwinsHs_DownloadWizardDefine.CurrentProgress.Caption := + Format(ExpandConstant('{cm:DwinsHs_ProgressValue}'), [FormatSize(ReadSize), FormatSize(TotalSize), + ReadSize * 100 / TotalSize]); + DwinsHs_DownloadWizardDefine.CurrentProgress.Repaint; + end; + if DwinsHs_DownloadWizardDefine.AllFilesSize > 0 then + begin + DwinsHs_DownloadWizardDefine.TotalProgress.Caption := + Format(ExpandConstant('{cm:DwinsHs_ProgressValue}'), [FormatSize(DwinsHs_DownloadWizardDefine.DownloadedSize), + FormatSize(DwinsHs_DownloadWizardDefine.AllFilesSize), DwinsHs_DownloadWizardDefine.DownloadedSize * 100 / + DwinsHs_DownloadWizardDefine.AllFilesSize]); + DwinsHs_DownloadWizardDefine.TotalProgress.Repaint; + end; + ElapsedTime := + DecodeDateTimeString(GetDateTimeString('yyyy-mm-dd hh:nn:ss', '-', ':')) - DwinsHs_DownloadWizardDefine.BeginTime; + DwinsHs_DownloadWizardDefine.DownloadElapsedTime.Caption := FormatTime(ElapsedTime); + DwinsHs_DownloadWizardDefine.DownloadElapsedTime.Repaint; + if ElapsedTime > 0 then + DwinsHs_DownloadWizardDefine.DownloadSpeed.Caption := + FormatSpeed(DwinsHs_DownloadWizardDefine.DownloadedSize div ElapsedTime) + else + DwinsHs_DownloadWizardDefine.DownloadSpeed.Caption := ''; + DwinsHs_DownloadWizardDefine.DownloadSpeed.Repaint; + if DwinsHs_DownloadWizardDefine.DownloadedSize > 0 then + DwinsHs_DownloadWizardDefine.DownloadRemainingTime.Caption := + FormatTime((DwinsHs_DownloadWizardDefine.AllFilesSize - DwinsHs_DownloadWizardDefine.DownloadedSize) * + ElapsedTime / DwinsHs_DownloadWizardDefine.DownloadedSize) + else + DwinsHs_DownloadWizardDefine.DownloadRemainingTime.Caption := ''; + DwinsHs_DownloadWizardDefine.DownloadRemainingTime.Repaint; + Result := DwinsHs_CancelDownload = cdNone; + ReadStr := ''; +end; + +function GetDownloadStateText(State: Integer): string; +var + Text: string; +begin + if State >= 400 then + begin + Text := ExpandConstant('{cm:DwinsHs_Status_HTTPxxx}'); + case State of + 400: Text := ExpandConstant('{cm:DwinsHs_Status_HTTP400}'); + 401: Text := ExpandConstant('{cm:DwinsHs_Status_HTTP401}'); + 404: Text := ExpandConstant('{cm:DwinsHs_Status_HTTP404}'); + 407: Text := ExpandConstant('{cm:DwinsHs_Status_HTTP407}'); + 500: Text := ExpandConstant('{cm:DwinsHs_Status_HTTP500}'); + 502: Text := ExpandConstant('{cm:DwinsHs_Status_HTTP502}'); + 503: Text := ExpandConstant('{cm:DwinsHs_Status_HTTP503}'); + end; + Result := Format(ExpandConstant('{cm:DwinsHs_Status_HTTPError}'), [State, Text]); + end + else + case State of + READ_OK: Result := ExpandConstant('{cm:DwinsHs_Status_DownlaodComplete}'); + CONNECT_ERROR_NETWORK: Result := ExpandConstant('{cm:DwinsHs_Error_Network}'); + CONNECT_ERROR_OFFLINE: Result := ExpandConstant('{cm:DwinsHs_Error_Offline}'); + CONNECT_ERROR_INITIALIZE: Result := ExpandConstant('{cm:DwinsHs_Error_Initialize}'); + CONNECT_ERROR_OPENSESSION: Result := ExpandConstant('{cm:DwinsHs_Error_OpenSession}'); + CONNECT_ERROR_CREATEREQUEST: Result := ExpandConstant('{cm:DwinsHs_Error_CreateRequest}'); + CONNECT_ERROR_SENDREQUEST: Result := ExpandConstant('{cm:DwinsHs_Error_SendRequest}'); + READ_ERROR_DELETEFILE: Result := ExpandConstant('{cm:DwinsHs_Error_DeleteFile}'); + READ_ERROR_SAVEFILE: Result := ExpandConstant('{cm:DwinsHs_Error_SaveFile}'); + READ_ERROR_CANCELED: Result := ExpandConstant('{cm:DwinsHs_Error_Canceled}'); + READ_ERROR_READDATA: Result := ExpandConstant('{cm:DwinsHs_Error_ReadData}'); + end; +end; + +// ===================================================================================================================== + +procedure DwinsHs_AppendRemoteFile(Filename: string; URL, Agent: AnsiString; Method: TReadMethod; FileSize: LongInt); +var + i, c: Integer; + Finded: Boolean; +begin + URL := FormatURL(URL); + Filename := Trim(Filename); + Agent := Trim(Agent); + Finded := False; + c := GetArrayLength(DwinsHs_DownloadsList); + for i := 0 to c - 1 do + begin + if CompareText(DwinsHs_DownloadsList[i].Filename, Filename) = 0 then + begin + Finded := True; + DwinsHs_DownloadsList[i].URL := URL; + DwinsHs_DownloadsList[i].Agent := Agent; + DwinsHs_DownloadsList[i].Method := Method; + DwinsHs_DownloadsList[i].Required := True; + DwinsHs_DownloadsList[i].FileSize := FileSize; + Break; + end; + end; + if not Finded then + begin + SetArrayLength(DwinsHs_DownloadsList, c + 1); + DwinsHs_DownloadsList[c].Filename := Filename; + DwinsHs_DownloadsList[c].URL := URL; + DwinsHs_DownloadsList[c].Agent := Agent; + DwinsHs_DownloadsList[c].Method := Method; + DwinsHs_DownloadsList[c].FileSize := FileSize; + DwinsHs_DownloadsList[c].RealSize := FILESIZE_UNKNOWN; + DwinsHs_DownloadsList[c].Downloaded := False; + DwinsHs_DownloadsList[c].Required := True; + end; +end; + +procedure DwinsHs_AppendMirrorFile(Filename: string; URL, Agent: AnsiString; Method: TReadMethod); +var + i, c: Integer; + Finded: Boolean; +begin + URL := FormatURL(URL); + Filename := Trim(Filename); + Agent := Trim(Agent); + Finded := False; + c := GetArrayLength(DwinsHs_MirrorsList); + for i := 0 to c - 1 do + begin + if (CompareText(DwinsHs_MirrorsList[i].Filename, Filename) = 0) and (DwinsHs_MirrorsList[i].URL = URL) and + (DwinsHs_MirrorsList[i].Agent = Agent) and (DwinsHs_MirrorsList[i].Method = Method) then + begin + Finded := True; + DwinsHs_MirrorsList[i].Required := True; + Break; + end; + end; + if not Finded then + begin + SetArrayLength(DwinsHs_MirrorsList, c + 1); + DwinsHs_MirrorsList[c].Filename := Filename; + DwinsHs_MirrorsList[c].URL := URL; + DwinsHs_MirrorsList[c].Agent := Agent; + DwinsHs_MirrorsList[c].Method := Method; + DwinsHs_MirrorsList[c].Required := True; + end; +end; + +function FindMirror(Filename: string; var URL, Agent: AnsiString; var Method: TReadMethod; + var MirrorID: Integer): Boolean; +var + i, c: Integer; +begin + Result := False; + c := GetArrayLength(DwinsHs_MirrorsList); + for i := MirrorID + 1 to c - 1 do + begin + if (CompareText(DwinsHs_MirrorsList[i].Filename, Filename) = 0) and DwinsHs_MirrorsList[i].Required then + begin + URL := DwinsHs_MirrorsList[i].URL; + Agent := DwinsHs_MirrorsList[i].Agent; + Method := DwinsHs_MirrorsList[i].Method; + MirrorID := i; + Result := True; + Break; + end; + end; +end; + +#ifdef DwinsHs_Use_RemoveRemoteFile +function DwinsHs_RemoveRemoteFile(Filename: string; Delete: Boolean): Boolean; +var + i: Integer; +begin + Filename := Trim(Filename); + Result := False; + for i := 0 to GetArrayLength(DwinsHs_DownloadsList) - 1 do + begin + if (CompareText(DwinsHs_DownloadsList[i].Filename, Filename) = 0) and DwinsHs_DownloadsList[i].Required then + begin + Result := True; + DwinsHs_DownloadsList[i].Required := False; + if Delete then + begin + DwinsHs_DownloadsList[i].RealSize := FILESIZE_UNKNOWN; + DwinsHs_DownloadsList[i].Downloaded := False; + if FileExists(Filename) then DeleteFile(Filename); + end; + Break; + end; + end; + for i := 0 to GetArrayLength(DwinsHs_MirrorsList) - 1 do + if CompareText(DwinsHs_MirrorsList[i].Filename, Filename) = 0 then DwinsHs_MirrorsList[i].Required := False; +end; +#endif + +#ifdef DwinsHs_Use_ResetRemoteFile +function DwinsHs_ResetRemoteFile(Filename: string; FileSize: Longint): Boolean; +var + i: Integer; +begin + Filename := Trim(Filename); + Result := False; + for i := 0 to GetArrayLength(DwinsHs_DownloadsList) - 1 do + begin + if (CompareText(DwinsHs_DownloadsList[i].Filename, Filename) = 0) and DwinsHs_DownloadsList[i].Required then + begin + Result := True; + if FileSize <> FILESIZE_KEEP_FORMER then DwinsHs_DownloadsList[i].FileSize := FileSize; + DwinsHs_DownloadsList[i].RealSize := FILESIZE_UNKNOWN; + DwinsHs_DownloadsList[i].Downloaded := False; + if FileExists(Filename) then DeleteFile(Filename); + Break; + end; + end; +end; +#endif + +#ifdef DwinsHs_Use_RemoteFilesCount +function DwinsHs_RemoteFilesCount(WaitToDownload: Boolean): Integer; +var + i: Integer; +begin + Result := 0; + for i := 0 to GetArrayLength(DwinsHs_DownloadsList) - 1 do + begin + if DwinsHs_DownloadsList[i].Required then + begin + Result := Result + 1; + if WaitToDownload and DwinsHs_DownloadsList[i].Downloaded then Result := Result - 1; + end; + end; +end; +#endif + +#ifdef DwinsHs_Use_RemoveAllRemoteFiles +procedure DwinsHs_RemoveAllRemoteFiles(Delete: Boolean); +var + i: Integer; +begin + for i := 0 to GetArrayLength(DwinsHs_DownloadsList) - 1 do + begin + DwinsHs_DownloadsList[i].Required := False; + if Delete and DwinsHs_DownloadsList[i].Required then + begin + DwinsHs_DownloadsList[i].RealSize := FILESIZE_UNKNOWN; + DwinsHs_DownloadsList[i].Downloaded := False; + if FileExists(DwinsHs_DownloadsList[i].Filename) then DeleteFile(DwinsHs_DownloadsList[i].Filename); + end; + end; + for i := 0 to GetArrayLength(DwinsHs_MirrorsList) - 1 do DwinsHs_MirrorsList[i].Required := False; +end; +#endif + +#ifdef DwinsHs_Use_ResetAllRemoteFiles +procedure DwinsHs_ResetAllRemoteFiles(); +var + i: Integer; +begin + for i := 0 to GetArrayLength(DwinsHs_DownloadsList) - 1 do + begin + DwinsHs_DownloadsList[i].RealSize := FILESIZE_UNKNOWN; + DwinsHs_DownloadsList[i].Downloaded := False; + if FileExists(DwinsHs_DownloadsList[i].Filename) then DeleteFile(DwinsHs_DownloadsList[i].Filename); + end; +end; +#endif + +#if (Find(FindSection('Files') + 1, 'DwinsHs_Check(', FIND_CONTAINS||FIND_TRIM) > 0) +function DwinsHs_Check(Filename, URL, Agent, Method: string; FileSize: LongInt): Boolean; +var + MethodValue: TReadMethod; +begin + Result := True; + case LowerCase(Trim(Method)) of + 'get': MethodValue := rmGet; + 'post': MethodValue := rmPost; + 'active': MethodValue := rmActive; + 'passive': MethodValue := rmPassive; + end; + DwinsHs_AppendRemoteFile(Filename, URL, Agent, MethodValue, FileSize); +end; +#endif + +procedure DwinsHs_InitializeWizard(AfterId: Integer); +begin + DwinsHs_DownloadWizardDefine.PreviousPageId := AfterId; + DwinsHs_DownloadWizardDefine.DownloadingPage := CreateCustomPage(AfterId, + ExpandConstant('{cm:DwinsHs_PageCaption}'), ExpandConstant('{cm:DwinsHs_PageDescription}')); + DwinsHs_DownloadWizardDefine.TotalProgress := CreateLabel(DwinsHs_DownloadWizardDefine.DownloadingPage, '', + ScaleX(8), ScaleY(16), DwinsHs_DownloadWizardDefine.DownloadingPage.SurfaceWidth - ScaleX(16), False, True); + CreateLabel(DwinsHs_DownloadWizardDefine.DownloadingPage, ExpandConstant('{cm:DwinsHs_TotalProgress}'), + ScaleX(8), ScaleY(16), DwinsHs_DownloadWizardDefine.DownloadingPage.SurfaceWidth - ScaleX(16), False, False); + DwinsHs_DownloadWizardDefine.TotalProgressBar := CreateProgressBar(DwinsHs_DownloadWizardDefine.DownloadingPage, + ScaleX(8), ScaleY(34), DwinsHs_DownloadWizardDefine.DownloadingPage.SurfaceWidth - ScaleX(16), ScaleY(16), 0, 0, + 0); + DwinsHs_DownloadWizardDefine.CurrentProgress := CreateLabel(DwinsHs_DownloadWizardDefine.DownloadingPage, '', + ScaleX(8), ScaleY(60), DwinsHs_DownloadWizardDefine.DownloadingPage.SurfaceWidth - ScaleX(16), False, True); + CreateLabel(DwinsHs_DownloadWizardDefine.DownloadingPage, ExpandConstant('{cm:DwinsHs_CurrentFile}'), ScaleX(8), + ScaleY(60), DwinsHs_DownloadWizardDefine.DownloadingPage.SurfaceWidth - ScaleX(16), False, False); + DwinsHs_DownloadWizardDefine.CurrentProgressBar := CreateProgressBar(DwinsHs_DownloadWizardDefine.DownloadingPage, + ScaleX(8), ScaleY(78), DwinsHs_DownloadWizardDefine.DownloadingPage.SurfaceWidth - ScaleX(16), ScaleY(16), 0, 0, + 0); + DwinsHs_DownloadWizardDefine.DownloadFile := CreateLabel(DwinsHs_DownloadWizardDefine.DownloadingPage, '', + ScaleX(8), ScaleY(114), DwinsHs_DownloadWizardDefine.DownloadingPage.SurfaceWidth - ScaleX(16), False, True); + CreateLabel(DwinsHs_DownloadWizardDefine.DownloadingPage, ExpandConstant('{cm:DwinsHs_File}'), + ScaleX(8), ScaleY(114), DwinsHs_DownloadWizardDefine.DownloadingPage.SurfaceWidth - ScaleX(16), False, False); + DwinsHs_DownloadWizardDefine.DownloadSpeed := CreateLabel(DwinsHs_DownloadWizardDefine.DownloadingPage, '', + ScaleX(8), ScaleY(134), DwinsHs_DownloadWizardDefine.DownloadingPage.SurfaceWidth - ScaleX(16), False, True); + CreateLabel(DwinsHs_DownloadWizardDefine.DownloadingPage, ExpandConstant('{cm:DwinsHs_Speed}'), ScaleX(8), + ScaleY(134), DwinsHs_DownloadWizardDefine.DownloadingPage.SurfaceWidth - ScaleX(16), False, False); + DwinsHs_DownloadWizardDefine.DownloadStatus := CreateLabel(DwinsHs_DownloadWizardDefine.DownloadingPage, '', + ScaleX(8), ScaleY(154), DwinsHs_DownloadWizardDefine.DownloadingPage.SurfaceWidth - ScaleX(16), False, True); + CreateLabel(DwinsHs_DownloadWizardDefine.DownloadingPage, ExpandConstant('{cm:DwinsHs_Status}'), + ScaleX(8), ScaleY(154), DwinsHs_DownloadWizardDefine.DownloadingPage.SurfaceWidth - ScaleX(16), False, False); + DwinsHs_DownloadWizardDefine.DownloadElapsedTime := CreateLabel(DwinsHs_DownloadWizardDefine.DownloadingPage, '', + ScaleX(8), ScaleY(174), DwinsHs_DownloadWizardDefine.DownloadingPage.SurfaceWidth - ScaleX(16), False, True); + CreateLabel(DwinsHs_DownloadWizardDefine.DownloadingPage, ExpandConstant('{cm:DwinsHs_ElapsedTime}'), + ScaleX(8), ScaleY(174), DwinsHs_DownloadWizardDefine.DownloadingPage.SurfaceWidth - ScaleX(16), False, False); + DwinsHs_DownloadWizardDefine.DownloadRemainingTime := CreateLabel(DwinsHs_DownloadWizardDefine.DownloadingPage, '', + ScaleX(8), ScaleY(194), DwinsHs_DownloadWizardDefine.DownloadingPage.SurfaceWidth - ScaleX(16), False, True); + CreateLabel(DwinsHs_DownloadWizardDefine.DownloadingPage, ExpandConstant('{cm:DwinsHs_RemainingTime}'), + ScaleX(8), ScaleY(194), DwinsHs_DownloadWizardDefine.DownloadingPage.SurfaceWidth - ScaleX(16), False, False); + SetArrayLength(DwinsHs_DownloadsList, 0); + DwinsHs_Proxy.Mode := pmDefault; +end; + +type + TBeforeDownload = function (): Boolean; + TAfterDownload = procedure (State: Integer); + +var + DwinsHs_BeforeDownload: TBeforeDownload; + DwinsHs_AfterDownload: TAfterDownload; + +procedure DwinsHs_CurPageChanged(CurPageID: Integer; BeforeDownload: TBeforeDownload; AfterDownload: TAfterDownload); +var + CurURL, CurAgent: AnsiString; + CurMethod: TReadMethod; + CurDownloadedSize: LongInt; + Response: AnsiString; + CurrentSize, Size: LongInt; + i, State, MirrorID: Integer; +begin + DwinsHs_BeforeDownload := BeforeDownload; + DwinsHs_AfterDownload := AfterDownload; + if (CurPageId = DwinsHs_DownloadWizardDefine.PreviousPageId) and (CurPageId = wpPreparing) then + begin + for i := 0 to GetArrayLength(DwinsHs_DownloadsList) - 1 do DwinsHs_DownloadsList[i].Required := False; + end + else if CurPageId = DwinsHs_DownloadWizardDefine.DownloadingPage.Id then + begin + WizardForm.NextButton.Enabled := False; + WizardForm.NextButton.Caption := ExpandConstant('{cm:DwinsHs_Status_ButtonNext}'); + WizardForm.NextButton.Repaint; + if BeforeDownload <> nil then + begin + if not BeforeDownload() then Exit; + end; + DwinsHs_DownloadWizardDefine.TotalProgress.Caption := ''; + DwinsHs_DownloadWizardDefine.TotalProgress.Repaint; + DwinsHs_DownloadWizardDefine.TotalProgressBar.Position := 0; + DwinsHs_DownloadWizardDefine.TotalProgressBar.Style := npbstMarquee; + DwinsHs_DownloadWizardDefine.TotalProgressBar.Repaint; + DwinsHs_DownloadWizardDefine.CurrentProgress.Caption := ''; + DwinsHs_DownloadWizardDefine.CurrentProgress.Repaint; + DwinsHs_DownloadWizardDefine.CurrentProgressBar.Position := 0; + DwinsHs_DownloadWizardDefine.CurrentProgressBar.Style := npbstMarquee; + DwinsHs_DownloadWizardDefine.CurrentProgressBar.Repaint; + DwinsHs_DownloadWizardDefine.DownloadSpeed.Caption := ''; + DwinsHs_DownloadWizardDefine.DownloadSpeed.Repaint; + DwinsHs_DownloadWizardDefine.DownloadStatus.Caption := ExpandConstant('{cm:DwinsHs_Status_GetFileInformation}'); + DwinsHs_DownloadWizardDefine.DownloadStatus.Font.Color := DwinsHs_DownloadWizardDefine.DownloadFile.Font.Color; + DwinsHs_DownloadWizardDefine.DownloadStatus.Repaint; + DwinsHs_DownloadWizardDefine.DownloadElapsedTime.Caption := FormatTime(0); + DwinsHs_DownloadWizardDefine.DownloadElapsedTime.Repaint; + DwinsHs_DownloadWizardDefine.DownloadRemainingTime.Caption := ''; + DwinsHs_DownloadWizardDefine.DownloadRemainingTime.Repaint; + DwinsHs_ProcessMessages(); + DwinsHs_DownloadWizardDefine.DownloadError := False; + DwinsHs_DownloadWizardDefine.AllFilesSize := 0; + DwinsHs_DownloadWizardDefine.DownloadedSize := 0; + DwinsHs_CancelDownload := cdNone; + State := 0; + DwinsHs_DownloadWizardDefine.BeginTime := DecodeDateTimeString(GetDateTimeString('yyyy-mm-dd hh:nn:ss', '-', ':')); + for i := 0 to GetArrayLength(DwinsHs_DownloadsList) - 1 do + begin + if DwinsHs_DownloadsList[i].Required then + begin + DwinsHs_DownloadWizardDefine.DownloadFile.Caption := ExtractFileName(DwinsHs_DownloadsList[i].Filename); + DwinsHs_DownloadWizardDefine.DownloadFile.Repaint; + DwinsHs_DownloadsList[i].RealSize := DwinsHs_DownloadsList[i].FileSize; + if DwinsHs_DownloadsList[i].FileSize <= 0 then + begin + CurURL := DwinsHs_DownloadsList[i].URL; + CurAgent := DwinsHs_DownloadsList[i].Agent; + CurMethod := DwinsHs_DownloadsList[i].Method; + MirrorID := -1; + repeat + CurrentSize := DwinsHs_GetRemoteSize(CurURL, CurAgent, CurMethod); + if CurrentSize >= 0 then Break; + if not FindMirror(DwinsHs_DownloadsList[i].Filename, CurURL, CurAgent, CurMethod, MirrorId) then Break; + until false; + if CurrentSize >= 0 then DwinsHs_DownloadsList[i].RealSize := CurrentSize; + end; + DwinsHs_ProcessMessages(); + if DwinsHs_DownloadsList[i].RealSize > 0 then + DwinsHs_DownloadWizardDefine.AllFilesSize := + DwinsHs_DownloadWizardDefine.AllFilesSize + DwinsHs_DownloadsList[i].RealSize; + end; + end; + DwinsHs_DownloadWizardDefine.TotalProgressBar.Max := DwinsHs_DownloadWizardDefine.AllFilesSize; + DwinsHs_DownloadWizardDefine.TotalProgressBar.Style := npbstNormal; + DwinsHs_DownloadWizardDefine.CurrentProgressBar.Style := npbstNormal; + DwinsHs_DownloadWizardDefine.DownloadStatus.Font.Color := DwinsHs_DownloadWizardDefine.DownloadFile.Font.Color; + DwinsHs_DownloadWizardDefine.TotalProgressBar.State := npbsNormal; + DwinsHs_DownloadWizardDefine.CurrentProgressBar.State := npbsNormal; + DwinsHs_DownloadWizardDefine.TotalProgressBar.Repaint; + DwinsHs_DownloadWizardDefine.CurrentProgressBar.Repaint; + DwinsHs_DownloadWizardDefine.DownloadStatus.Repaint; + DwinsHs_ProcessMessages(); + for i := 0 to GetArrayLength(DwinsHs_DownloadsList) - 1 do + begin + DwinsHs_ProcessMessages(); + if DwinsHs_DownloadsList[i].Downloaded then + begin + DwinsHs_DownloadWizardDefine.DownloadedSize := + DwinsHs_DownloadWizardDefine.DownloadedSize + DwinsHs_DownloadsList[i].RealSize; + DwinsHs_DownloadWizardDefine.DownloadFile.Caption := ExtractFileName(DwinsHs_DownloadsList[i].Filename); + DwinsHs_DownloadWizardDefine.DownloadFile.Repaint; + DwinsHs_DownloadWizardDefine.DownloadStatus.Caption := ExpandConstant('{cm:DwinsHs_Status_DownlaodComplete}'); + DwinsHs_DownloadWizardDefine.DownloadStatus.Repaint; + UpdateDownloadingPage(DwinsHs_DownloadsList[i].URL, DwinsHs_DownloadsList[i].Agent, + DwinsHs_DownloadsList[i].Method, -1, DwinsHs_DownloadsList[i].RealSize, DwinsHs_DownloadsList[i].RealSize, 0, + Response); + if DwinsHs_CancelDownload <> cdNone then Break; + end + else + begin + DwinsHs_DownloadWizardDefine.DownloadFile.Caption := ExtractFileName(DwinsHs_DownloadsList[i].Filename); + DwinsHs_DownloadWizardDefine.DownloadFile.Repaint; + CurDownloadedSize := DwinsHs_DownloadWizardDefine.DownloadedSize; + CurURL := DwinsHs_DownloadsList[i].URL; + CurAgent := DwinsHs_DownloadsList[i].Agent; + CurMethod := DwinsHs_DownloadsList[i].Method; + MirrorID := -1; + repeat + DwinsHs_DownloadWizardDefine.DownloadedSize := CurDownloadedSize; + DwinsHs_DownloadWizardDefine.DownloadStatus.Caption := ExpandConstant('{cm:DwinsHs_Status_StartingDownload}'); + DwinsHs_DownloadWizardDefine.DownloadStatus.Repaint; + UpdateDownloadingPage(CurURL, CurAgent, CurMethod, -1, DwinsHs_DownloadsList[i].RealSize, 0, 0, Response); + DwinsHs_DownloadWizardDefine.CurrentProgressBar.Max := DwinsHs_DownloadsList[i].RealSize; + State := DwinsHs_ReadRemoteURL(CurURL, CurAgent, CurMethod, Response, Size, DwinsHs_DownloadsList[i].Filename, + @UpdateDownloadingPage); + DwinsHs_DownloadWizardDefine.DownloadStatus.Caption := GetDownloadStateText(State); + DwinsHs_DownloadWizardDefine.DownloadStatus.Repaint; + if DwinsHs_CancelDownload <> cdNone then Break; + if State = READ_OK then Break; + if not FindMirror(DwinsHs_DownloadsList[i].Filename, CurURL, CurAgent, CurMethod, MirrorID) then Break; + until false; + if DwinsHs_CancelDownload <> cdNone then Break; + if State <> READ_OK then Break; + DwinsHs_DownloadsList[i].Downloaded := True; + end; + WizardForm.Repaint; + end; + DwinsHs_DownloadWizardDefine.TotalProgressBar.Repaint; + DwinsHs_DownloadWizardDefine.CurrentProgressBar.Repaint; + case DwinsHs_CancelDownload of + cdNone: + begin + WizardForm.NextButton.Enabled := True; + if State <> READ_OK then + begin + DwinsHs_DownloadWizardDefine.TotalProgressBar.State := npbsError; + DwinsHs_DownloadWizardDefine.DownloadStatus.Font.Color := clRed; + DwinsHs_DownloadWizardDefine.CurrentProgressBar.State := npbsError; + WizardForm.NextButton.Caption := ExpandConstant('{cm:DwinsHs_Status_ButtonRetry}'); + WizardForm.NextButton.Repaint; + DwinsHs_DownloadWizardDefine.DownloadError := True; + if AfterDownload <> nil then AfterDownload(State); + end + else + begin + DwinsHs_DownloadWizardDefine.DownloadStatus.Font.Color := clGreen; + if AfterDownload <> nil then AfterDownload(State); + #ifdef DwinsHs_Auto_Continue + ClickNext(); + #endif + end; + end; + cdBack: ; + cdExit: ClickCancel(); + end; + end; +end; + +procedure DwinsHs_ShouldSkipPage(CurPageID: Integer; var ChangeResult: Boolean); +var + i: Integer; +begin + if CurPageID = DwinsHs_DownloadWizardDefine.DownloadingPage.Id then + begin + ChangeResult := True; + for i := 0 to GetArrayLength(DwinsHs_DownloadsList) - 1 do + begin + if DwinsHs_DownloadsList[i].Required and (not DwinsHs_DownloadsList[i].Downloaded) then + begin + ChangeResult := False; + Break; + end; + end; + end; +end; + +procedure DwinsHs_BackButtonClick(CurPageID: Integer); +begin + if CurPageID = DwinsHs_DownloadWizardDefine.DownloadingPage.Id then DwinsHs_CancelDownload := cdBack; +end; + +procedure DwinsHs_NextButtonClick(CurPageID: Integer; var ChangeResult: Boolean); +begin + if (CurPageID = DwinsHs_DownloadWizardDefine.DownloadingPage.Id) and DwinsHs_DownloadWizardDefine.DownloadError then + begin + ChangeResult := False; + DwinsHs_CurPageChanged(CurPageID, DwinsHs_BeforeDownload, DwinsHs_AfterDownload); + end; +end; + +procedure DwinsHs_CancelButtonClick(CurPageID: Integer; var Cancel, Confirm: Boolean); +begin + if (CurPageId = DwinsHs_DownloadWizardDefine.DownloadingPage.Id) and (DwinsHs_CancelDownload = cdExit) then + Confirm := False; +end; + +#endif diff --git a/distr/iss/make_tess_iss.sh b/distr/iss/make_tess_iss.sh new file mode 100755 index 0000000..b64ee6f --- /dev/null +++ b/distr/iss/make_tess_iss.sh @@ -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 diff --git a/distr/iss/tessdata.iss b/distr/iss/tessdata.iss new file mode 100644 index 0000000..9c82276 --- /dev/null +++ b/distr/iss/tessdata.iss @@ -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=Èäèø + diff --git a/distr/ru/Russian.isl b/distr/ru/Russian.isl deleted file mode 100644 index 61b380f..0000000 --- a/distr/ru/Russian.isl +++ /dev/null @@ -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=Âüåòíàìñêèé - - diff --git a/distr/sf/readme.md b/distr/sf/readme.md deleted file mode 100644 index d0a536a..0000000 --- a/distr/sf/readme.md +++ /dev/null @@ -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. diff --git a/images/STIcon.xcf b/images/STIcon.xcf new file mode 100644 index 0000000..a141be3 Binary files /dev/null and b/images/STIcon.xcf differ diff --git a/images/STIconBlue.png b/images/STIconBlue.png new file mode 100644 index 0000000..7ca2c3c Binary files /dev/null and b/images/STIconBlue.png differ diff --git a/images/STIconGreen.png b/images/STIconGreen.png new file mode 100644 index 0000000..4892af1 Binary files /dev/null and b/images/STIconGreen.png differ diff --git a/images/STIconOrange.png b/images/STIconOrange.png new file mode 100644 index 0000000..9bfa7e6 Binary files /dev/null and b/images/STIconOrange.png differ diff --git a/images/STIconRed.png b/images/STIconRed.png new file mode 100644 index 0000000..672c573 Binary files /dev/null and b/images/STIconRed.png differ diff --git a/images/icon.ico b/images/icon.ico index a89f6ee..abbac3b 100644 Binary files a/images/icon.ico and b/images/icon.ico differ diff --git a/images/icon.png b/images/icon.png deleted file mode 100644 index 17fc2c5..0000000 Binary files a/images/icon.png and /dev/null differ diff --git a/main.cpp b/main.cpp index 72d7a7b..01a9f1e 100644 --- a/main.cpp +++ b/main.cpp @@ -1,12 +1,23 @@ +#ifdef Q_OS_LINUX +# include +#endif + #include #include +#include + #include #include -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 (); } diff --git a/scripts/get_deps.sh b/scripts/get_deps.sh new file mode 100755 index 0000000..d2b0eaf --- /dev/null +++ b/scripts/get_deps.sh @@ -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 + diff --git a/scripts/get_tessdata.sh b/scripts/get_tessdata.sh new file mode 100755 index 0000000..fd20a03 --- /dev/null +++ b/scripts/get_tessdata.sh @@ -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 + diff --git a/scripts/install_deps.sh b/scripts/install_deps.sh new file mode 100755 index 0000000..1480183 --- /dev/null +++ b/scripts/install_deps.sh @@ -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 diff --git a/scripts/make_all.sh b/scripts/make_all.sh new file mode 100755 index 0000000..f325033 --- /dev/null +++ b/scripts/make_all.sh @@ -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" diff --git a/scripts/make_app.sh b/scripts/make_app.sh new file mode 100755 index 0000000..90388bb --- /dev/null +++ b/scripts/make_app.sh @@ -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 + diff --git a/scripts/make_deb.sh b/scripts/make_deb.sh new file mode 100755 index 0000000..c46fadd --- /dev/null +++ b/scripts/make_deb.sh @@ -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 `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 + diff --git a/scripts/make_deps.sh b/scripts/make_deps.sh new file mode 100755 index 0000000..d824999 --- /dev/null +++ b/scripts/make_deps.sh @@ -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" + diff --git a/scripts/make_iss.sh b/scripts/make_iss.sh new file mode 100755 index 0000000..fee4ce9 --- /dev/null +++ b/scripts/make_iss.sh @@ -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" diff --git a/scripts/make_sf.sh b/scripts/make_sf.sh new file mode 100755 index 0000000..53f3096 --- /dev/null +++ b/scripts/make_sf.sh @@ -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 diff --git a/scripts/options.sh b/scripts/options.sh new file mode 100755 index 0000000..f824fe7 --- /dev/null +++ b/scripts/options.sh @@ -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 +} + diff --git a/translations/translation_en.ts b/translations/translation_en.ts index 6f7c0a0..f8bc7fb 100644 --- a/translations/translation_en.ts +++ b/translations/translation_en.ts @@ -4,59 +4,129 @@ GoogleWebTranslator - Ðеверные парметры Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´Ð°. - Wrong translation parameters. + Wrong translation parameters. Manager - + Захват Capture - - - Перевод - Translation + Translation - Повторить - Repeat + Repeat - Скопировать - Copy + Copy - + + Повторить захват + Retry capture + + + + + + Результат + Result + + + + Показать + Show + + + + Ð’ буфер + To clipboard + + + ÐаÑтройки Settings - - + + О программе About - + Выход Exit - + + Failed to register global shortcuts: +%1 + Failed to register global shortcuts: +%1 + + + + Ðе найден подходÑщий Ñзык раÑпознаваниÑ. + Failed to find selected recognition language. + + + Программа Ð´Ð»Ñ Ñ€Ð°ÑÐ¿Ð¾Ð·Ð½Ð°Ð²Ð°Ð½Ð¸Ñ Ñ‚ÐµÐºÑта на Ñкране. Создана Ñ Ð¸Ñпользованием Qt, tesseract-ocr, Google Translate. Ðвтор: Gres (translator@gres.biz) ВерÑиÑ: %1 от %2 %3 Screen text recognition and translation program. \n Uses Qt, tesseract-ocr, Google Translate. \n Author: Gres (translator@gres.biz) \n Version: %1 from %2 %3 + + + + +ПодÑказки. +Клик по иконке в трее: +* левой кнопкой - отобразить поÑледний результат +* Ñредней кнопкой - Ñкопировать поÑледний результат в буфер обмена +* двойной клик - повторный захват поÑледнего Ñкрана + +Захвата Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸ зажатых кнопках: +* Ctrl - не выходить из режима захвата +* Alt - выполнить перевод, еÑли в наÑтройках он выключен (и наоборот, не выполнÑÑ‚ÑŒ, еÑли включен) + + + +Tips. +Tray icon click: +* left button - show last result +* middle button - copy last result to clipboard +* double click - repeat last screen capture + +Key modifiers what capturing : +* Ctrl - do not exit from capture mode +* Alt - make translation if it is disabled in settings (or do not make, if it is enabled) + + + + + ПоÑледний результат был Ñкопирован в буфер обмена. + Last result has been copied to clipboard. + + + + Правка + Correction + + + + ИÑправьте раÑпознанный текÑÑ‚ + Correct recognized text + Программа Ð´Ð»Ñ Ñ€Ð°ÑÐ¿Ð¾Ð·Ð½Ð°Ð²Ð°Ð½Ð¸Ñ Ñ‚ÐµÐºÑта на Ñкране. Создана Ñ Ð¸Ñпользованием Qt, tesseract-ocr, Google Translate. @@ -64,12 +134,11 @@ Screen text recognition and translation program. \n Uses Qt, tesseract-ocr, Google Translate. \n Author: Gres (translator@gres.biz) - ПоÑледний перевод был Ñкопирован в буфер обмена. - Last translation has been copied to the clipboard. + Last translation has been copied to the clipboard. - + Ошибка Error @@ -77,433 +146,584 @@ QObject - - + + Afrikaans Afrikaans - - + + Albanian Albanian - - + + Arabic Arabic - + Armenian Armenian - - + + Azerbaijani Azerbaijani - - + + Basque Basque - - + + Belarusian Belarusian - - + + Bulgarian Bulgarian - - + + Catalan Catalan - - + + Chinese (Simplified) Chinese (Simplified) - - + + Chinese (Traditional) Chinese (Traditional) - - + + Croatian Croatian - - + + Czech Czech - - + + Danish Danish - - + + Dutch Dutch - - + + English English - - + + Estonian Estonian - + Filipino Filipino - - + + Finnish Finnish - - + + French French - - + + Galician Galician - + + Georgian Georgian - - + + German German - - + + Greek Greek - + Haitian Creole Haitian Creole - - + + Hebrew Hebrew - - + + Hindi Hindi - - + + Hungarian Hungarian - - + + Icelandic Icelandic - - + + Indonesian Indonesian - + + Irish Irish - - + + Italian Italian - - + + Japanese Japanese - - + + Korean Korean - - + + Latvian Latvian - - + + Lithuanian Lithuanian - - + + Macedonian Macedonian - - + + Malay Malay - - + + Maltese Maltese - - + + Norwegian Norwegian - + + Persian Persian - - + + Polish Polish - - + + Portuguese Portuguese - - + + Romanian Romanian - - + + Russian Russian - - + + Serbian Serbian - + Slovak Slovak - - + + Slovenian Slovenian - - + + Spanish Spanish - - + + Swahili Swahili - - + + Swedish Swedish - - + + Thai Thai - - + + Turkish Turkish - - + + Ukrainian Ukrainian - + + Urdu Urdu - - + + Vietnamese Vietnamese - + + Welsh Welsh - + + Yiddish Yiddish - + Ancient Greek Ancient Greek - + Esperanto alternative - + Tagalog Tagalog - + Telugu Telugu - + Tamil Tamil - + Slovakian Slovakian - + Malayalam Malayalam - + Kannada Kannada - + Cherokee Cherokee - + Middle French (ca. 1400-1600) Middle French - + Frankish Frankish - + Math / equation Math / equation - + Esperanto Esperanto - + Middle English (1100-1500) Middle English - + Bengali Bengali + + + Amharic + Amharic + + + + Assamese + Assamese + + + + Tibetan + Tibetan + + + + Bosnian + Bosnian + + + + Cebuano + Cebuano + + + + Dzongkha + Dzongkha + + + + Gujarati + Gujarati + + + + Haitian + Haitian + + + + Inuktitut + Inuktitut + + + + Javanese + Javanese + + + + Kazakh + Kazakh + + + + Khmer + Khmer + + + + Kirghiz + Kirghiz + + + + Kurdish + Kurdish + + + + Lao + Lao + + + + Latin + Latin + + + + Marathi + Marathi + + + + Burmese + Burmese + + + + Nepali + Nepali + + + + Oriya + Oriya + + + + Panjabi + Panjabi + + + + Pushto + Pushto + + + + Sanskrit + Sanskrit + + + + Sinhala + Sinhala + + + + Syriac + Syriac + + + + Tajik + Tajik + + + + Tigrinya + Tigrinya + + + + Uighur + Uighur + + + + Uzbek + Uzbek + Recognizer - + Ðеверные параметры Ð´Ð»Ñ OCR Wrong parameters for OCR - + Ошибка инициализации OCR: %1 OCR initialization error: %1 - + ТекÑÑ‚ не раÑпознан. Failed to recognize text. @@ -515,6 +735,31 @@ Результат Result + + + РаÑпознать другой Ñзык + Recognize another language + + + + ПеревеÑти на другой Ñзык + Translate to another language + + + + Скопировать в буфер + Copy to clipboard + + + + Скопировать риÑунок в буфер + Copy image to clibpoard + + + + ИÑправить раÑпознанный текÑÑ‚ + Correct recognized text + SelectionDialog @@ -523,6 +768,11 @@ Dialog Selection + + + ПоменÑÑ‚ÑŒ Ñзык текÑта и перевода + Swap recognition/translation languages + SettingsEditor @@ -532,102 +782,261 @@ Settings - + + Общее + General + + + ГорÑчие клавиши Hotkeys - - - + <html><head/><body><p>Сочетание клавиш Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´Ð° в режим захвата.</p></body></html> <html><head/><body><p>Keys combination to enter capture mode.</p></body></html> - + Захватить Capture - + + <html><head/><body><p>Сочетание клавиш Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´Ð° в режим захвата, но Ñ Ð¸Ñпользованием поÑледнего иÑпользованного, а не текущего, изображениÑ.</p></body></html> + <html><head/><body><p>Keys combination to enter capture mode, but with last used image instead of current.</p></body></html> + + + + Захватить повторно + Repeat capture + + + + <html><head/><body><p>Сочетание клавиш Ð´Ð»Ñ Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€Ð½Ð¾Ð³Ð¾ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ð¾Ñледнего результата.</p></body></html> + <html><head/><body><p>Keys combination to show last result again.</p></body></html> + + + + Показать + Show + + + + <html><head/><body><p>Сочетание клавиш Ð´Ð»Ñ ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¿Ð¾Ñледнего результата в буфер обмена.</p></body></html> + <html><head/><body><p>Keys combination to copy last result to clipboard.</p></body></html> + + + Скопировать Copy - Повторить - Repeat + Repeat - + РаÑпознавание Recognition - <html><head/><body><p>Ðеобходимо Ð´Ð»Ñ Ñ€Ð°ÑпознаваниÑ.</p><p>СкачиваетÑÑ Ð¾Ñ‚Ñюда: <a href="https://code.google.com/p/tesseract-ocr/downloads/list"><span style=" text-decoration: underline; color:#0000ff;">https://code.google.com/p/tesseract-ocr/downloads/list</span></a></p></body></html> - <html><head/><body><p>Required for recognition.</p><p>Can me downloaded from there: <a href="https://code.google.com/p/tesseract-ocr/downloads/list"><span style=" text-decoration: underline; color:#0000ff;">https://code.google.com/p/tesseract-ocr/downloads/list</span></a></p></body></html> + <html><head/><body><p>Required for recognition.</p><p>Can me downloaded from there: <a href="https://code.google.com/p/tesseract-ocr/downloads/list"><span style=" text-decoration: underline; color:#0000ff;">https://code.google.com/p/tesseract-ocr/downloads/list</span></a></p></body></html> - - + + Путь к tessdata Tessdata path - + ... ... - + <html><head/><body><p>ЗаполнÑетÑÑ Ð½Ð° оÑновании ÑÐ¾Ð´ÐµÑ€Ð¶Ð°Ð½Ð¸Ñ tessdata</p></body></html> <html><head/><body><p>Values depend on tessdata contents</p></body></html> - + Язык раÑÐ¿Ð¾Ð·Ð½Ð°Ð²Ð°Ð½Ð¸Ñ Recognition language - <html><head/><body><p>МаÑштабирование Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð´Ð»Ñ ÑƒÐ»ÑƒÑ‡ÑˆÐµÐ½Ð¸Ñ Ñ€Ð°ÑпознаниÑ. Больше - лучше (до определенных пределов), но медленнее.</p></body></html> - <html><head/><body><p>Image scaling for better recognition. More is better (reasonable), but slower.</p></body></html> + <html><head/><body><p>Image scaling for better recognition. More is better (reasonable), but slower.</p></body></html> - + Увеличение маÑштаба Scale factor - + Вывод результата Result representation - + Трей Tray - + Окно Window - + + ПрокÑи + Proxy + + + + Тип: + Type: + + + + Пользователь: + User: + + + + ÐдреÑ: + Host: + + + + Пароль: + Password: + + + + Порт: + Port: + + + + СохранÑÑ‚ÑŒ пароль (небезопаÑно) + Save password (unsafe) + + + + Обновление + Updates + + + + ПроверÑÑ‚ÑŒ обновлениÑ: + Check interval: + + + + Проверить + Check now + + + + <html><head/><body><p>Ðеобходимо Ð´Ð»Ñ Ñ€Ð°ÑпознаваниÑ.</p><p>СкачиваетÑÑ Ð¾Ñ‚Ñюда: <a href="https://github.com/tesseract-ocr/tessdata"><span style=" text-decoration: underline; color:#7593bc;">https://github.com/tesseract-ocr/tessdata</span></a></p><p>&quot;./&quot; означает, что папка &quot;tessdata&quot; находитÑÑ Ð² одной директории Ñ Ð¸ÑполнÑемым файлом программы.</p></body></html> + <html><head/><body><p>Required for recognition.</p><p>Can me downloaded from there: <a href="https://github.com/tesseract-ocr/tessdata"><span style=" text-decoration: underline; color:#7593bc;">https://github.com/tesseract-ocr/tessdata</span></a></p><p>&quot;./&quot; means that .&quot;tessdata&quot; is in the same folder as program's binary</p></body></html> + + + + <html><head/><body><p>МаÑштабирование Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð´Ð»Ñ ÑƒÐ»ÑƒÑ‡ÑˆÐµÐ½Ð¸Ñ Ñ€Ð°ÑпознаниÑ. Больше - лучше (до определенных пределов), но медленнее и потреблÑет больше памÑти.</p><p>Рекомендуемые Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¾Ñ‚ 5 до 10.</p></body></html> + <html><head/><body><p>Image scaling can improve recognition results. More is better (up to reasonable limits), but slower and consumes more memory.</p><p>Recommended values are between 5 and 10.</p></body></html> + + + + <html><head/><body><p>Символы, регулÑрно раÑпознаваемые Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°Ð¼Ð¸. При обнаружении будут заменены на указанные.</p></body></html> + <html><head/><body><p>Symbols to replace in recognition results. Allows to avoid repeating errors.</p></body></html> + + + + ИÑправлениÑ: + Substitutions: + + + + Язык + Language + + + + ИÑходный текÑÑ‚ + Source + + + + ИÑправление + Target + + + Перевод Translation - + + <html><head/><body><p>Ðеобходимо ли переводить (вкл) раÑпознанный текÑÑ‚.</p></body></html> + <html><head/><body><p>If enabled - recognized text will be translated. Only recognize otherwise.</p></body></html> + + + + Переводить текÑÑ‚ + Translate text + + + + <html><head/><body><p>Отображает окно переводчика. Следует иÑпользовать только Ð´Ð»Ñ Ñ€Ð°Ð·Ñ€Ð°Ð±Ð¾Ñ‚ÐºÐ¸ переводчиков.</p></body></html> + <html><head/><body><p>Displays translator's window. Should me used only for new translators development.</p></body></html> + + + + Режим отладки + Debug mode + + + + <html><head/><body><p>МакÑимальное времÑ, которое может быть затрачено на перевод, чтобы он не ÑчиталÑÑ &quot;завиÑшим&quot;.</p></body></html> + <html><head/><body><p>Max time of translation process.</p></body></html> + + + + МакÑимальное Ð²Ñ€ÐµÐ¼Ñ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´Ð°: + Max translation time: + + + <html><head/><body><p>Язык, на который оÑущеÑтвлÑетÑÑ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´.</p></body></html> <html><head/><body><p>Translated text language.</p></body></html> - + + Язык результата: + Translation language: + + + + Переводчики: + Translators: + + + + Ñек. + secs. + + + + <html><head/><body><p>Отображены в порÑдке ÑƒÐ±Ñ‹Ð²Ð°Ð½Ð¸Ñ Ð¿Ñ€Ð¸Ð¾Ñ€Ð¸Ñ‚ÐµÑ‚Ð°.</p></body></html> + <html><head/><body><p>Sorted by priority descending.</p></body></html> + + Язык результата - Result language + Result language Afrikaans @@ -917,18 +1326,51 @@ Bengali Bengali + + + Ðикогда + Never + + + + Ежедневно + Daily + + + + Еженедельно + Weekly + + + + ЕжемеÑÑчно + Monthly + + + + Ðет + None + + + + SOCKS 5 + SOCKS 5 + + + + HTTP + HTTP + Translator - Ðеверные парметры Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´Ð°. - Wrong translation parameters. + Wrong translation parameters. - Ошибка альтернативного перевода текÑта: %1 - Failed to translate with alternative method: %1 + Failed to translate with alternative method: %1 Ошибка перевода: %1 @@ -939,4 +1381,84 @@ Translation parsing error: %1 (%2) + + Updater + + + Ошибка Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ñ‚ÐµÐºÑƒÑ‰ÐµÐ¹ верÑии. Обновление недоÑтупно. + Current version check error. Updates disabled. + + + + Ошибка загрузки информации Ð´Ð»Ñ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ. + Update load error. + + + + ДоÑтупно обновлений: %1. + + Updates available: %1. + + + + + ÐеÑовмеÑтимых обновлений: %1. +Выполните обновление вручную. + Incompatible updates: %1. +Perform manual update. + + + + ÐедоÑтупных Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи директорий: %1. +%2 +Измените права доÑтупа и повторите попытку или выполните обновление вручную. + Inaccessible dirs (no write access): %1. +%2 +Change dirs permissions and try again or perform manual update. + + + + Обновить? + Update? + + + + + Обновление + Update + + + + Ошибка Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð° (%1). + File update error (%1). + + + + Обновление завершено. Ð”Ð»Ñ Ð°ÐºÑ‚Ð¸Ð²Ð°Ñ†Ð¸Ð¸ некоторых компонентов может потребоватьÑÑ Ð¿ÐµÑ€ÐµÐ·Ð°Ð¿ÑƒÑк. + Update finished. Some components may require restart to work. + + + + Ошибка Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð° Ñ Ñ‚ÐµÐºÑƒÑ‰ÐµÐ¹ верÑией. + Failed to update current version file. + + + + WebTranslator + + + Перевод отменен по таймауту. + Translation timed out. + + + + Ошибка загрузки Ñтраницы (%1) Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´Ð°. + Page (%1) load failed. + + + + Ðет Ñценариев Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´Ð°. Измените наÑтройки. + Not found any translators. Change settings. + + diff --git a/translations/translation_ru.ts b/translations/translation_ru.ts index d93797a..690dc61 100644 --- a/translations/translation_ru.ts +++ b/translations/translation_ru.ts @@ -4,53 +4,81 @@ GoogleWebTranslator - Ðеверные парметры Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´Ð°. - Ðеверные парметры Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´Ð°. + Ðеверные парметры Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´Ð°. Manager - + Захват Захват - - - Перевод - Перевод + Перевод - Повторить - Повторить + Повторить - Скопировать - Скопировать + Скопировать - + + Повторить захват + Повторить захват + + + + + + Результат + Результат + + + + Показать + Показать + + + + Ð’ буфер + Ð’ буфер + + + ÐаÑтройки ÐаÑтройки - - + + О программе О программе - + Выход Выход - + + Failed to register global shortcuts: +%1 + Ошибка региÑтрации глобальных горÑчих клавиш: +%1 + + + + Ðе найден подходÑщий Ñзык раÑпознаваниÑ. + Ðе найден подходÑщий Ñзык раÑпознаваниÑ. + + + Программа Ð´Ð»Ñ Ñ€Ð°ÑÐ¿Ð¾Ð·Ð½Ð°Ð²Ð°Ð½Ð¸Ñ Ñ‚ÐµÐºÑта на Ñкране. Создана Ñ Ð¸Ñпользованием Qt, tesseract-ocr, Google Translate. Ðвтор: Gres (translator@gres.biz) @@ -60,6 +88,48 @@ Ðвтор: Gres (translator@gres.biz) ВерÑиÑ: %1 от %2 %3 + + + + +ПодÑказки. +Клик по иконке в трее: +* левой кнопкой - отобразить поÑледний результат +* Ñредней кнопкой - Ñкопировать поÑледний результат в буфер обмена +* двойной клик - повторный захват поÑледнего Ñкрана + +Захвата Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸ зажатых кнопках: +* Ctrl - не выходить из режима захвата +* Alt - выполнить перевод, еÑли в наÑтройках он выключен (и наоборот, не выполнÑÑ‚ÑŒ, еÑли включен) + + + +ПодÑказки. +Клик по иконке в трее: +* левой кнопкой - отобразить поÑледний результат +* Ñредней кнопкой - Ñкопировать поÑледний результат в буфер обмена +* двойной клик - повторный захват поÑледнего Ñкрана + +Захват Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸ зажатых кнопках: +* Ctrl - не выходить из режима захвата +* Alt - выполнить перевод, еÑли в наÑтройках он выключен (и наоборот, не выполнÑÑ‚ÑŒ, еÑли включен) + + + + + ПоÑледний результат был Ñкопирован в буфер обмена. + ПоÑледний результат был Ñкопирован в буфер обмена. + + + + Правка + Правка + + + + ИÑправьте раÑпознанный текÑÑ‚ + ИÑправьте раÑпознанный текÑÑ‚ + Программа Ð´Ð»Ñ Ñ€Ð°ÑÐ¿Ð¾Ð·Ð½Ð°Ð²Ð°Ð½Ð¸Ñ Ñ‚ÐµÐºÑта на Ñкране. Создана Ñ Ð¸Ñпользованием Qt, tesseract-ocr, Google Translate. @@ -69,12 +139,11 @@ Ðвтор: Gres (translator@gres.biz) - ПоÑледний перевод был Ñкопирован в буфер обмена. - ПоÑледний перевод был Ñкопирован в буфер обмена. + ПоÑледний перевод был Ñкопирован в буфер обмена. - + Ошибка Ошибка @@ -82,433 +151,584 @@ QObject - - + + Afrikaans ÐÑ„Ñ€Ð¸ÐºÐ°Ð°Ð½Ñ - - + + Albanian ÐлбанÑкий - - + + Arabic ÐрабÑкий - + Armenian ÐрмÑнÑкий - - + + Azerbaijani ÐзербайджанÑкий - - + + Basque БаÑков - - + + Belarusian БелоруÑÑкий - - + + Bulgarian БолгарÑкий - - + + Catalan КаталонÑкий - - + + Chinese (Simplified) КитайÑкий (упрощенный) - - + + Chinese (Traditional) КитайÑкий (традиционный) - - + + Croatian ХорватÑкий - - + + Czech ЧешÑкий - - + + Danish ДатÑкий - - + + Dutch ГолландÑкий - - + + English ÐнглийÑкий - - + + Estonian ЭÑтонÑкий - + Filipino ФилиппинÑкий - - + + Finnish ФинÑкий - - + + French ФранцузÑкий - - + + Galician Галицкий - + + Georgian ГрузинÑкий - - + + German Ðемецкий - - + + Greek ГречеÑкий - + Haitian Creole ГаитÑнÑкий креольÑкий - - + + Hebrew Иврит - - + + Hindi Хинди - - + + Hungarian ВенгерÑкий - - + + Icelandic ИÑландÑкий - - + + Indonesian ИндонезийÑкий - + + Irish ИрландÑкий - - + + Italian ИтальÑнÑкий - - + + Japanese ЯпонÑкий - - + + Korean КорейÑкий - - + + Latvian ЛатвийÑкий - - + + Lithuanian ЛитовÑкий - - + + Macedonian МакедонÑкий - - + + Malay МалайÑкий - - + + Maltese МальтийÑкий - - + + Norwegian ÐорвежÑкий - + + Persian ПерÑидÑкий - - + + Polish ПольÑкий - - + + Portuguese ПортугальÑкий - - + + Romanian РумынÑкий - - + + Russian РуÑÑкий - - + + Serbian СербÑкий - + Slovak Словацкий - - + + Slovenian СловенÑкий - - + + Spanish ИÑпанÑкий - - + + Swahili Суахили - - + + Swedish ШведÑкий - - + + Thai ТайÑкий - - + + Turkish Турецкий - - + + Ukrainian УкраинÑкий - + + Urdu Урду - - + + Vietnamese ВьетнамÑкий - + + Welsh ВаллийÑкий - + + Yiddish Идиш - + Ancient Greek ДревнегречеÑкий - + Esperanto alternative ЭÑперанто альтернативный - + Tagalog ТагальÑкий - + Telugu Телугу - + Tamil Тамил - + Slovakian Словацкий - + Malayalam МалаÑлам - + Kannada Каннада - + Cherokee Чероки - + Middle French (ca. 1400-1600) Средневековый ФранцузÑкий - + Frankish ФранкÑкий - + Math / equation Математика/уравнение - + Esperanto ЭÑперанто - + Middle English (1100-1500) Средневековый ÐнглийÑкий - + Bengali БенгальÑкий + + + Amharic + ÐмхарÑкий + + + + Assamese + ÐÑÑамÑкий + + + + Tibetan + ТибетÑкий + + + + Bosnian + БоÑнийÑкий + + + + Cebuano + Кебуано + + + + Dzongkha + Джонгха + + + + Gujarati + Гуджарати + + + + Haitian + Гаити + + + + Inuktitut + Инуктитут + + + + Javanese + ЯванÑкий + + + + Kazakh + КазахÑкий + + + + Khmer + КхмерÑкий + + + + Kirghiz + КиргизÑкий + + + + Kurdish + КурдÑкий + + + + Lao + Лао + + + + Latin + ЛатинÑкий + + + + Marathi + Маратхи + + + + Burmese + БирманÑкий + + + + Nepali + ÐепальÑкий + + + + Oriya + ÐžÑ€Ð¸Ñ + + + + Panjabi + Панджаби + + + + Pushto + Пушту + + + + Sanskrit + СанÑкрит + + + + Sinhala + СингальÑкий + + + + Syriac + СирийÑкий + + + + Tajik + ТаджикиÑкий + + + + Tigrinya + Тиграи + + + + Uighur + УйгурÑкий + + + + Uzbek + УзбекÑкий + Recognizer - + Ðеверные параметры Ð´Ð»Ñ OCR Ðеверные параметры Ð´Ð»Ñ OCR - + Ошибка инициализации OCR: %1 Ошибка инициализации OCR: %1 - + ТекÑÑ‚ не раÑпознан. ТекÑÑ‚ не раÑпознан. @@ -520,6 +740,31 @@ Результат Результат + + + РаÑпознать другой Ñзык + РаÑпознать другой Ñзык + + + + ПеревеÑти на другой Ñзык + ПеревеÑти на другой Ñзык + + + + Скопировать в буфер + Скопировать в буфер + + + + Скопировать риÑунок в буфер + Скопировать риÑунок в буфер + + + + ИÑправить раÑпознанный текÑÑ‚ + ИÑправить раÑпознанный текÑÑ‚ + SelectionDialog @@ -528,6 +773,11 @@ Dialog Выбор + + + ПоменÑÑ‚ÑŒ Ñзык текÑта и перевода + ПоменÑÑ‚ÑŒ Ñзык текÑта и перевода + SettingsEditor @@ -537,102 +787,261 @@ ÐаÑтройки - + + Общее + Общее + + + ГорÑчие клавиши ГорÑчие клавиши - - - + <html><head/><body><p>Сочетание клавиш Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´Ð° в режим захвата.</p></body></html> <html><head/><body><p>Сочетание клавиш Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´Ð° в режим захвата.</p></body></html> - + Захватить Захватить - + + <html><head/><body><p>Сочетание клавиш Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´Ð° в режим захвата, но Ñ Ð¸Ñпользованием поÑледнего иÑпользованного, а не текущего, изображениÑ.</p></body></html> + <html><head/><body><p>Сочетание клавиш Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´Ð° в режим захвата, но Ñ Ð¸Ñпользованием поÑледнего иÑпользованного, а не текущего, изображениÑ.</p></body></html> + + + + Захватить повторно + Захватить повторно + + + + <html><head/><body><p>Сочетание клавиш Ð´Ð»Ñ Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€Ð½Ð¾Ð³Ð¾ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ð¾Ñледнего результата.</p></body></html> + <html><head/><body><p>Сочетание клавиш Ð´Ð»Ñ Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€Ð½Ð¾Ð³Ð¾ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ð¾Ñледнего результата.</p></body></html> + + + + Показать + Показать + + + + <html><head/><body><p>Сочетание клавиш Ð´Ð»Ñ ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¿Ð¾Ñледнего результата в буфер обмена.</p></body></html> + <html><head/><body><p>Сочетание клавиш Ð´Ð»Ñ ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¿Ð¾Ñледнего результата в буфер обмена.</p></body></html> + + + Скопировать Скопировать - Повторить - Повторить + Повторить - + РаÑпознавание РаÑпознавание - <html><head/><body><p>Ðеобходимо Ð´Ð»Ñ Ñ€Ð°ÑпознаваниÑ.</p><p>СкачиваетÑÑ Ð¾Ñ‚Ñюда: <a href="https://code.google.com/p/tesseract-ocr/downloads/list"><span style=" text-decoration: underline; color:#0000ff;">https://code.google.com/p/tesseract-ocr/downloads/list</span></a></p></body></html> - <html><head/><body><p>Ðеобходимо Ð´Ð»Ñ Ñ€Ð°ÑпознаваниÑ.</p><p>СкачиваетÑÑ Ð¾Ñ‚Ñюда: <a href="https://code.google.com/p/tesseract-ocr/downloads/list"><span style=" text-decoration: underline; color:#0000ff;">https://code.google.com/p/tesseract-ocr/downloads/list</span></a></p></body></html> + <html><head/><body><p>Ðеобходимо Ð´Ð»Ñ Ñ€Ð°ÑпознаваниÑ.</p><p>СкачиваетÑÑ Ð¾Ñ‚Ñюда: <a href="https://code.google.com/p/tesseract-ocr/downloads/list"><span style=" text-decoration: underline; color:#0000ff;">https://code.google.com/p/tesseract-ocr/downloads/list</span></a></p></body></html> - - + + Путь к tessdata Путь к tessdata - + ... ... - + <html><head/><body><p>ЗаполнÑетÑÑ Ð½Ð° оÑновании ÑÐ¾Ð´ÐµÑ€Ð¶Ð°Ð½Ð¸Ñ tessdata</p></body></html> <html><head/><body><p>ЗаполнÑетÑÑ Ð½Ð° оÑновании ÑÐ¾Ð´ÐµÑ€Ð¶Ð°Ð½Ð¸Ñ tessdata</p></body></html> - + Язык раÑÐ¿Ð¾Ð·Ð½Ð°Ð²Ð°Ð½Ð¸Ñ Ð¯Ð·Ñ‹Ðº раÑÐ¿Ð¾Ð·Ð½Ð°Ð²Ð°Ð½Ð¸Ñ - <html><head/><body><p>МаÑштабирование Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð´Ð»Ñ ÑƒÐ»ÑƒÑ‡ÑˆÐµÐ½Ð¸Ñ Ñ€Ð°ÑпознаниÑ. Больше - лучше (до определенных пределов), но медленнее.</p></body></html> - <html><head/><body><p>МаÑштабирование Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð´Ð»Ñ ÑƒÐ»ÑƒÑ‡ÑˆÐµÐ½Ð¸Ñ Ñ€Ð°ÑпознаниÑ. Больше - лучше (до определенных пределов), но медленнее.</p></body></html> + <html><head/><body><p>МаÑштабирование Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð´Ð»Ñ ÑƒÐ»ÑƒÑ‡ÑˆÐµÐ½Ð¸Ñ Ñ€Ð°ÑпознаниÑ. Больше - лучше (до определенных пределов), но медленнее.</p></body></html> - + Увеличение маÑштаба Увеличение маÑштаба - + Вывод результата Вывод результата - + Трей Трей - + Окно Окно - + + ПрокÑи + ПрокÑи + + + + Тип: + Тип: + + + + Пользователь: + Пользователь: + + + + ÐдреÑ: + ÐдреÑ: + + + + Пароль: + Пароль: + + + + Порт: + Порт: + + + + СохранÑÑ‚ÑŒ пароль (небезопаÑно) + СохранÑÑ‚ÑŒ пароль (небезопаÑно) + + + + Обновление + Обновление + + + + ПроверÑÑ‚ÑŒ обновлениÑ: + ПроверÑÑ‚ÑŒ обновлениÑ: + + + + Проверить + Проверить + + + + <html><head/><body><p>Ðеобходимо Ð´Ð»Ñ Ñ€Ð°ÑпознаваниÑ.</p><p>СкачиваетÑÑ Ð¾Ñ‚Ñюда: <a href="https://github.com/tesseract-ocr/tessdata"><span style=" text-decoration: underline; color:#7593bc;">https://github.com/tesseract-ocr/tessdata</span></a></p><p>&quot;./&quot; означает, что папка &quot;tessdata&quot; находитÑÑ Ð² одной директории Ñ Ð¸ÑполнÑемым файлом программы.</p></body></html> + <html><head/><body><p>Ðеобходимо Ð´Ð»Ñ Ñ€Ð°ÑпознаваниÑ.</p><p>СкачиваетÑÑ Ð¾Ñ‚Ñюда: <a href="https://github.com/tesseract-ocr/tessdata"><span style=" text-decoration: underline; color:#7593bc;">https://github.com/tesseract-ocr/tessdata</span></a></p><p>&quot;./&quot; означает, что папка &quot;tessdata&quot; находитÑÑ Ð² одной директории Ñ Ð¸ÑполнÑемым файлом программы.</p></body></html> + + + + <html><head/><body><p>МаÑштабирование Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð´Ð»Ñ ÑƒÐ»ÑƒÑ‡ÑˆÐµÐ½Ð¸Ñ Ñ€Ð°ÑпознаниÑ. Больше - лучше (до определенных пределов), но медленнее и потреблÑет больше памÑти.</p><p>Рекомендуемые Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¾Ñ‚ 5 до 10.</p></body></html> + <html><head/><body><p>МаÑштабирование Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð´Ð»Ñ ÑƒÐ»ÑƒÑ‡ÑˆÐµÐ½Ð¸Ñ Ñ€Ð°ÑпознаниÑ. Больше - лучше (до определенных пределов), но медленнее и потреблÑет больше памÑти.</p><p>Рекомендуемые Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¾Ñ‚ 5 до 10.</p></body></html> + + + + <html><head/><body><p>Символы, регулÑрно раÑпознаваемые Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°Ð¼Ð¸. При обнаружении будут заменены на указанные.</p></body></html> + <html><head/><body><p>Символы, регулÑрно раÑпознаваемые Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°Ð¼Ð¸. При обнаружении будут заменены на указанные.</p></body></html> + + + + ИÑправлениÑ: + ИÑправлениÑ: + + + + Язык + Язык + + + + ИÑходный текÑÑ‚ + ИÑходный текÑÑ‚ + + + + ИÑправление + ИÑправление + + + Перевод Перевод - + + <html><head/><body><p>Ðеобходимо ли переводить (вкл) раÑпознанный текÑÑ‚.</p></body></html> + <html><head/><body><p>Ðеобходимо ли переводить (вкл) раÑпознанный текÑÑ‚.</p></body></html> + + + + Переводить текÑÑ‚ + Переводить текÑÑ‚ + + + + <html><head/><body><p>Отображает окно переводчика. Следует иÑпользовать только Ð´Ð»Ñ Ñ€Ð°Ð·Ñ€Ð°Ð±Ð¾Ñ‚ÐºÐ¸ переводчиков.</p></body></html> + <html><head/><body><p>Отображает окно переводчика. Следует иÑпользовать только Ð´Ð»Ñ Ñ€Ð°Ð·Ñ€Ð°Ð±Ð¾Ñ‚ÐºÐ¸ переводчиков.</p></body></html> + + + + Режим отладки + Режим отладки + + + + <html><head/><body><p>МакÑимальное времÑ, которое может быть затрачено на перевод, чтобы он не ÑчиталÑÑ &quot;завиÑшим&quot;.</p></body></html> + <html><head/><body><p>МакÑимальное времÑ, которое может быть затрачено на перевод, чтобы он не ÑчиталÑÑ &quot;завиÑшим&quot;.</p></body></html> + + + + МакÑимальное Ð²Ñ€ÐµÐ¼Ñ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´Ð°: + МакÑимальное Ð²Ñ€ÐµÐ¼Ñ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´Ð°: + + + <html><head/><body><p>Язык, на который оÑущеÑтвлÑетÑÑ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´.</p></body></html> <html><head/><body><p>Язык, на который оÑущеÑтвлÑетÑÑ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´.</p></body></html> - + + Язык результата: + Язык результата: + + + + Переводчики: + Переводчики: + + + + Ñек. + Ñек. + + + + <html><head/><body><p>Отображены в порÑдке ÑƒÐ±Ñ‹Ð²Ð°Ð½Ð¸Ñ Ð¿Ñ€Ð¸Ð¾Ñ€Ð¸Ñ‚ÐµÑ‚Ð°.</p></body></html> + <html><head/><body><p>Отображены в порÑдке ÑƒÐ±Ñ‹Ð²Ð°Ð½Ð¸Ñ Ð¿Ñ€Ð¸Ð¾Ñ€Ð¸Ñ‚ÐµÑ‚Ð°.</p></body></html> + + Язык результата - Язык результата + Язык результата Afrikaans @@ -926,18 +1335,51 @@ Bengali БенгальÑкий + + + Ðикогда + Ðикогда + + + + Ежедневно + Ежедневно + + + + Еженедельно + Еженедельно + + + + ЕжемеÑÑчно + ЕжемеÑÑчно + + + + Ðет + Ðет + + + + SOCKS 5 + SOCKS 5 + + + + HTTP + HTTP + Translator - Ðеверные парметры Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´Ð°. - Ðеверные парметры Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´Ð°. + Ðеверные парметры Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´Ð°. - Ошибка альтернативного перевода текÑта: %1 - Ошибка альтернативного перевода текÑта: %1 + Ошибка альтернативного перевода текÑта: %1 Ошибка перевода: %1 @@ -948,4 +1390,84 @@ Ошибка разбора перевода: %1 (%2) + + Updater + + + Ошибка Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ñ‚ÐµÐºÑƒÑ‰ÐµÐ¹ верÑии. Обновление недоÑтупно. + Ошибка Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ñ‚ÐµÐºÑƒÑ‰ÐµÐ¹ верÑии. Обновление недоÑтупно. + + + + Ошибка загрузки информации Ð´Ð»Ñ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ. + Ошибка загрузки информации Ð´Ð»Ñ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ. + + + + ДоÑтупно обновлений: %1. + + ДоÑтупно обновлений: %1. + + + + + ÐеÑовмеÑтимых обновлений: %1. +Выполните обновление вручную. + ÐеÑовмеÑтимых обновлений: %1. +Выполните обновление вручную. + + + + ÐедоÑтупных Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи директорий: %1. +%2 +Измените права доÑтупа и повторите попытку или выполните обновление вручную. + ÐедоÑтупных Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи директорий: %1. +%2 +Измените права доÑтупа и повторите попытку или выполните обновление вручную. + + + + Обновить? + Обновить? + + + + + Обновление + Обновление + + + + Ошибка Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð° (%1). + Ошибка Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð° (%1). + + + + Обновление завершено. Ð”Ð»Ñ Ð°ÐºÑ‚Ð¸Ð²Ð°Ñ†Ð¸Ð¸ некоторых компонентов может потребоватьÑÑ Ð¿ÐµÑ€ÐµÐ·Ð°Ð¿ÑƒÑк. + Обновление завершено. Ð”Ð»Ñ Ð°ÐºÑ‚Ð¸Ð²Ð°Ñ†Ð¸Ð¸ некоторых компонентов может потребоватьÑÑ Ð¿ÐµÑ€ÐµÐ·Ð°Ð¿ÑƒÑк. + + + + Ошибка Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð° Ñ Ñ‚ÐµÐºÑƒÑ‰ÐµÐ¹ верÑией. + Ошибка Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð° Ñ Ñ‚ÐµÐºÑƒÑ‰ÐµÐ¹ верÑией. + + + + WebTranslator + + + Перевод отменен по таймауту. + Перевод отменен по таймауту. + + + + Ошибка загрузки Ñтраницы (%1) Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´Ð°. + Ошибка загрузки Ñтраницы (%1) Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´Ð°. + + + + Ðет Ñценариев Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´Ð°. Измените наÑтройки. + Ðет Ñценариев Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´Ð°. Измените наÑтройки. + + diff --git a/translators/bing.js b/translators/bing.js new file mode 100644 index 0000000..2fa19c1 --- /dev/null +++ b/translators/bing.js @@ -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); +} diff --git a/translators/google.js b/translators/google.js new file mode 100644 index 0000000..1607db2 --- /dev/null +++ b/translators/google.js @@ -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); +} diff --git a/translators/yandex.js b/translators/yandex.js new file mode 100644 index 0000000..7686593 --- /dev/null +++ b/translators/yandex.js @@ -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); +} diff --git a/uncrustify.cfg b/uncrustify.cfg new file mode 100644 index 0000000..d589be4 --- /dev/null +++ b/uncrustify.cfg @@ -0,0 +1,1578 @@ +# Uncrustify 0.60 + +# +# General options +# + +# The type of line endings +newlines = auto # auto/lf/crlf/cr + +# The original size of tabs in the input +input_tab_size = 2 # number + +# The size of tabs in the output (only used if align_with_tabs=true) +output_tab_size = 2 # number + +# The ASCII value of the string escape char, usually 92 (\) or 94 (^). (Pawn) +string_escape_char = 92 # number + +# Alternate string escape char for Pawn. Only works right before the quote char. +string_escape_char2 = 0 # number + +# Allow interpreting '>=' and '>>=' as part of a template in 'void f(list>=val);'. +# If true (default), 'assert(x<0 && y>=3)' will be broken. +# Improvements to template detection may make this option obsolete. +tok_split_gte = false # false/true + +# Control what to do with the UTF-8 BOM (recommend 'remove') +utf8_bom = ignore # ignore/add/remove/force + +# If the file contains bytes with values between 128 and 255, but is not UTF-8, then output as UTF-8 +utf8_byte = false # false/true + +# Force the output encoding to UTF-8 +utf8_force = false # false/true + +# +# Indenting +# + +# The number of columns to indent per level. +# Usually 2, 3, 4, or 8. +indent_columns = 2 # number + +# The continuation indent. If non-zero, this overrides the indent of '(' and '=' continuation indents. +# For FreeBSD, this is set to 4. Negative value is absolute and not increased for each ( level +indent_continue = 0 # number + +# How to use tabs when indenting code +# 0=spaces only +# 1=indent with tabs to brace level, align with spaces +# 2=indent and align with tabs, using spaces when not on a tabstop +indent_with_tabs = 0 # number + +# Comments that are not a brace level are indented with tabs on a tabstop. +# Requires indent_with_tabs=2. If false, will use spaces. +indent_cmt_with_tabs = false # false/true + +# Whether to indent strings broken by '\' so that they line up +indent_align_string = false # false/true + +# The number of spaces to indent multi-line XML strings. +# Requires indent_align_string=True +indent_xml_string = 0 # number + +# Spaces to indent '{' from level +indent_brace = 0 # number + +# Whether braces are indented to the body level +indent_braces = false # false/true + +# Disabled indenting function braces if indent_braces is true +indent_braces_no_func = false # false/true + +# Disabled indenting class braces if indent_braces is true +indent_braces_no_class = false # false/true + +# Disabled indenting struct braces if indent_braces is true +indent_braces_no_struct = false # false/true + +# Indent based on the size of the brace parent, i.e. 'if' => 3 spaces, 'for' => 4 spaces, etc. +indent_brace_parent = false # false/true + +# Whether the 'namespace' body is indented +indent_namespace = true # false/true + +# The number of spaces to indent a namespace block +indent_namespace_level = 2 # number + +# If the body of the namespace is longer than this number, it won't be indented. +# Requires indent_namespace=true. Default=0 (no limit) +indent_namespace_limit = 0 # number + +# Whether the 'extern "C"' body is indented +indent_extern = true # false/true + +# Whether the 'class' body is indented +indent_class = true # false/true + +# Whether to indent the stuff after a leading class colon +indent_class_colon = true # false/true + +# Virtual indent from the ':' for member initializers. Default is 2 +indent_ctor_init_leading = 2 # number + +# Additional indenting for constructor initializer list +indent_ctor_init = 0 # number + +# False=treat 'else\nif' as 'else if' for indenting purposes +# True=indent the 'if' one level +indent_else_if = false # false/true + +# Amount to indent variable declarations after a open brace. neg=relative, pos=absolute +indent_var_def_blk = 0 # number + +# Indent continued variable declarations instead of aligning. +indent_var_def_cont = false # false/true + +# True: force indentation of function definition to start in column 1 +# False: use the default behavior +indent_func_def_force_col1 = false # false/true + +# True: indent continued function call parameters one indent level +# False: align parameters under the open paren +indent_func_call_param = false # false/true + +# Same as indent_func_call_param, but for function defs +indent_func_def_param = false # false/true + +# Same as indent_func_call_param, but for function protos +indent_func_proto_param = false # false/true + +# Same as indent_func_call_param, but for class declarations +indent_func_class_param = false # false/true + +# Same as indent_func_call_param, but for class variable constructors +indent_func_ctor_var_param = false # false/true + +# Same as indent_func_call_param, but for templates +indent_template_param = false # false/true + +# Double the indent for indent_func_xxx_param options +indent_func_param_double = false # false/true + +# Indentation column for standalone 'const' function decl/proto qualifier +indent_func_const = 0 # number + +# Indentation column for standalone 'throw' function decl/proto qualifier +indent_func_throw = 0 # number + +# The number of spaces to indent a continued '->' or '.' +# Usually set to 0, 1, or indent_columns. +indent_member = 0 # number + +# Spaces to indent single line ('//') comments on lines before code +indent_sing_line_comments = 0 # number + +# If set, will indent trailing single line ('//') comments relative +# to the code instead of trying to keep the same absolute column +indent_relative_single_line_comments = false # false/true + +# Spaces to indent 'case' from 'switch' +# Usually 0 or indent_columns. +indent_switch_case = 2 # number + +# Spaces to shift the 'case' line, without affecting any other lines +# Usually 0. +indent_case_shift = 0 # number + +# Spaces to indent '{' from 'case'. +# By default, the brace will appear under the 'c' in case. +# Usually set to 0 or indent_columns. +indent_case_brace = 2 # number + +# Whether to indent comments found in first column +indent_col1_comment = true # false/true + +# How to indent goto labels +# >0 : absolute column where 1 is the leftmost column +# <=0 : subtract from brace indent +indent_label = 1 # number + +# Same as indent_label, but for access specifiers that are followed by a colon +indent_access_spec = 1 # number + +# Indent the code after an access specifier by one level. +# If set, this option forces 'indent_access_spec=0' +indent_access_spec_body = true # false/true + +# If an open paren is followed by a newline, indent the next line so that it lines up after the open paren (not recommended) +indent_paren_nl = false # false/true + +# Controls the indent of a close paren after a newline. +# 0: Indent to body level +# 1: Align under the open paren +# 2: Indent to the brace level +indent_paren_close = 0 # number + +# Controls the indent of a comma when inside a paren.If TRUE, aligns under the open paren +indent_comma_paren = false # false/true + +# Controls the indent of a BOOL operator when inside a paren.If TRUE, aligns under the open paren +indent_bool_paren = false # false/true + +# If 'indent_bool_paren' is true, controls the indent of the first expression. If TRUE, aligns the first expression to the following ones +indent_first_bool_expr = false # false/true + +# If an open square is followed by a newline, indent the next line so that it lines up after the open square (not recommended) +indent_square_nl = false # false/true + +# Don't change the relative indent of ESQL/C 'EXEC SQL' bodies +indent_preserve_sql = false # false/true + +# Align continued statements at the '='. Default=True +# If FALSE or the '=' is followed by a newline, the next line is indent one tab. +indent_align_assign = true # false/true + +# Indent OC blocks at brace level instead of usual rules. +indent_oc_block = false # false/true + +# Indent OC blocks in a message relative to the parameter name. +# 0=use indent_oc_block rules, 1+=spaces to indent +indent_oc_block_msg = 0 # number + +# Minimum indent for subsequent parameters +indent_oc_msg_colon = 0 # number + +# +# Spacing options +# + +# Add or remove space around arithmetic operator '+', '-', '/', '*', etc +sp_arith = add # ignore/add/remove/force + +# Add or remove space around assignment operator '=', '+=', etc +sp_assign = add " # ignore/add/remove/force + +# Add or remove space around '=' in C++11 lambda capture specifications. Overrides sp_assign +sp_cpp_lambda_assign = ignore # ignore/add/remove/force + +# Add or remove space after the capture specification in C++11 lambda. +sp_cpp_lambda_paren = ignore # ignore/add/remove/force + +# Add or remove space around assignment operator '=' in a prototype +sp_assign_default = add # ignore/add/remove/force + +# Add or remove space before assignment operator '=', '+=', etc. Overrides sp_assign. +sp_before_assign = add # ignore/add/remove/force + +# Add or remove space after assignment operator '=', '+=', etc. Overrides sp_assign. +sp_after_assign = add # ignore/add/remove/force + +# Add or remove space around assignment '=' in enum +sp_enum_assign = add # ignore/add/remove/force + +# Add or remove space before assignment '=' in enum. Overrides sp_enum_assign. +sp_enum_before_assign = add # ignore/add/remove/force + +# Add or remove space after assignment '=' in enum. Overrides sp_enum_assign. +sp_enum_after_assign = add # ignore/add/remove/force + +# Add or remove space around preprocessor '##' concatenation operator. Default=Add +sp_pp_concat = add # ignore/add/remove/force + +# Add or remove space after preprocessor '#' stringify operator. Also affects the '#@' charizing operator. +sp_pp_stringify = ignore # ignore/add/remove/force + +# Add or remove space before preprocessor '#' stringify operator as in '#define x(y) L#y'. +sp_before_pp_stringify = ignore # ignore/add/remove/force + +# Add or remove space around boolean operators '&&' and '||' +sp_bool = add # ignore/add/remove/force + +# Add or remove space around compare operator '<', '>', '==', etc +sp_compare = add # ignore/add/remove/force + +# Add or remove space inside '(' and ')' +sp_inside_paren = ignore # ignore/add/remove/force + +# Add or remove space between nested parens +sp_paren_paren = ignore # ignore/add/remove/force + +# Whether to balance spaces inside nested parens +sp_balance_nested_parens = false # false/true + +# Add or remove space between ')' and '{' +sp_paren_brace = add # ignore/add/remove/force + +# Add or remove space before pointer star '*' +sp_before_ptr_star = add # ignore/add/remove/force + +# Add or remove space before pointer star '*' that isn't followed by a variable name +# If set to 'ignore', sp_before_ptr_star is used instead. +sp_before_unnamed_ptr_star = ignore # ignore/add/remove/force + +# Add or remove space between pointer stars '*' +sp_between_ptr_star = remove # ignore/add/remove/force + +# Add or remove space after pointer star '*', if followed by a word. +sp_after_ptr_star = remove # ignore/add/remove/force + +# Add or remove space after a pointer star '*', if followed by a func proto/def. +sp_after_ptr_star_func = add # ignore/add/remove/force + +# Add or remove space after a pointer star '*', if followed by an open paren (function types). +sp_ptr_star_paren = ignore # ignore/add/remove/force + +# Add or remove space before a pointer star '*', if followed by a func proto/def. +sp_before_ptr_star_func = ignore # ignore/add/remove/force + +# Add or remove space before a reference sign '&' +sp_before_byref = add # ignore/add/remove/force + +# Add or remove space before a reference sign '&' that isn't followed by a variable name +# If set to 'ignore', sp_before_byref is used instead. +sp_before_unnamed_byref = ignore # ignore/add/remove/force + +# Add or remove space after reference sign '&', if followed by a word. +sp_after_byref = remove # ignore/add/remove/force + +# Add or remove space after a reference sign '&', if followed by a func proto/def. +sp_after_byref_func = ignore # ignore/add/remove/force + +# Add or remove space before a reference sign '&', if followed by a func proto/def. +sp_before_byref_func = ignore # ignore/add/remove/force + +# Add or remove space between type and word. Default=Force +sp_after_type = force # ignore/add/remove/force + +# Add or remove space before the paren in the D constructs 'template Foo(' and 'class Foo('. +sp_before_template_paren = ignore # ignore/add/remove/force + +# Add or remove space in 'template <' vs 'template<'. +# If set to ignore, sp_before_angle is used. +sp_template_angle = ignore # ignore/add/remove/force + +# Add or remove space before '<>' +sp_before_angle = ignore # ignore/add/remove/force + +# Add or remove space inside '<' and '>' +sp_inside_angle = ignore # ignore/add/remove/force + +# Add or remove space after '<>' +sp_after_angle = ignore # ignore/add/remove/force + +# Add or remove space between '<>' and '(' as found in 'new List();' +sp_angle_paren = ignore # ignore/add/remove/force + +# Add or remove space between '<>' and a word as in 'List m;' +sp_angle_word = ignore # ignore/add/remove/force + +# Add or remove space between '>' and '>' in '>>' (template stuff C++/C# only). Default=Add +sp_angle_shift = add # ignore/add/remove/force + +# Permit removal of the space between '>>' in 'foo >' (C++11 only). Default=False +# sp_angle_shift cannot remove the space without this option. +sp_permit_cpp11_shift = false # false/true + +# Add or remove space before '(' of 'if', 'for', 'switch', and 'while' +sp_before_sparen = add # ignore/add/remove/force + +# Add or remove space inside if-condition '(' and ')' +sp_inside_sparen = ignore # ignore/add/remove/force + +# Add or remove space before if-condition ')'. Overrides sp_inside_sparen. +sp_inside_sparen_close = ignore # ignore/add/remove/force + +# Add or remove space before if-condition '('. Overrides sp_inside_sparen. +sp_inside_sparen_open = ignore # ignore/add/remove/force + +# Add or remove space after ')' of 'if', 'for', 'switch', and 'while' +sp_after_sparen = ignore # ignore/add/remove/force + +# Add or remove space between ')' and '{' of 'if', 'for', 'switch', and 'while' +sp_sparen_brace = ignore # ignore/add/remove/force + +# Add or remove space between 'invariant' and '(' in the D language. +sp_invariant_paren = ignore # ignore/add/remove/force + +# Add or remove space after the ')' in 'invariant (C) c' in the D language. +sp_after_invariant_paren = ignore # ignore/add/remove/force + +# Add or remove space before empty statement ';' on 'if', 'for' and 'while' +sp_special_semi = ignore # ignore/add/remove/force + +# Add or remove space before ';'. Default=Remove +sp_before_semi = remove # ignore/add/remove/force + +# Add or remove space before ';' in non-empty 'for' statements +sp_before_semi_for = ignore # ignore/add/remove/force + +# Add or remove space before a semicolon of an empty part of a for statement. +sp_before_semi_for_empty = ignore # ignore/add/remove/force + +# Add or remove space after ';', except when followed by a comment. Default=Add +sp_after_semi = add # ignore/add/remove/force + +# Add or remove space after ';' in non-empty 'for' statements. Default=Force +sp_after_semi_for = force # ignore/add/remove/force + +# Add or remove space after the final semicolon of an empty part of a for statement: for ( ; ; ). +sp_after_semi_for_empty = ignore # ignore/add/remove/force + +# Add or remove space before '[' (except '[]') +sp_before_square = ignore # ignore/add/remove/force + +# Add or remove space before '[]' +sp_before_squares = ignore # ignore/add/remove/force + +# Add or remove space inside a non-empty '[' and ']' +sp_inside_square = ignore # ignore/add/remove/force + +# Add or remove space after ',' +sp_after_comma = ignore # ignore/add/remove/force + +# Add or remove space before ',' +sp_before_comma = remove # ignore/add/remove/force + +# Add or remove space between an open paren and comma: '(,' vs '( ,' +sp_paren_comma = force # ignore/add/remove/force + +# Add or remove space before the variadic '...' when preceded by a non-punctuator +sp_before_ellipsis = ignore # ignore/add/remove/force + +# Add or remove space after class ':' +sp_after_class_colon = ignore # ignore/add/remove/force + +# Add or remove space before class ':' +sp_before_class_colon = ignore # ignore/add/remove/force + +# Add or remove space before case ':'. Default=Remove +sp_before_case_colon = remove # ignore/add/remove/force + +# Add or remove space between 'operator' and operator sign +sp_after_operator = ignore # ignore/add/remove/force + +# Add or remove space between the operator symbol and the open paren, as in 'operator ++(' +sp_after_operator_sym = ignore # ignore/add/remove/force + +# Add or remove space after C/D cast, i.e. 'cast(int)a' vs 'cast(int) a' or '(int)a' vs '(int) a' +sp_after_cast = ignore # ignore/add/remove/force + +# Add or remove spaces inside cast parens +sp_inside_paren_cast = ignore # ignore/add/remove/force + +# Add or remove space between the type and open paren in a C++ cast, i.e. 'int(exp)' vs 'int (exp)' +sp_cpp_cast_paren = ignore # ignore/add/remove/force + +# Add or remove space between 'sizeof' and '(' +sp_sizeof_paren = ignore # ignore/add/remove/force + +# Add or remove space after the tag keyword (Pawn) +sp_after_tag = ignore # ignore/add/remove/force + +# Add or remove space inside enum '{' and '}' +sp_inside_braces_enum = ignore # ignore/add/remove/force + +# Add or remove space inside struct/union '{' and '}' +sp_inside_braces_struct = ignore # ignore/add/remove/force + +# Add or remove space inside '{' and '}' +sp_inside_braces = ignore # ignore/add/remove/force + +# Add or remove space inside '{}' +sp_inside_braces_empty = ignore # ignore/add/remove/force + +# Add or remove space between return type and function name +# A minimum of 1 is forced except for pointer return types. +sp_type_func = add # ignore/add/remove/force + +# Add or remove space between function name and '(' on function declaration +sp_func_proto_paren = add # ignore/add/remove/force + +# Add or remove space between function name and '(' on function definition +sp_func_def_paren = add # ignore/add/remove/force + +# Add or remove space inside empty function '()' +sp_inside_fparens = remove # ignore/add/remove/force + +# Add or remove space inside function '(' and ')' +sp_inside_fparen = remove # ignore/add/remove/force + +# Add or remove space inside the first parens in the function type: 'void (*x)(...)' +sp_inside_tparen = ignore # ignore/add/remove/force + +# Add or remove between the parens in the function type: 'void (*x)(...)' +sp_after_tparen_close = ignore # ignore/add/remove/force + +# Add or remove space between ']' and '(' when part of a function call. +sp_square_fparen = ignore # ignore/add/remove/force + +# Add or remove space between ')' and '{' of function +sp_fparen_brace = add # ignore/add/remove/force + +# Add or remove space between function name and '(' on function calls +sp_func_call_paren = add # ignore/add/remove/force + +# Add or remove space between function name and '()' on function calls without parameters. +# If set to 'ignore' (the default), sp_func_call_paren is used. +sp_func_call_paren_empty = add # ignore/add/remove/force + +# Add or remove space between the user function name and '(' on function calls +# You need to set a keyword to be a user function, like this: 'set func_call_user _' in the config file. +sp_func_call_user_paren = ignore # ignore/add/remove/force + +# Add or remove space between a constructor/destructor and the open paren +sp_func_class_paren = add # ignore/add/remove/force + +# Add or remove space between 'return' and '(' +sp_return_paren = ignore # ignore/add/remove/force + +# Add or remove space between '__attribute__' and '(' +sp_attribute_paren = ignore # ignore/add/remove/force + +# Add or remove space between 'defined' and '(' in '#if defined (FOO)' +sp_defined_paren = ignore # ignore/add/remove/force + +# Add or remove space between 'throw' and '(' in 'throw (something)' +sp_throw_paren = ignore # ignore/add/remove/force + +# Add or remove space between 'throw' and anything other than '(' as in '@throw [...];' +sp_after_throw = ignore # ignore/add/remove/force + +# Add or remove space between 'catch' and '(' in 'catch (something) { }' +# If set to ignore, sp_before_sparen is used. +sp_catch_paren = ignore # ignore/add/remove/force + +# Add or remove space between 'version' and '(' in 'version (something) { }' (D language) +# If set to ignore, sp_before_sparen is used. +sp_version_paren = ignore # ignore/add/remove/force + +# Add or remove space between 'scope' and '(' in 'scope (something) { }' (D language) +# If set to ignore, sp_before_sparen is used. +sp_scope_paren = ignore # ignore/add/remove/force + +# Add or remove space between macro and value +sp_macro = ignore # ignore/add/remove/force + +# Add or remove space between macro function ')' and value +sp_macro_func = ignore # ignore/add/remove/force + +# Add or remove space between 'else' and '{' if on the same line +sp_else_brace = add # ignore/add/remove/force + +# Add or remove space between '}' and 'else' if on the same line +sp_brace_else = add # ignore/add/remove/force + +# Add or remove space between '}' and the name of a typedef on the same line +sp_brace_typedef = add # ignore/add/remove/force + +# Add or remove space between 'catch' and '{' if on the same line +sp_catch_brace = add # ignore/add/remove/force + +# Add or remove space between '}' and 'catch' if on the same line +sp_brace_catch = add # ignore/add/remove/force + +# Add or remove space between 'finally' and '{' if on the same line +sp_finally_brace = add # ignore/add/remove/force + +# Add or remove space between '}' and 'finally' if on the same line +sp_brace_finally = add # ignore/add/remove/force + +# Add or remove space between 'try' and '{' if on the same line +sp_try_brace = add # ignore/add/remove/force + +# Add or remove space between get/set and '{' if on the same line +sp_getset_brace = add # ignore/add/remove/force + +# Add or remove space before the '::' operator +sp_before_dc = ignore # ignore/add/remove/force + +# Add or remove space after the '::' operator +sp_after_dc = ignore # ignore/add/remove/force + +# Add or remove around the D named array initializer ':' operator +sp_d_array_colon = ignore # ignore/add/remove/force + +# Add or remove space after the '!' (not) operator. Default=Remove +sp_not = remove # ignore/add/remove/force + +# Add or remove space after the '~' (invert) operator. Default=Remove +sp_inv = remove # ignore/add/remove/force + +# Add or remove space after the '&' (address-of) operator. Default=Remove +# This does not affect the spacing after a '&' that is part of a type. +sp_addr = remove # ignore/add/remove/force + +# Add or remove space around the '.' or '->' operators. Default=Remove +sp_member = remove # ignore/add/remove/force + +# Add or remove space after the '*' (dereference) operator. Default=Remove +# This does not affect the spacing after a '*' that is part of a type. +sp_deref = remove # ignore/add/remove/force + +# Add or remove space after '+' or '-', as in 'x = -5' or 'y = +7'. Default=Remove +sp_sign = remove # ignore/add/remove/force + +# Add or remove space before or after '++' and '--', as in '(--x)' or 'y++;'. Default=Remove +sp_incdec = remove # ignore/add/remove/force + +# Add or remove space before a backslash-newline at the end of a line. Default=Add +sp_before_nl_cont = add # ignore/add/remove/force + +# Add or remove space after the scope '+' or '-', as in '-(void) foo;' or '+(int) bar;' +sp_after_oc_scope = ignore # ignore/add/remove/force + +# Add or remove space after the colon in message specs +# '-(int) f:(int) x;' vs '-(int) f: (int) x;' +sp_after_oc_colon = ignore # ignore/add/remove/force + +# Add or remove space before the colon in message specs +# '-(int) f: (int) x;' vs '-(int) f : (int) x;' +sp_before_oc_colon = ignore # ignore/add/remove/force + +# Add or remove space after the colon in immutable dictionary expression +# 'NSDictionary *test = @{@"foo" :@"bar"};' +sp_after_oc_dict_colon = ignore # ignore/add/remove/force + +# Add or remove space before the colon in immutable dictionary expression +# 'NSDictionary *test = @{@"foo" :@"bar"};' +sp_before_oc_dict_colon = ignore # ignore/add/remove/force + +# Add or remove space after the colon in message specs +# '[object setValue:1];' vs '[object setValue: 1];' +sp_after_send_oc_colon = ignore # ignore/add/remove/force + +# Add or remove space before the colon in message specs +# '[object setValue:1];' vs '[object setValue :1];' +sp_before_send_oc_colon = ignore # ignore/add/remove/force + +# Add or remove space after the (type) in message specs +# '-(int)f: (int) x;' vs '-(int)f: (int)x;' +sp_after_oc_type = ignore # ignore/add/remove/force + +# Add or remove space after the first (type) in message specs +# '-(int) f:(int)x;' vs '-(int)f:(int)x;' +sp_after_oc_return_type = ignore # ignore/add/remove/force + +# Add or remove space between '@selector' and '(' +# '@selector(msgName)' vs '@selector (msgName)' +# Also applies to @protocol() constructs +sp_after_oc_at_sel = ignore # ignore/add/remove/force + +# Add or remove space between '@selector(x)' and the following word +# '@selector(foo) a:' vs '@selector(foo)a:' +sp_after_oc_at_sel_parens = ignore # ignore/add/remove/force + +# Add or remove space inside '@selector' parens +# '@selector(foo)' vs '@selector( foo )' +# Also applies to @protocol() constructs +sp_inside_oc_at_sel_parens = ignore # ignore/add/remove/force + +# Add or remove space before a block pointer caret +# '^int (int arg){...}' vs. ' ^int (int arg){...}' +sp_before_oc_block_caret = ignore # ignore/add/remove/force + +# Add or remove space after a block pointer caret +# '^int (int arg){...}' vs. '^ int (int arg){...}' +sp_after_oc_block_caret = ignore # ignore/add/remove/force + +# Add or remove space between the receiver and selector in a message. +# '[receiver selector ...]' +sp_after_oc_msg_receiver = ignore # ignore/add/remove/force + +# Add or remove space after @property. +sp_after_oc_property = ignore # ignore/add/remove/force + +# Add or remove space around the ':' in 'b ? t : f' +sp_cond_colon = ignore # ignore/add/remove/force + +# Add or remove space around the '?' in 'b ? t : f' +sp_cond_question = ignore # ignore/add/remove/force + +# Fix the spacing between 'case' and the label. Only 'ignore' and 'force' make sense here. +sp_case_label = ignore # ignore/add/remove/force + +# Control the space around the D '..' operator. +sp_range = ignore # ignore/add/remove/force + +# Control the spacing after ':' in 'for (TYPE VAR : EXPR)' (Java) +sp_after_for_colon = ignore # ignore/add/remove/force + +# Control the spacing before ':' in 'for (TYPE VAR : EXPR)' (Java) +sp_before_for_colon = ignore # ignore/add/remove/force + +# Control the spacing in 'extern (C)' (D) +sp_extern_paren = ignore # ignore/add/remove/force + +# Control the space after the opening of a C++ comment '// A' vs '//A' +sp_cmt_cpp_start = ignore # ignore/add/remove/force + +# Controls the spaces between #else or #endif and a trailing comment +sp_endif_cmt = ignore # ignore/add/remove/force + +# Controls the spaces after 'new', 'delete', and 'delete[]' +sp_after_new = ignore # ignore/add/remove/force + +# Controls the spaces before a trailing or embedded comment +sp_before_tr_emb_cmt = ignore # ignore/add/remove/force + +# Number of spaces before a trailing or embedded comment +sp_num_before_tr_emb_cmt = 0 # number + +# Control space between a Java annotation and the open paren. +sp_annotation_paren = ignore # ignore/add/remove/force + +# +# Code alignment (not left column spaces/tabs) +# + +# Whether to keep non-indenting tabs +align_keep_tabs = false # false/true + +# Whether to use tabs for aligning +align_with_tabs = false # false/true + +# Whether to bump out to the next tab when aligning +align_on_tabstop = false # false/true + +# Whether to left-align numbers +align_number_left = false # false/true + +# Align variable definitions in prototypes and functions +align_func_params = false # false/true + +# Align parameters in single-line functions that have the same name. +# The function names must already be aligned with each other. +align_same_func_call_params = false # false/true + +# The span for aligning variable definitions (0=don't align) +align_var_def_span = 0 # number + +# How to align the star in variable definitions. +# 0=Part of the type 'void * foo;' +# 1=Part of the variable 'void *foo;' +# 2=Dangling 'void *foo;' +align_var_def_star_style = 1 # number + +# How to align the '&' in variable definitions. +# 0=Part of the type +# 1=Part of the variable +# 2=Dangling +align_var_def_amp_style = 1 # number + +# The threshold for aligning variable definitions (0=no limit) +align_var_def_thresh = 0 # number + +# The gap for aligning variable definitions +align_var_def_gap = 0 # number + +# Whether to align the colon in struct bit fields +align_var_def_colon = false # false/true + +# Whether to align any attribute after the variable name +align_var_def_attribute = false # false/true + +# Whether to align inline struct/enum/union variable definitions +align_var_def_inline = false # false/true + +# The span for aligning on '=' in assignments (0=don't align) +align_assign_span = 0 # number + +# The threshold for aligning on '=' in assignments (0=no limit) +align_assign_thresh = 10 # number + +# The span for aligning on '=' in enums (0=don't align) +align_enum_equ_span = 0 # number + +# The threshold for aligning on '=' in enums (0=no limit) +align_enum_equ_thresh = 0 # number + +# The span for aligning struct/union (0=don't align) +align_var_struct_span = 0 # number + +# The threshold for aligning struct/union member definitions (0=no limit) +align_var_struct_thresh = 0 # number + +# The gap for aligning struct/union member definitions +align_var_struct_gap = 0 # number + +# The span for aligning struct initializer values (0=don't align) +align_struct_init_span = 0 # number + +# The minimum space between the type and the synonym of a typedef +align_typedef_gap = 0 # number + +# The span for aligning single-line typedefs (0=don't align) +align_typedef_span = 0 # number + +# How to align typedef'd functions with other typedefs +# 0: Don't mix them at all +# 1: align the open paren with the types +# 2: align the function type name with the other type names +align_typedef_func = 0 # number + +# Controls the positioning of the '*' in typedefs. Just try it. +# 0: Align on typedef type, ignore '*' +# 1: The '*' is part of type name: typedef int *pint; +# 2: The '*' is part of the type, but dangling: typedef int *pint; +align_typedef_star_style = 0 # number + +# Controls the positioning of the '&' in typedefs. Just try it. +# 0: Align on typedef type, ignore '&' +# 1: The '&' is part of type name: typedef int &pint; +# 2: The '&' is part of the type, but dangling: typedef int &pint; +align_typedef_amp_style = 0 # number + +# The span for aligning comments that end lines (0=don't align) +align_right_cmt_span = 0 # number + +# If aligning comments, mix with comments after '}' and #endif with less than 3 spaces before the comment +align_right_cmt_mix = false # false/true + +# If a trailing comment is more than this number of columns away from the text it follows, +# it will qualify for being aligned. This has to be > 0 to do anything. +align_right_cmt_gap = 0 # number + +# Align trailing comment at or beyond column N; 'pulls in' comments as a bonus side effect (0=ignore) +align_right_cmt_at_col = 0 # number + +# The span for aligning function prototypes (0=don't align) +align_func_proto_span = 0 # number + +# Minimum gap between the return type and the function name. +align_func_proto_gap = 0 # number + +# Align function protos on the 'operator' keyword instead of what follows +align_on_operator = false # false/true + +# Whether to mix aligning prototype and variable declarations. +# If true, align_var_def_XXX options are used instead of align_func_proto_XXX options. +align_mix_var_proto = false # false/true + +# Align single-line functions with function prototypes, uses align_func_proto_span +align_single_line_func = false # false/true + +# Aligning the open brace of single-line functions. +# Requires align_single_line_func=true, uses align_func_proto_span +align_single_line_brace = false # false/true + +# Gap for align_single_line_brace. +align_single_line_brace_gap = 0 # number + +# The span for aligning ObjC msg spec (0=don't align) +align_oc_msg_spec_span = 0 # number + +# Whether to align macros wrapped with a backslash and a newline. +# This will not work right if the macro contains a multi-line comment. +align_nl_cont = false # false/true + +# # Align macro functions and variables together +align_pp_define_together = false # false/true + +# The minimum space between label and value of a preprocessor define +align_pp_define_gap = 0 # number + +# The span for aligning on '#define' bodies (0=don't align) +align_pp_define_span = 0 # number + +# Align lines that start with '<<' with previous '<<'. Default=true +align_left_shift = true # false/true + +# Span for aligning parameters in an Obj-C message call on the ':' (0=don't align) +align_oc_msg_colon_span = 0 # number + +# If true, always align with the first parameter, even if it is too short. +align_oc_msg_colon_first = false # false/true + +# Aligning parameters in an Obj-C '+' or '-' declaration on the ':' +align_oc_decl_colon = false # false/true + +# +# Newline adding and removing options +# + +# Whether to collapse empty blocks between '{' and '}' +nl_collapse_empty_body = false # false/true + +# Don't split one-line braced assignments - 'foo_t f = { 1, 2 };' +nl_assign_leave_one_liners = false # false/true + +# Don't split one-line braced statements inside a class xx { } body +nl_class_leave_one_liners = false # false/true + +# Don't split one-line enums: 'enum foo { BAR = 15 };' +nl_enum_leave_one_liners = false # false/true + +# Don't split one-line get or set functions +nl_getset_leave_one_liners = false # false/true + +# Don't split one-line function definitions - 'int foo() { return 0; }' +nl_func_leave_one_liners = false # false/true + +# Don't split one-line if/else statements - 'if(a) b++;' +nl_if_leave_one_liners = false # false/true + +# Don't split one-line OC messages +nl_oc_msg_leave_one_liner = false # false/true + +# Add or remove newlines at the start of the file +nl_start_of_file = ignore # ignore/add/remove/force + +# The number of newlines at the start of the file (only used if nl_start_of_file is 'add' or 'force' +nl_start_of_file_min = 0 # number + +# Add or remove newline at the end of the file +nl_end_of_file = ignore # ignore/add/remove/force + +# The number of newlines at the end of the file (only used if nl_end_of_file is 'add' or 'force') +nl_end_of_file_min = 0 # number + +# Add or remove newline between '=' and '{' +nl_assign_brace = ignore # ignore/add/remove/force + +# Add or remove newline between '=' and '[' (D only) +nl_assign_square = ignore # ignore/add/remove/force + +# Add or remove newline after '= [' (D only). Will also affect the newline before the ']' +nl_after_square_assign = ignore # ignore/add/remove/force + +# The number of blank lines after a block of variable definitions at the top of a function body +# 0 = No change (default) +nl_func_var_def_blk = 0 # number + +# The number of newlines before a block of typedefs +# 0 = No change (default) +nl_typedef_blk_start = 0 # number + +# The number of newlines after a block of typedefs +# 0 = No change (default) +nl_typedef_blk_end = 0 # number + +# The maximum consecutive newlines within a block of typedefs +# 0 = No change (default) +nl_typedef_blk_in = 0 # number + +# The number of newlines before a block of variable definitions not at the top of a function body +# 0 = No change (default) +nl_var_def_blk_start = 0 # number + +# The number of newlines after a block of variable definitions not at the top of a function body +# 0 = No change (default) +nl_var_def_blk_end = 0 # number + +# The maximum consecutive newlines within a block of variable definitions +# 0 = No change (default) +nl_var_def_blk_in = 0 # number + +# Add or remove newline between a function call's ')' and '{', as in: +# list_for_each(item, &list) { } +nl_fcall_brace = remove # ignore/add/remove/force + +# Add or remove newline between 'enum' and '{' +nl_enum_brace = remove # ignore/add/remove/force + +# Add or remove newline between 'struct and '{' +nl_struct_brace = remove # ignore/add/remove/force + +# Add or remove newline between 'union' and '{' +nl_union_brace = remove # ignore/add/remove/force + +# Add or remove newline between 'if' and '{' +nl_if_brace = remove # ignore/add/remove/force + +# Add or remove newline between '}' and 'else' +nl_brace_else = add # ignore/add/remove/force + +# Add or remove newline between 'else if' and '{' +# If set to ignore, nl_if_brace is used instead +nl_elseif_brace = remove # ignore/add/remove/force + +# Add or remove newline between 'else' and '{' +nl_else_brace = remove # ignore/add/remove/force + +# Add or remove newline between 'else' and 'if' +nl_else_if = remove # ignore/add/remove/force + +# Add or remove newline between '}' and 'finally' +nl_brace_finally = ignore # ignore/add/remove/force + +# Add or remove newline between 'finally' and '{' +nl_finally_brace = remove # ignore/add/remove/force + +# Add or remove newline between 'try' and '{' +nl_try_brace = remove # ignore/add/remove/force + +# Add or remove newline between get/set and '{' +nl_getset_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'for' and '{' +nl_for_brace = remove # ignore/add/remove/force + +# Add or remove newline between 'catch' and '{' +nl_catch_brace = remove # ignore/add/remove/force + +# Add or remove newline between '}' and 'catch' +nl_brace_catch = ignore # ignore/add/remove/force + +# Add or remove newline between 'while' and '{' +nl_while_brace = remove # ignore/add/remove/force + +# Add or remove newline between 'scope (x)' and '{' (D) +nl_scope_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'unittest' and '{' (D) +nl_unittest_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'version (x)' and '{' (D) +nl_version_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'using' and '{' +nl_using_brace = ignore # ignore/add/remove/force + +# Add or remove newline between two open or close braces. +# Due to general newline/brace handling, REMOVE may not work. +nl_brace_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'do' and '{' +nl_do_brace = remove # ignore/add/remove/force + +# Add or remove newline between '}' and 'while' of 'do' statement +nl_brace_while = add # ignore/add/remove/force + +# Add or remove newline between 'switch' and '{' +nl_switch_brace = remove # ignore/add/remove/force + +# Add a newline between ')' and '{' if the ')' is on a different line than the if/for/etc. +# Overrides nl_for_brace, nl_if_brace, nl_switch_brace, nl_while_switch, and nl_catch_brace. +nl_multi_line_cond = false # false/true + +# Force a newline in a define after the macro name for multi-line defines. +nl_multi_line_define = false # false/true + +# Whether to put a newline before 'case' statement +nl_before_case = false # false/true + +# Add or remove newline between ')' and 'throw' +nl_before_throw = ignore # ignore/add/remove/force + +# Whether to put a newline after 'case' statement +nl_after_case = false # false/true + +# Add or remove a newline between a case ':' and '{'. Overrides nl_after_case. +nl_case_colon_brace = ignore # ignore/add/remove/force + +# Newline between namespace and { +nl_namespace_brace = remove # ignore/add/remove/force + +# Add or remove newline between 'template<>' and whatever follows. +nl_template_class = ignore # ignore/add/remove/force + +# Add or remove newline between 'class' and '{' +nl_class_brace = remove # ignore/add/remove/force + +# Add or remove newline after each ',' in the constructor member initialization +nl_class_init_args = ignore # ignore/add/remove/force + +# Add or remove newline between return type and function name in a function definition +nl_func_type_name = ignore # ignore/add/remove/force + +# Add or remove newline between return type and function name inside a class {} +# Uses nl_func_type_name or nl_func_proto_type_name if set to ignore. +nl_func_type_name_class = ignore # ignore/add/remove/force + +# Add or remove newline between function scope and name in a definition +# Controls the newline after '::' in 'void A::f() { }' +nl_func_scope_name = ignore # ignore/add/remove/force + +# Add or remove newline between return type and function name in a prototype +nl_func_proto_type_name = ignore # ignore/add/remove/force + +# Add or remove newline between a function name and the opening '(' +nl_func_paren = ignore # ignore/add/remove/force + +# Add or remove newline between a function name and the opening '(' in the definition +nl_func_def_paren = ignore # ignore/add/remove/force + +# Add or remove newline after '(' in a function declaration +nl_func_decl_start = ignore # ignore/add/remove/force + +# Add or remove newline after '(' in a function definition +nl_func_def_start = ignore # ignore/add/remove/force + +# Overrides nl_func_decl_start when there is only one parameter. +nl_func_decl_start_single = ignore # ignore/add/remove/force + +# Overrides nl_func_def_start when there is only one parameter. +nl_func_def_start_single = ignore # ignore/add/remove/force + +# Add or remove newline after each ',' in a function declaration +nl_func_decl_args = ignore # ignore/add/remove/force + +# Add or remove newline after each ',' in a function definition +nl_func_def_args = ignore # ignore/add/remove/force + +# Add or remove newline before the ')' in a function declaration +nl_func_decl_end = ignore # ignore/add/remove/force + +# Add or remove newline before the ')' in a function definition +nl_func_def_end = ignore # ignore/add/remove/force + +# Overrides nl_func_decl_end when there is only one parameter. +nl_func_decl_end_single = ignore # ignore/add/remove/force + +# Overrides nl_func_def_end when there is only one parameter. +nl_func_def_end_single = ignore # ignore/add/remove/force + +# Add or remove newline between '()' in a function declaration. +nl_func_decl_empty = ignore # ignore/add/remove/force + +# Add or remove newline between '()' in a function definition. +nl_func_def_empty = ignore # ignore/add/remove/force + +# Whether to put each OC message parameter on a separate line +# See nl_oc_msg_leave_one_liner +nl_oc_msg_args = false # false/true + +# Add or remove newline between function signature and '{' +nl_fdef_brace = remove # ignore/add/remove/force + +# Add or remove a newline between the return keyword and return expression. +nl_return_expr = ignore # ignore/add/remove/force + +# Whether to put a newline after semicolons, except in 'for' statements +nl_after_semicolon = false # false/true + +# Whether to put a newline after brace open. +# This also adds a newline before the matching brace close. +nl_after_brace_open = false # false/true + +# If nl_after_brace_open and nl_after_brace_open_cmt are true, a newline is +# placed between the open brace and a trailing single-line comment. +nl_after_brace_open_cmt = false # false/true + +# Whether to put a newline after a virtual brace open with a non-empty body. +# These occur in un-braced if/while/do/for statement bodies. +nl_after_vbrace_open = false # false/true + +# Whether to put a newline after a virtual brace open with an empty body. +# These occur in un-braced if/while/do/for statement bodies. +nl_after_vbrace_open_empty = false # false/true + +# Whether to put a newline after a brace close. +# Does not apply if followed by a necessary ';'. +nl_after_brace_close = false # false/true + +# Whether to put a newline after a virtual brace close. +# Would add a newline before return in: 'if (foo) a++; return;' +nl_after_vbrace_close = false # false/true + +# Control the newline between the close brace and 'b' in: 'struct { int a; } b;' +# Affects enums, unions, and structures. If set to ignore, uses nl_after_brace_close +nl_brace_struct_var = ignore # ignore/add/remove/force + +# Whether to alter newlines in '#define' macros +nl_define_macro = false # false/true + +# Whether to not put blanks after '#ifxx', '#elxx', or before '#endif' +nl_squeeze_ifdef = false # false/true + +# Add or remove blank line before 'if' +nl_before_if = ignore # ignore/add/remove/force + +# Add or remove blank line after 'if' statement +nl_after_if = ignore # ignore/add/remove/force + +# Add or remove blank line before 'for' +nl_before_for = ignore # ignore/add/remove/force + +# Add or remove blank line after 'for' statement +nl_after_for = ignore # ignore/add/remove/force + +# Add or remove blank line before 'while' +nl_before_while = ignore # ignore/add/remove/force + +# Add or remove blank line after 'while' statement +nl_after_while = ignore # ignore/add/remove/force + +# Add or remove blank line before 'switch' +nl_before_switch = ignore # ignore/add/remove/force + +# Add or remove blank line after 'switch' statement +nl_after_switch = ignore # ignore/add/remove/force + +# Add or remove blank line before 'do' +nl_before_do = ignore # ignore/add/remove/force + +# Add or remove blank line after 'do/while' statement +nl_after_do = ignore # ignore/add/remove/force + +# Whether to double-space commented-entries in struct/enum +nl_ds_struct_enum_cmt = false # false/true + +# Whether to double-space before the close brace of a struct/union/enum +# (lower priority than 'eat_blanks_before_close_brace') +nl_ds_struct_enum_close_brace = false # false/true + +# Add or remove a newline around a class colon. +# Related to pos_class_colon, nl_class_init_args, and pos_comma. +nl_class_colon = ignore # ignore/add/remove/force + +# Change simple unbraced if statements into a one-liner +# 'if(b)\n i++;' => 'if(b) i++;' +nl_create_if_one_liner = false # false/true + +# Change simple unbraced for statements into a one-liner +# 'for (i=0;i<5;i++)\n foo(i);' => 'for (i=0;i<5;i++) foo(i);' +nl_create_for_one_liner = false # false/true + +# Change simple unbraced while statements into a one-liner +# 'while (i<5)\n foo(i++);' => 'while (i<5) foo(i++);' +nl_create_while_one_liner = false # false/true + +# +# Positioning options +# + +# The position of arithmetic operators in wrapped expressions +pos_arith = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of assignment in wrapped expressions. +# Do not affect '=' followed by '{' +pos_assign = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of boolean operators in wrapped expressions +pos_bool = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of comparison operators in wrapped expressions +pos_compare = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of conditional (b ? t : f) operators in wrapped expressions +pos_conditional = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of the comma in wrapped expressions +pos_comma = trail # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of the comma in the constructor initialization list +pos_class_comma = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of colons between constructor and member initialization +pos_class_colon = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# +# Line Splitting options +# + +# Try to limit code width to N number of columns +code_width = 0 # number + +# Whether to fully split long 'for' statements at semi-colons +ls_for_split_full = false # false/true + +# Whether to fully split long function protos/calls at commas +ls_func_split_full = false # false/true + +# Whether to split lines as close to code_width as possible and ignore some groupings +ls_code_width = false # false/true + +# +# Blank line options +# + +# The maximum consecutive newlines +nl_max = 0 # number + +# The number of newlines after a function prototype, if followed by another function prototype +nl_after_func_proto = 0 # number + +# The number of newlines after a function prototype, if not followed by another function prototype +nl_after_func_proto_group = 0 # number + +# The number of newlines after '}' of a multi-line function body +nl_after_func_body = 0 # number + +# The number of newlines after '}' of a multi-line function body in a class declaration +nl_after_func_body_class = 0 # number + +# The number of newlines after '}' of a single line function body +nl_after_func_body_one_liner = 0 # number + +# The minimum number of newlines before a multi-line comment. +# Doesn't apply if after a brace open or another multi-line comment. +nl_before_block_comment = 0 # number + +# The minimum number of newlines before a single-line C comment. +# Doesn't apply if after a brace open or other single-line C comments. +nl_before_c_comment = 0 # number + +# The minimum number of newlines before a CPP comment. +# Doesn't apply if after a brace open or other CPP comments. +nl_before_cpp_comment = 0 # number + +# Whether to force a newline after a multi-line comment. +nl_after_multiline_comment = false # false/true + +# The number of newlines after '}' or ';' of a struct/enum/union definition +nl_after_struct = 0 # number + +# The number of newlines after '}' or ';' of a class definition +nl_after_class = 0 # number + +# The number of newlines before a 'private:', 'public:', 'protected:', 'signals:', or 'slots:' label. +# Will not change the newline count if after a brace open. +# 0 = No change. +nl_before_access_spec = 2 # number + +# The number of newlines after a 'private:', 'public:', 'protected:', 'signals:', or 'slots:' label. +# 0 = No change. +nl_after_access_spec = 0 # number + +# The number of newlines between a function def and the function comment. +# 0 = No change. +nl_comment_func_def = 0 # number + +# The number of newlines after a try-catch-finally block that isn't followed by a brace close. +# 0 = No change. +nl_after_try_catch_finally = 0 # number + +# The number of newlines before and after a property, indexer or event decl. +# 0 = No change. +nl_around_cs_property = 0 # number + +# The number of newlines between the get/set/add/remove handlers in C#. +# 0 = No change. +nl_between_get_set = 0 # number + +# Add or remove newline between C# property and the '{' +nl_property_brace = ignore # ignore/add/remove/force + +# Whether to remove blank lines after '{' +eat_blanks_after_open_brace = false # false/true + +# Whether to remove blank lines before '}' +eat_blanks_before_close_brace = false # false/true + +# How aggressively to remove extra newlines not in preproc. +# 0: No change +# 1: Remove most newlines not handled by other config +# 2: Remove all newlines and reformat completely by config +nl_remove_extra_newlines = 0 # number + +# Whether to put a blank line before 'return' statements, unless after an open brace. +nl_before_return = false # false/true + +# Whether to put a blank line after 'return' statements, unless followed by a close brace. +nl_after_return = false # false/true + +# Whether to put a newline after a Java annotation statement. +# Only affects annotations that are after a newline. +nl_after_annotation = ignore # ignore/add/remove/force + +# Controls the newline between two annotations. +nl_between_annotation = ignore # ignore/add/remove/force + +# +# Code modifying options (non-whitespace) +# + +# Add or remove braces on single-line 'do' statement +mod_full_brace_do = ignore # ignore/add/remove/force + +# Add or remove braces on single-line 'for' statement +mod_full_brace_for = add # ignore/add/remove/force + +# Add or remove braces on single-line function definitions. (Pawn) +mod_full_brace_function = add # ignore/add/remove/force + +# Add or remove braces on single-line 'if' statement. Will not remove the braces if they contain an 'else'. +mod_full_brace_if = add # ignore/add/remove/force + +# Make all if/elseif/else statements in a chain be braced or not. Overrides mod_full_brace_if. +# If any must be braced, they are all braced. If all can be unbraced, then the braces are removed. +mod_full_brace_if_chain = false # false/true + +# Don't remove braces around statements that span N newlines +mod_full_brace_nl = 0 # number + +# Add or remove braces on single-line 'while' statement +mod_full_brace_while = add # ignore/add/remove/force + +# Add or remove braces on single-line 'using ()' statement +mod_full_brace_using = ignore # ignore/add/remove/force + +# Add or remove unnecessary paren on 'return' statement +mod_paren_on_return = ignore # ignore/add/remove/force + +# Whether to change optional semicolons to real semicolons +mod_pawn_semicolon = false # false/true + +# Add parens on 'while' and 'if' statement around bools +mod_full_paren_if_bool = false # false/true + +# Whether to remove superfluous semicolons +mod_remove_extra_semicolon = false # false/true + +# If a function body exceeds the specified number of newlines and doesn't have a comment after +# the close brace, a comment will be added. +mod_add_long_function_closebrace_comment = 0 # number + +# If a switch body exceeds the specified number of newlines and doesn't have a comment after +# the close brace, a comment will be added. +mod_add_long_switch_closebrace_comment = 0 # number + +# If an #ifdef body exceeds the specified number of newlines and doesn't have a comment after +# the #endif, a comment will be added. +mod_add_long_ifdef_endif_comment = 0 # number + +# If an #ifdef or #else body exceeds the specified number of newlines and doesn't have a comment after +# the #else, a comment will be added. +mod_add_long_ifdef_else_comment = 0 # number + +# If TRUE, will sort consecutive single-line 'import' statements [Java, D] +mod_sort_import = false # false/true + +# If TRUE, will sort consecutive single-line 'using' statements [C#] +mod_sort_using = false # false/true + +# If TRUE, will sort consecutive single-line '#include' statements [C/C++] and '#import' statements [Obj-C] +# This is generally a bad idea, as it may break your code. +mod_sort_include = false # false/true + +# If TRUE, it will move a 'break' that appears after a fully braced 'case' before the close brace. +mod_move_case_break = false # false/true + +# Will add or remove the braces around a fully braced case statement. +# Will only remove the braces if there are no variable declarations in the block. +mod_case_brace = ignore # ignore/add/remove/force + +# If TRUE, it will remove a void 'return;' that appears as the last statement in a function. +mod_remove_empty_return = false # false/true + +# +# Comment modifications +# + +# Try to wrap comments at cmt_width columns +cmt_width = 0 # number + +# Set the comment reflow mode (default: 0) +# 0: no reflowing (apart from the line wrapping due to cmt_width) +# 1: no touching at all +# 2: full reflow +cmt_reflow_mode = 0 # number + +# If false, disable all multi-line comment changes, including cmt_width. keyword substitution, and leading chars. +# Default is true. +cmt_indent_multi = true # false/true + +# Whether to group c-comments that look like they are in a block +cmt_c_group = false # false/true + +# Whether to put an empty '/*' on the first line of the combined c-comment +cmt_c_nl_start = false # false/true + +# Whether to put a newline before the closing '*/' of the combined c-comment +cmt_c_nl_end = false # false/true + +# Whether to group cpp-comments that look like they are in a block +cmt_cpp_group = false # false/true + +# Whether to put an empty '/*' on the first line of the combined cpp-comment +cmt_cpp_nl_start = false # false/true + +# Whether to put a newline before the closing '*/' of the combined cpp-comment +cmt_cpp_nl_end = false # false/true + +# Whether to change cpp-comments into c-comments +cmt_cpp_to_c = false # false/true + +# Whether to put a star on subsequent comment lines +cmt_star_cont = false # false/true + +# The number of spaces to insert at the start of subsequent comment lines +cmt_sp_before_star_cont = 0 # number + +# The number of spaces to insert after the star on subsequent comment lines +cmt_sp_after_star_cont = 0 # number + +# For multi-line comments with a '*' lead, remove leading spaces if the first and last lines of +# the comment are the same length. Default=True +cmt_multi_check_last = true # false/true + +# The filename that contains text to insert at the head of a file if the file doesn't start with a C/C++ comment. +# Will substitute $(filename) with the current file's name. +cmt_insert_file_header = "" # string + +# The filename that contains text to insert at the end of a file if the file doesn't end with a C/C++ comment. +# Will substitute $(filename) with the current file's name. +cmt_insert_file_footer = "" # string + +# The filename that contains text to insert before a function implementation if the function isn't preceded with a C/C++ comment. +# Will substitute $(function) with the function name and $(javaparam) with the javadoc @param and @return stuff. +# Will also substitute $(fclass) with the class name: void CFoo::Bar() { ... } +cmt_insert_func_header = "" # string + +# The filename that contains text to insert before a class if the class isn't preceded with a C/C++ comment. +# Will substitute $(class) with the class name. +cmt_insert_class_header = "" # string + +# The filename that contains text to insert before a Obj-C message specification if the method isn't preceeded with a C/C++ comment. +# Will substitute $(message) with the function name and $(javaparam) with the javadoc @param and @return stuff. +cmt_insert_oc_msg_header = "" # string + +# If a preprocessor is encountered when stepping backwards from a function name, then +# this option decides whether the comment should be inserted. +# Affects cmt_insert_oc_msg_header, cmt_insert_func_header and cmt_insert_class_header. +cmt_insert_before_preproc = false # false/true + +# +# Preprocessor options +# + +# Control indent of preprocessors inside #if blocks at brace level 0 +pp_indent = remove # ignore/add/remove/force + +# Whether to indent #if/#else/#endif at the brace level (true) or from column 1 (false) +pp_indent_at_level = false # false/true + +# If pp_indent_at_level=false, specifies the number of columns to indent per level. Default=1. +pp_indent_count = 0 # number + +# Add or remove space after # based on pp_level of #if blocks +pp_space = add # ignore/add/remove/force + +# Sets the number of spaces added with pp_space +pp_space_count = 2 # number + +# The indent for #region and #endregion in C# and '#pragma region' in C/C++ +pp_indent_region = 0 # number + +# Whether to indent the code between #region and #endregion +pp_region_indent_code = false # false/true + +# If pp_indent_at_level=true, sets the indent for #if, #else, and #endif when not at file-level +pp_indent_if = 0 # number + +# Control whether to indent the code between #if, #else and #endif when not at file-level +pp_if_indent_code = false # false/true + +# Whether to indent '#define' at the brace level (true) or from column 1 (false) +pp_define_at_level = false # false/true + +# You can force a token to be a type with the 'type' option. +# Example: +# type myfoo1 myfoo2 +# +# You can create custom macro-based indentation using macro-open, +# macro-else and macro-close. +# Example: +# macro-open BEGIN_TEMPLATE_MESSAGE_MAP +# macro-open BEGIN_MESSAGE_MAP +# macro-close END_MESSAGE_MAP +# +# You can assign any keyword to any type with the set option. +# set func_call_user _ N_ +# +# The full syntax description of all custom definition config entries +# is shown below: +# +# define custom tokens as: +# - embed whitespace in token using '' escape character, or +# put token in quotes +# - these: ' " and ` are recognized as quote delimiters +# +# type token1 token2 token3 ... +# ^ optionally specify multiple tokens on a single line +# define def_token output_token +# ^ output_token is optional, then NULL is assumed +# macro-open token +# macro-close token +# macro-else token +# set id token1 token2 ... +# ^ optionally specify multiple tokens on a single line +# ^ id is one of the names in token_enum.h sans the CT_ prefix, +# e.g. PP_PRAGMA +# +# all tokens are separated by any mix of ',' commas, '=' equal signs +# and whitespace (space, tab) +# diff --git a/version.json b/version.json new file mode 100644 index 0000000..d57f8cf --- /dev/null +++ b/version.json @@ -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" + } +}