From 0069bb0b95e4386c7fe71906abb88498668b3e9e Mon Sep 17 00:00:00 2001 From: Syping <schiedelrafael@keppe.org> Date: Mon, 9 Oct 2017 08:35:48 +0200 Subject: [PATCH] latest changes from gta5sync --- .gitattributes | 27 + .travis.yml | 27 +- AboutDialog.cpp | 246 ++--- AboutDialog.h | 88 +- AboutDialog.ui | 204 ++-- AppEnv.cpp | 333 +++--- AppEnv.h | 92 +- CrewDatabase.cpp | 248 +++-- CrewDatabase.h | 96 +- DatabaseThread.cpp | 572 +++++----- DatabaseThread.h | 106 +- ExportDialog.cpp | 96 +- ExportDialog.h | 92 +- ExportDialog.ui | 452 ++++---- ExportThread.cpp | 369 +++---- ExportThread.h | 112 +- GlobalString.cpp | 174 ++- GlobalString.h | 70 +- IconLoader.cpp | 90 +- IconLoader.h | 63 +- ImportDialog.cpp | 409 +++---- ImportDialog.h | 122 +-- ImportDialog.ui | 426 ++++---- MapPreviewDialog.cpp | 76 ++ MapPreviewDialog.h | 41 + MapPreviewDialog.ui | 71 ++ OptionsDialog.cpp | 896 ++++++++-------- OptionsDialog.h | 158 +-- OptionsDialog.ui | 1012 +++++++++--------- PictureDialog.cpp | 1433 +++++++++++++------------ PictureDialog.h | 256 ++--- PictureDialog.ui | 508 ++++----- PictureExport.cpp | 622 +++++------ PictureExport.h | 70 +- ProfileDatabase.cpp | 137 +-- ProfileDatabase.h | 88 +- ProfileInterface.cpp | 344 +++++- ProfileInterface.h | 241 +++-- ProfileInterface.ui | 488 ++++----- ProfileLoader.cpp | 209 ++-- ProfileLoader.h | 104 +- ProfileWidget.cpp | 127 +-- ProfileWidget.h | 91 +- SavegameCopy.cpp | 200 ++-- SavegameCopy.h | 64 +- SavegameData.cpp | 239 ++--- SavegameData.h | 90 +- SavegameDialog.cpp | 106 +- SavegameDialog.h | 58 +- SavegameDialog.ui | 179 ++-- SavegameWidget.cpp | 525 ++++----- SavegameWidget.h | 162 ++- SavegameWidget.ui | 270 ++--- SidebarGenerator.cpp | 122 +-- SidebarGenerator.h | 64 +- SnapmaticEditor.cpp | 680 ++++++------ SnapmaticEditor.h | 138 +-- SnapmaticEditor.ui | 496 ++++----- SnapmaticPicture.cpp | 2050 +++++++++++++++++++----------------- SnapmaticPicture.h | 308 +++--- SnapmaticWidget.cpp | 676 ++++++------ SnapmaticWidget.h | 202 ++-- SnapmaticWidget.ui | 338 +++--- StandardPaths.cpp | 256 ++--- StandardPaths.h | 82 +- StringParser.cpp | 156 +-- StringParser.h | 76 +- TranslationClass.cpp | 543 ++++++++++ TranslationClass.h | 63 ++ UserInterface.cpp | 1081 +++++++++---------- UserInterface.h | 189 ++-- UserInterface.ui | 702 ++++++------ config.h | 262 +++-- gta5view.pro | 368 ++++--- lang/gta5sync_no.qm | Bin 0 -> 23 bytes lang/gta5sync_no.ts | 1619 ++++++++++++++++++++++++++++ main.cpp | 696 ++++-------- qjson4/QJsonArray | 2 +- qjson4/QJsonArray.cpp | 820 +++++++-------- qjson4/QJsonArray.h | 278 ++--- qjson4/QJsonDocument | 2 +- qjson4/QJsonDocument.cpp | 834 +++++++-------- qjson4/QJsonDocument.h | 206 ++-- qjson4/QJsonObject | 2 +- qjson4/QJsonObject.cpp | 644 +++++------ qjson4/QJsonObject.h | 242 ++--- qjson4/QJsonParseError | 2 +- qjson4/QJsonParseError.cpp | 128 +-- qjson4/QJsonParseError.h | 120 +-- qjson4/QJsonParser.cpp | 910 ++++++++-------- qjson4/QJsonParser.h | 162 +-- qjson4/QJsonRoot | 2 +- qjson4/QJsonRoot.h | 90 +- qjson4/QJsonValue | 2 +- qjson4/QJsonValue.cpp | 782 +++++++------- qjson4/QJsonValue.h | 240 ++--- qjson4/QJsonValueRef | 2 +- qjson4/QJsonValueRef.cpp | 456 ++++---- qjson4/QJsonValueRef.h | 158 +-- res/960x536.png | Bin 48000 -> 19532 bytes res/app.qrc | 5 + res/app.rc | 72 +- res/global.de.ini | 204 ++-- res/global.en.ini | 206 ++-- res/global.es.ini | 214 ++-- res/global.fr.ini | 206 ++-- res/global.ja.ini | 212 ++-- res/global.zh.ini | 208 ++-- res/gta5sync_de.qm | Bin 30448 -> 32293 bytes res/gta5sync_de.ts | 876 +++++++++------ res/gta5sync_en_US.qm | Bin 0 -> 18703 bytes res/gta5sync_en_US.ts | 1619 ++++++++++++++++++++++++++++ res/gta5sync_fr.qm | Bin 29475 -> 27241 bytes res/gta5sync_fr.ts | 834 +++++++++------ res/gta5sync_ru.qm | Bin 29918 -> 27502 bytes res/gta5sync_ru.ts | 842 +++++++++------ res/mappreview.jpg | Bin 0 -> 207939 bytes res/pointmaker-16.png | Bin 0 -> 352 bytes res/pointmaker-24.png | Bin 0 -> 444 bytes res/pointmaker-32.png | Bin 0 -> 611 bytes res/pointmaker-8.png | Bin 0 -> 244 bytes res/qtbase_en_GB.qm | Bin 0 -> 941 bytes res/tr_g5p.qrc | 1 + res/tr_qt5.qrc | 1 + uimod/UiModLabel.cpp | 150 +-- uimod/UiModLabel.h | 106 +- uimod/UiModWidget.cpp | 152 +-- uimod/UiModWidget.h | 94 +- 128 files changed, 20971 insertions(+), 15661 deletions(-) create mode 100644 .gitattributes create mode 100644 MapPreviewDialog.cpp create mode 100644 MapPreviewDialog.h create mode 100644 MapPreviewDialog.ui create mode 100644 TranslationClass.cpp create mode 100644 TranslationClass.h create mode 100644 lang/gta5sync_no.qm create mode 100644 lang/gta5sync_no.ts create mode 100644 res/gta5sync_en_US.qm create mode 100644 res/gta5sync_en_US.ts create mode 100644 res/mappreview.jpg create mode 100644 res/pointmaker-16.png create mode 100644 res/pointmaker-24.png create mode 100644 res/pointmaker-32.png create mode 100644 res/pointmaker-8.png create mode 100644 res/qtbase_en_GB.qm diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..41f4538 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,27 @@ +# Auto detect text files and perform LF normalization +* text=auto eol=lf + +# Development files +*.cpp text eol=lf +*.h text eol=lf +*.ui text eol=lf +*.qrc text eol=lf + +# Development resources +*.ini text eol=lf + +# Linux development files +*.desktop text eol=lf + +# Windows development files +*.rc text eol=crlf +*.exe.manifest text eol=crlf + +# Binary files +*.png binary +*.jpg binary +*.qm binary +*.ico binary +*.icns binary +*.xcf binary +*.g5e binary diff --git a/.travis.yml b/.travis.yml index 5ea857e..0a356bb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ sudo: required language: cpp env: -- PACKAGE_VERSION="1.4.0" +- PACKAGE_VERSION="1.5.0" before_install: - test -n $CC && unset CC @@ -12,27 +12,42 @@ before_install: install: - sudo apt-get update -qq - - sudo apt-get install -qq checkinstall dpkg-dev g++ gcc qtbase5-dev qt5-qmake + - sudo apt-get install -qq checkinstall dpkg-dev g++ gcc qtbase5-dev qt5-qmake qttranslations5-l10n libqt4-dev before_script: - - export INSTALL_ROOT=/usr - if [ `git name-rev --tags --name-only $(git rev-parse HEAD)` == "undefined" ]; then export APPLICATION_VERSION="$PACKAGE_VERSION.$TRAVIS_BUILD_NUMBER"; else export APPLICATION_VERSION=`git name-rev --tags --name-only $(git rev-parse HEAD)`; fi - echo "gta5view build version is $APPLICATION_VERSION" - mkdir build - mkdir package + - chmod -x res/gta5sync_*.qm res/gta5view.desktop res/gta5view.png - cd build + - mkdir qt4 + - cd qt4 - echo "Grand Theft Auto V Snapmatic and Savegame viewer" > ./description-pak + - cd .. + - mkdir qt5 + - cd qt5 + - echo "Grand Theft Auto V Snapmatic and Savegame viewer" > ./description-pak + - cd .. script: - - qmake -qt=5 "DEFINES+=GTA5SYNC_BUILDTYPE=\\\\\\\"Release\\\\\\\"" "DEFINES+=GTA5SYNC_DAILYB=\\\\\\\"$APPLICATION_VERSION\\\\\\\"" ../gta5view.pro + - cd qt5 + - qmake -qt=5 GTA5SYNC_PREFIX=/usr QMAKE_CXXFLAGS+=-std=c++11 DEFINES+=GTA5SYNC_BUILDTYPE_DEV "DEFINES+=GTA5SYNC_APPVER=\\\\\\\"$APPLICATION_VERSION\\\\\\\"" DEFINES+=GTA5SYNC_QCONF ../../gta5view.pro - make -j 4 - - sudo checkinstall -D --default --nodoc --pkgname=gta5view --pkgversion=$APPLICATION_VERSION --pkgrelease=travis1 --pkggroup=utility --maintainer="Syping on Travis \<travisci@syping.de\>" --requires=libqt5core5a,libqt5gui5,libqt5network5,libqt5widgets5 --pakdir=../package + - sudo checkinstall -D --default --nodoc --install=no --pkgname=gta5view --pkgversion=$APPLICATION_VERSION --pkgrelease=travis1 --pkggroup=utility --maintainer="Syping on Travis \<travisci@syping.de\>" --requires=libqt5core5a,libqt5gui5,libqt5network5,libqt5widgets5,qttranslations5-l10n --conflicts=gta5view-qt4 --replaces=gta5view-qt4 --pakdir=../../package + - cd .. + - cd qt4 + - qmake -qt=4 GTA5SYNC_PREFIX=/usr QMAKE_CXXFLAGS+=-std=c++11 DEFINES+=GTA5SYNC_BUILDTYPE_DEV "DEFINES+=GTA5SYNC_APPVER=\\\\\\\"$APPLICATION_VERSION\\\\\\\"" DEFINES+=GTA5SYNC_QCONF ../../gta5view.pro + - make -j 4 + - sudo checkinstall -D --default --nodoc --install=no --pkgname=gta5view-qt4 --pkgversion=$APPLICATION_VERSION --pkgrelease=travis1 --pkggroup=utility --maintainer="Syping on Travis \<travisci@syping.de\>" --requires=libqtcore4,libqtgui4,libqt4-network,qtcore4-l10n --conflicts=gta5view --replaces=gta5view --pakdir=../../package + - cd .. deploy: provider: releases api_key: secure: "o7VneEz1aHfdVwZvOZLfopf6uJWNrFsZaBvunTmXFzpmNFhlNS1qwqgMUkIA2yBRbZ3wIzVs4vfwIHv7W9yE/PqK+AYL+R8+AwKGrwlgT4HqJNuk6VM/LNJ6GwT/qkQuaoOVw29bUjmzzgIRdHmw53SlJv6Hh1VE8HphlTT//aex6nCfcFhUZ0BETdZDWz5FSHwL3NalUoqfKfQrJeky5RXzCyCANQC2tKt0bV46GaWIgWrDo2KCTNqPtRWWf5GDmnkXE5IYRMQ3mXvO9iYh0v5Y2jo4PiXGUiFUU6Z3aAWFAiPdGclrBO697cf3lCTzDMhuCETR153qFYsLShUlFf61ITAmCeHAWETjZDri0lmPONo3GoNB6alGfYEA51qw14kXakrTpICtTJj7gw/gtUYOabW6hrzmieNzMBIy62RikDPjyakFnuwW2qNHRlD65e0jYv+6nCpb6E+OV16Ysh1zhV2vTfpfzVmSuyu2J+ELqXD3OZCXRSPpDIih9UQ8335p8FBji6jHORcgym/TRgdgRmENibh8tLzWp+UjpWHuWfcpvZgOskjfwU0iDMCayMJ7tDpOhXHcAhDRnd6XRIiOJ5YZCzflj2nEwmt3YUd7DwXS/AU+WHOmcNQBjXBxF/FJa35XXcy3HKJM5TTKqtph3medo30us5yXHeG6NNg=" - file: "../package/gta5view_$APPLICATION_VERSION-travis1_amd64.deb" + file_glob: true + file: "../package/gta5view*.deb" skip_cleanup: true on: tags: true diff --git a/AboutDialog.cpp b/AboutDialog.cpp index a7bdb51..bf2d4ed 100755 --- a/AboutDialog.cpp +++ b/AboutDialog.cpp @@ -1,121 +1,125 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include <QStringBuilder> -#include "AboutDialog.h" -#include "ui_AboutDialog.h" -#include "AppEnv.h" -#include "config.h" - -AboutDialog::AboutDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::AboutDialog) -{ - // Set Window Flags - setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint); - - // Build Strings - QString appVersion = qApp->applicationVersion(); - QString buildType = GTA5SYNC_BUILDTYPE; - buildType.replace("_", " "); - QString projectBuild = GTA5SYNC_BUILDDATETIME; - QString buildStr = GTA5SYNC_BUILDSTRING; - - // Additional Content - QString usingStr = tr("Using %1 %2", "Exp. Using libmyfuck"); - QString translatedByStr = tr("Translated by %1", "Exp. Translated by Syping"); - QString translatedByVal = tr("NAME_OF_TRANSLATOR", "Your Name (The person behind your screen looking at this text!)"); - QString translatorProfile = tr("TRANSLATOR_PROFILE", "mailto: http:// https:// Exp. https://github.com/Syping/"); - QString additionalContent = ""; - if (translatedByVal != "NAME_OF_TRANSLATOR") - { - if (translatorProfile != "TRANSLATOR_PROFILE") - { - additionalContent.append(translatedByStr.arg(QString("<a href=\"%1\">%2</a>").arg(translatorProfile, translatedByVal))); - } - else - { - additionalContent.append(translatedByStr.arg(translatedByVal)); - } - } -#ifdef WITH_LIBJPEGTURBO // DONT USE IT FOR NOW - bool additionalContentClip = false; - if (!additionalContent.isEmpty()) - { - additionalContentClip = true; - additionalContent.append(" ("); - } - additionalContent.append(usingStr.arg("libjpegturbo", WITH_LIBJPEGTURBO)); - if (additionalContentClip) - { - additionalContent.append(")"); - } -#else - Q_UNUSED(usingStr) -#endif - - // Project Description -#ifdef GTA5SYNC_ENABLED - QString projectDes = tr("A project for viewing and sync Grand Theft Auto V Snapmatic<br/>\nPictures and Savegames"); -#else - QString projectDes = tr("A project for viewing Grand Theft Auto V Snapmatic<br/>\nPictures and Savegames"); -#endif - - // Copyright Description - QString copyrightDes1 = tr("Copyright © <a href=\"%1\">%2</a> %3"); - copyrightDes1 = copyrightDes1.arg(GTA5SYNC_APPVENDORLINK, GTA5SYNC_APPVENDOR, GTA5SYNC_COPYRIGHT); - QString copyrightDes2 = tr("%1 is licensed under <a href=\"https://www.gnu.org/licenses/gpl-3.0.html#content\">GNU GPLv3</a>"); - copyrightDes2 = copyrightDes2.arg(GTA5SYNC_APPSTR); - QString copyrightDesA; - if (!additionalContent.isEmpty()) - { - copyrightDesA = copyrightDes1 % "<br/>" % additionalContent % "<br/>" % copyrightDes2; - } - else - { - copyrightDesA = copyrightDes1 % "<br/>" % copyrightDes2; - } - - // Setup User Interface - ui->setupUi(this); - aboutStr = ui->labAbout->text(); - titleStr = this->windowTitle(); - ui->labAbout->setText(aboutStr.arg(GTA5SYNC_APPSTR, projectDes, appVersion % " (" % buildType % ")", projectBuild, buildStr, qVersion(), copyrightDesA)); - this->setWindowTitle(titleStr.arg(GTA5SYNC_APPSTR)); - - if (QIcon::hasThemeIcon("dialog-close")) - { - ui->cmdClose->setIcon(QIcon::fromTheme("dialog-close")); - } - - // DPI calculation - qreal screenRatio = AppEnv::screenRatio(); - if (!additionalContent.isEmpty()) - { - resize(375 * screenRatio, 270 * screenRatio); - } - else - { - resize(375 * screenRatio, 260 * screenRatio); - } -} - -AboutDialog::~AboutDialog() -{ - delete ui; -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include <QStringBuilder> +#include "AboutDialog.h" +#include "ui_AboutDialog.h" +#include "AppEnv.h" +#include "config.h" + +AboutDialog::AboutDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::AboutDialog) +{ + // Set Window Flags + setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint); + + // Build Strings + QString appVersion = qApp->applicationVersion(); + QString buildType = tr(GTA5SYNC_BUILDTYPE); + buildType.replace("_", " "); + QString projectBuild = GTA5SYNC_BUILDDATETIME; + QString buildStr = GTA5SYNC_BUILDSTRING; + + // Translator Comments + //: Using specific library, example Using libmyfuck + QString usingStr = tr("Using %1 %2"); + //: Translated by translator, example Translated by Syping + QString translatedByStr = tr("Translated by %1"); + //: Enter your name there + QString translatedByVal = tr("NAME_OF_TRANSLATOR"); + //: Enter your proilfe there, example a GitHub profile, E-Mail with "mailto: afucker@sumfuck.com" or a webpage + QString translatorProfile = tr("TRANSLATOR_PROFILE"); + QString additionalContent = ""; + if (translatedByVal != "NAME_OF_TRANSLATOR") + { + if (translatorProfile != "TRANSLATOR_PROFILE") + { + additionalContent += translatedByStr.arg(QString("<a href=\"%1\">%2</a>").arg(translatorProfile, translatedByVal)); + } + else + { + additionalContent += translatedByStr.arg(translatedByVal); + } + } +#ifdef WITH_LIBJPEGTURBO // DONT USE IT FOR NOW + bool additionalContentClip = false; + if (!additionalContent.isEmpty()) + { + additionalContentClip = true; + additionalContent += " ("; + } + additionalContent += usingStr.arg("libjpegturbo", WITH_LIBJPEGTURBO); + if (additionalContentClip) + { + additionalContent += ")"; + } +#else + Q_UNUSED(usingStr) +#endif + + // Project Description +#ifdef GTA5SYNC_ENABLED + QString projectDes = tr("A project for viewing and sync Grand Theft Auto V Snapmatic<br/>\nPictures and Savegames"); +#else + QString projectDes = tr("A project for viewing Grand Theft Auto V Snapmatic<br/>\nPictures and Savegames"); +#endif + + // Copyright Description + QString copyrightDes1 = tr("Copyright © <a href=\"%1\">%2</a> %3"); + copyrightDes1 = copyrightDes1.arg(GTA5SYNC_APPVENDORLINK, GTA5SYNC_APPVENDOR, GTA5SYNC_COPYRIGHT); + QString copyrightDes2 = tr("%1 is licensed under <a href=\"https://www.gnu.org/licenses/gpl-3.0.html#content\">GNU GPLv3</a>"); + copyrightDes2 = copyrightDes2.arg(GTA5SYNC_APPSTR); + QString copyrightDesA; + if (!additionalContent.isEmpty()) + { + copyrightDesA = copyrightDes1 % "<br/>" % additionalContent % "<br/>" % copyrightDes2; + } + else + { + copyrightDesA = copyrightDes1 % "<br/>" % copyrightDes2; + } + + // Setup User Interface + ui->setupUi(this); + aboutStr = ui->labAbout->text(); + titleStr = this->windowTitle(); + ui->labAbout->setText(aboutStr.arg(GTA5SYNC_APPSTR, projectDes, appVersion % " (" % buildType % ")", projectBuild, buildStr, qVersion(), copyrightDesA)); + this->setWindowTitle(titleStr.arg(GTA5SYNC_APPSTR)); + + if (QIcon::hasThemeIcon("dialog-close")) + { + ui->cmdClose->setIcon(QIcon::fromTheme("dialog-close")); + } + + // DPI calculation + qreal screenRatio = AppEnv::screenRatio(); + if (!additionalContent.isEmpty()) + { + resize(375 * screenRatio, 270 * screenRatio); + } + else + { + resize(375 * screenRatio, 260 * screenRatio); + } +} + +AboutDialog::~AboutDialog() +{ + delete ui; +} diff --git a/AboutDialog.h b/AboutDialog.h index ef78bd5..a160ae9 100755 --- a/AboutDialog.h +++ b/AboutDialog.h @@ -1,44 +1,44 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef ABOUTDIALOG_H -#define ABOUTDIALOG_H - -#include <QDialog> - -namespace Ui { -class AboutDialog; -} - -class AboutDialog : public QDialog -{ - Q_OBJECT - -public: - explicit AboutDialog(QWidget *parent = 0); - ~AboutDialog(); - -private slots: - -private: - Ui::AboutDialog *ui; - QString aboutStr; - QString titleStr; -}; - -#endif // ABOUTDIALOG_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef ABOUTDIALOG_H +#define ABOUTDIALOG_H + +#include <QDialog> + +namespace Ui { +class AboutDialog; +} + +class AboutDialog : public QDialog +{ + Q_OBJECT + +public: + explicit AboutDialog(QWidget *parent = 0); + ~AboutDialog(); + +private slots: + +private: + Ui::AboutDialog *ui; + QString aboutStr; + QString titleStr; +}; + +#endif // ABOUTDIALOG_H diff --git a/AboutDialog.ui b/AboutDialog.ui index d44926d..9419485 100755 --- a/AboutDialog.ui +++ b/AboutDialog.ui @@ -1,102 +1,102 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>AboutDialog</class> - <widget class="QDialog" name="AboutDialog"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>375</width> - <height>260</height> - </rect> - </property> - <property name="windowTitle"> - <string>About %1</string> - </property> - <property name="modal"> - <bool>true</bool> - </property> - <layout class="QVBoxLayout" name="vlAbout"> - <item> - <widget class="QLabel" name="labAbout"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string><span style=" font-weight:600;">%1</span><br/> -<br/> -%2<br/> -<br/> -Version %3<br/> -Created on %4<br/> -Built with Qt %5<br/> -Running with Qt %6<br/> -<br/> -%7</string> - </property> - <property name="alignment"> - <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> - </property> - <property name="wordWrap"> - <bool>false</bool> - </property> - <property name="openExternalLinks"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="hlButtons"> - <item> - <spacer name="hsButtons"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="cmdClose"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>&Close</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - <resources/> - <connections> - <connection> - <sender>cmdClose</sender> - <signal>clicked()</signal> - <receiver>AboutDialog</receiver> - <slot>close()</slot> - <hints> - <hint type="sourcelabel"> - <x>327</x> - <y>228</y> - </hint> - <hint type="destinationlabel"> - <x>187</x> - <y>124</y> - </hint> - </hints> - </connection> - </connections> -</ui> +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>AboutDialog</class> + <widget class="QDialog" name="AboutDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>375</width> + <height>260</height> + </rect> + </property> + <property name="windowTitle"> + <string>About %1</string> + </property> + <property name="modal"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="vlAbout"> + <item> + <widget class="QLabel" name="labAbout"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string><span style=" font-weight:600;">%1</span><br/> +<br/> +%2<br/> +<br/> +Version %3<br/> +Created on %4<br/> +Built with Qt %5<br/> +Running with Qt %6<br/> +<br/> +%7</string> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + <property name="openExternalLinks"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="hlButtons"> + <item> + <spacer name="hsButtons"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="cmdClose"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Close</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>cmdClose</sender> + <signal>clicked()</signal> + <receiver>AboutDialog</receiver> + <slot>close()</slot> + <hints> + <hint type="sourcelabel"> + <x>327</x> + <y>228</y> + </hint> + <hint type="destinationlabel"> + <x>187</x> + <y>124</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/AppEnv.cpp b/AppEnv.cpp index c1449f8..cab453a 100755 --- a/AppEnv.cpp +++ b/AppEnv.cpp @@ -1,155 +1,178 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "config.h" -#include "AppEnv.h" -#include "StringParser.h" -#include "StandardPaths.h" -#include <QtGlobal> -#include <QDesktopWidget> -#include <QApplication> -#include <QSettings> -#include <QScreen> -#include <QDebug> -#include <QRect> -#include <QDir> -#include <iostream> -using namespace std; - -AppEnv::AppEnv() -{ - -} - -// Folder Stuff - -QString AppEnv::getGameFolder(bool *ok) -{ - QDir dir; - QString GTAV_FOLDER = QString::fromUtf8(qgetenv("GTAV_FOLDER")); - if (GTAV_FOLDER != "") - { - dir.setPath(GTAV_FOLDER); - if (dir.exists()) - { - if (ok != NULL) *ok = true; - qputenv("GTAV_FOLDER", dir.absolutePath().toUtf8()); - return dir.absolutePath(); - } - } - - QString GTAV_defaultFolder = StandardPaths::documentsLocation() + QDir::separator() + "Rockstar Games" + QDir::separator() + "GTA V"; - QString GTAV_returnFolder = GTAV_defaultFolder; - - QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); - settings.beginGroup("dir"); - bool forceDir = settings.value("force", false).toBool(); - GTAV_returnFolder = settings.value("dir", GTAV_defaultFolder).toString(); - settings.endGroup(); - - if (forceDir) - { - dir.setPath(GTAV_returnFolder); - if (dir.exists()) - { - if (ok != 0) *ok = true; - qputenv("GTAV_FOLDER", dir.absolutePath().toUtf8()); - return dir.absolutePath(); - } - } - - dir.setPath(GTAV_defaultFolder); - if (dir.exists()) - { - if (ok != 0) *ok = true; - qputenv("GTAV_FOLDER", dir.absolutePath().toUtf8()); - return dir.absolutePath(); - } - - if (!forceDir) - { - dir.setPath(GTAV_returnFolder); - if (dir.exists()) - { - if (ok != 0) *ok = true; - qputenv("GTAV_FOLDER", dir.absolutePath().toUtf8()); - return dir.absolutePath(); - } - } - - if (ok != 0) *ok = false; - return ""; -} - -bool AppEnv::setGameFolder(QString gameFolder) -{ - QDir dir; - dir.setPath(gameFolder); - if (dir.exists()) - { - qputenv("GTAV_FOLDER", dir.absolutePath().toUtf8()); - return true; - } - return false; -} - -QString AppEnv::getLangFolder() -{ - return StringParser::convertBuildedString(QString::fromUtf8(GTA5SYNC_LANG)); -} - -QString AppEnv::getPluginsFolder() -{ - return StringParser::convertBuildedString(QString::fromUtf8(GTA5SYNC_PLUG)); -} - -// Web Stuff - -QByteArray AppEnv::getUserAgent() -{ - return QString("Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0 %1/%2").arg(GTA5SYNC_APPSTR, GTA5SYNC_APPVER).toUtf8(); -} - -// QUrl AppEnv::getCrewFetchingUrl(QString crewID) -// { -// return QUrl(QString("https://socialclub.rockstargames.com/reference/crewfeed/%1").arg(crewID)); -// } - -QUrl AppEnv::getCrewFetchingUrl(QString crewID) -{ - return QUrl(QString("https://socialclub.rockstargames.com/crew/%1/%1").arg(crewID)); -} - -QUrl AppEnv::getPlayerFetchingUrl(QString crewID, QString pageNumber) -{ - return QUrl(QString("https://socialclub.rockstargames.com/crewsapi/GetMembersList?crewId=%1&pageNumber=%2").arg(crewID, pageNumber)); -} - -qreal AppEnv::screenRatio() -{ -#if QT_VERSION >= 0x050000 - qreal dpi = QGuiApplication::primaryScreen()->logicalDotsPerInch(); -#else - qreal dpi = qApp->desktop()->logicalDpiX(); -#endif -#ifdef Q_OS_MAC - return (dpi / 72); -#else - return (dpi / 96); -#endif -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "config.h" +#include "AppEnv.h" +#include "StringParser.h" +#include "StandardPaths.h" +#include <QtGlobal> +#include <QStringBuilder> +#include <QDesktopWidget> +#include <QApplication> +#include <QSettings> +#include <QScreen> +#include <QDebug> +#include <QRect> +#include <QDir> +#include <iostream> +using namespace std; + +AppEnv::AppEnv() +{ + +} + +// Folder Stuff + +QString AppEnv::getGameFolder(bool *ok) +{ + QDir dir; + QString GTAV_FOLDER = QString::fromUtf8(qgetenv("GTAV_FOLDER")); + if (GTAV_FOLDER != "") + { + dir.setPath(GTAV_FOLDER); + if (dir.exists()) + { + if (ok != NULL) *ok = true; + qputenv("GTAV_FOLDER", dir.absolutePath().toUtf8()); + return dir.absolutePath(); + } + } + + QString GTAV_defaultFolder = StandardPaths::documentsLocation() % QDir::separator() % "Rockstar Games" % QDir::separator() % "GTA V"; + QString GTAV_returnFolder = GTAV_defaultFolder; + + QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); + settings.beginGroup("dir"); + bool forceDir = settings.value("force", false).toBool(); + GTAV_returnFolder = settings.value("dir", GTAV_defaultFolder).toString(); + settings.endGroup(); + + if (forceDir) + { + dir.setPath(GTAV_returnFolder); + if (dir.exists()) + { + if (ok != 0) *ok = true; + qputenv("GTAV_FOLDER", dir.absolutePath().toUtf8()); + return dir.absolutePath(); + } + } + + dir.setPath(GTAV_defaultFolder); + if (dir.exists()) + { + if (ok != 0) *ok = true; + qputenv("GTAV_FOLDER", dir.absolutePath().toUtf8()); + return dir.absolutePath(); + } + + if (!forceDir) + { + dir.setPath(GTAV_returnFolder); + if (dir.exists()) + { + if (ok != 0) *ok = true; + qputenv("GTAV_FOLDER", dir.absolutePath().toUtf8()); + return dir.absolutePath(); + } + } + + if (ok != 0) *ok = false; + return ""; +} + +bool AppEnv::setGameFolder(QString gameFolder) +{ + QDir dir; + dir.setPath(gameFolder); + if (dir.exists()) + { + qputenv("GTAV_FOLDER", dir.absolutePath().toUtf8()); + return true; + } + return false; +} + +QString AppEnv::getExLangFolder() +{ + return StringParser::convertBuildedString(GTA5SYNC_LANG); +} + +QString AppEnv::getInLangFolder() +{ +#ifdef GTA5SYNC_QCONF +#ifdef GTA5SYNC_INLANG + return StringParser::convertBuildedString(GTA5SYNC_INLANG); +#else + return StringParser::convertBuildedString(GTA5SYNC_SHARE % QLatin1String("SEPARATOR:APPNAME:SEPARATOR:translations")); +#endif +#else +#ifdef GTA5SYNC_INLANG + return StringParser::convertBuildedString(GTA5SYNC_INLANG); +#else + return QString(":/tr"); +#endif +#endif +} + +QString AppEnv::getPluginsFolder() +{ + return StringParser::convertBuildedString(GTA5SYNC_PLUG); +} + +// Web Stuff + +QByteArray AppEnv::getUserAgent() +{ + return QString("Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0 %1/%2").arg(GTA5SYNC_APPSTR, GTA5SYNC_APPVER).toUtf8(); +} + +// QUrl AppEnv::getCrewFetchingUrl(QString crewID) +// { +// return QUrl(QString("https://socialclub.rockstargames.com/reference/crewfeed/%1").arg(crewID)); +// } + +QUrl AppEnv::getCrewFetchingUrl(QString crewID) +{ + return QUrl(QString("https://socialclub.rockstargames.com/crew/%1/%1").arg(crewID)); +} + +QUrl AppEnv::getPlayerFetchingUrl(QString crewID, QString pageNumber) +{ + return QUrl(QString("https://socialclub.rockstargames.com/crewsapi/GetMembersList?crewId=%1&pageNumber=%2").arg(crewID, pageNumber)); +} + +QUrl AppEnv::getPlayerFetchingUrl(QString crewID, int pageNumber) +{ + return getPlayerFetchingUrl(crewID, QString::number(pageNumber)); +} + +qreal AppEnv::screenRatio() +{ +#if QT_VERSION >= 0x050000 + qreal dpi = QGuiApplication::primaryScreen()->logicalDotsPerInch(); +#else + qreal dpi = qApp->desktop()->logicalDpiX(); +#endif +#ifdef Q_OS_MAC + return (dpi / 72); +#else + return (dpi / 96); +#endif +} diff --git a/AppEnv.h b/AppEnv.h index 332b6e1..21a8e7b 100755 --- a/AppEnv.h +++ b/AppEnv.h @@ -1,45 +1,47 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef APPENV_H -#define APPENV_H - -#include <QString> -#include <QUrl> - -class AppEnv -{ -public: - AppEnv(); - - // Folder Stuff - static QString getGameFolder(bool *ok = 0); - static bool setGameFolder(QString gameFolder); - static QString getLangFolder(); - static QString getPluginsFolder(); - - // Web Stuff - static QByteArray getUserAgent(); - static QUrl getCrewFetchingUrl(QString crewID); - static QUrl getPlayerFetchingUrl(QString crewID, QString pageNumber); - - // Screen Stuff - static qreal screenRatio(); -}; - -#endif // APPENV_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef APPENV_H +#define APPENV_H + +#include <QString> +#include <QUrl> + +class AppEnv +{ +public: + AppEnv(); + + // Folder Stuff + static QString getGameFolder(bool *ok = 0); + static bool setGameFolder(QString gameFolder); + static QString getExLangFolder(); + static QString getInLangFolder(); + static QString getPluginsFolder(); + + // Web Stuff + static QByteArray getUserAgent(); + static QUrl getCrewFetchingUrl(QString crewID); + static QUrl getPlayerFetchingUrl(QString crewID, QString pageNumber); + static QUrl getPlayerFetchingUrl(QString crewID, int pageNumber); + + // Screen Stuff + static qreal screenRatio(); +}; + +#endif // APPENV_H diff --git a/CrewDatabase.cpp b/CrewDatabase.cpp index 11e3a97..a1b4919 100755 --- a/CrewDatabase.cpp +++ b/CrewDatabase.cpp @@ -1,83 +1,165 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "StandardPaths.h" -#include "CrewDatabase.h" -#include "config.h" -#include <QFile> -#include <QDir> - -CrewDatabase::CrewDatabase(QObject *parent) : QObject(parent) -{ - QDir dir; - dir.mkpath(StandardPaths::dataLocation()); - dir.setPath(StandardPaths::dataLocation()); - QString dirPath = dir.absolutePath(); - QString defaultConfPath = dirPath + QDir::separator() + "crews.ini"; - - QSettings confPathSettings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); - confPathSettings.beginGroup("Database"); - QString confPathFile = confPathSettings.value("Crews", defaultConfPath).toString(); - confPathSettings.endGroup(); - - crewDB = new QSettings(confPathFile, QSettings::IniFormat); - crewDB->beginGroup("Crews"); -} - -CrewDatabase::~CrewDatabase() -{ - crewDB->endGroup(); - delete crewDB; -} - -QStringList CrewDatabase::getCrews() -{ - QStringList compatibleCrewList = crewDB->childKeys(); - crewDB->endGroup(); - crewDB->beginGroup("CrewList"); - QStringList crewIDs = crewDB->value("IDs", QStringList()).toStringList(); - crewIDs.append(compatibleCrewList); - crewIDs.removeDuplicates(); - crewDB->endGroup(); - crewDB->beginGroup("Crews"); - return crewIDs; -} - -QString CrewDatabase::getCrewName(int crewID) -{ - QString crewStr = crewDB->value(QString::number(crewID), crewID).toString(); - if (crewID == 0) crewStr = tr("No Crew", ""); - return crewStr; -} - -void CrewDatabase::setCrewName(int crewID, QString crewName) -{ - crewDB->setValue(QString::number(crewID), crewName); -} - -void CrewDatabase::addCrew(int crewID) -{ - QStringList crews = getCrews(); - crews.append(QString::number(crewID)); - crews.removeDuplicates(); - crewDB->endGroup(); - crewDB->beginGroup("CrewList"); - crewDB->setValue("IDs", crews); - crewDB->endGroup(); - crewDB->beginGroup("Crews"); -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "StandardPaths.h" +#include "CrewDatabase.h" +#include "config.h" +#include <QStringBuilder> +#include <QMutexLocker> +#include <QDebug> +#include <QFile> +#include <QDir> + +CrewDatabase::CrewDatabase(QObject *parent) : QObject(parent) +{ + QDir dir; + dir.mkpath(StandardPaths::dataLocation()); + dir.setPath(StandardPaths::dataLocation()); + QString dirPath = dir.absolutePath(); + QString defaultConfPath = dirPath % QDir::separator() % "crews.ini"; + + QSettings confPathSettings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); + confPathSettings.beginGroup("Database"); + QString confPathFile = confPathSettings.value("Crews", defaultConfPath).toString(); + confPathSettings.endGroup(); + + crewDB = new QSettings(confPathFile, QSettings::IniFormat); + crewDB->beginGroup("Crews"); + + addProcess = false; +} + +CrewDatabase::~CrewDatabase() +{ + crewDB->endGroup(); + delete crewDB; +} + +QStringList CrewDatabase::getCrews() +{ + QMutexLocker locker(&mutex); +#ifdef GTA5SYNC_DEBUG + qDebug() << "getCrews"; +#endif + return getCrews_p(); +} + +QStringList CrewDatabase::getCrews_p() +{ +#ifdef GTA5SYNC_DEBUG + qDebug() << "getCrews_p"; +#endif + QStringList compatibleCrewList = getCompatibleCrews_p(); + crewDB->endGroup(); + crewDB->beginGroup("CrewList"); + QStringList crewIDs = crewDB->value("IDs", QStringList()).toStringList(); + crewIDs += compatibleCrewList; + crewIDs.removeDuplicates(); + crewDB->endGroup(); + crewDB->beginGroup("Crews"); + return crewIDs; +} + +QStringList CrewDatabase::getCompatibleCrews() +{ + QMutexLocker locker(&mutex); +#ifdef GTA5SYNC_DEBUG + qDebug() << "getCompatibleCrews"; +#endif + return getCompatibleCrews_p(); +} + +QStringList CrewDatabase::getCompatibleCrews_p() +{ +#ifdef GTA5SYNC_DEBUG + qDebug() << "getCompatibleCrews_p"; +#endif + return crewDB->childKeys(); +} + +QString CrewDatabase::getCrewName(int crewID) +{ + QMutexLocker locker(&mutex); +#ifdef GTA5SYNC_DEBUG + qDebug() << "getCrewName" << crewID; +#endif + QString crewStr = crewDB->value(QString::number(crewID), crewID).toString(); + if (crewID == 0) crewStr = tr("No Crew", ""); + return crewStr; +} + +void CrewDatabase::setCrewName(int crewID, QString crewName) +{ + QMutexLocker locker(&mutex); +#ifdef GTA5SYNC_DEBUG + qDebug() << "setCrewName" << crewID << crewName; +#endif + crewDB->setValue(QString::number(crewID), crewName); +} + +void CrewDatabase::addCrew(int crewID) +{ + QMutexLocker locker(&mutex); +#ifdef GTA5SYNC_DEBUG + qDebug() << "addCrew" << crewID; +#endif + QStringList crews = getCrews_p(); + crews += QString::number(crewID); + crews.removeDuplicates(); + crewDB->endGroup(); + crewDB->beginGroup("CrewList"); + crewDB->setValue("IDs", crews); + crewDB->endGroup(); + crewDB->beginGroup("Crews"); +} + +bool CrewDatabase::isCompatibleCrew(QString crewNID) +{ + QMutexLocker locker(&mutex); +#ifdef GTA5SYNC_DEBUG + qDebug() << "isCompatibleCrew" << crewNID; +#endif + return crewDB->contains(crewNID); +} + +bool CrewDatabase::isCompatibleCrew(int crewID) +{ + QMutexLocker locker(&mutex); +#ifdef GTA5SYNC_DEBUG + qDebug() << "isCompatibleCrew" << crewID; +#endif + return crewDB->contains(QString::number(crewID)); +} + +void CrewDatabase::setAddingCrews(bool addingCrews) +{ + QMutexLocker locker(&mutex); +#ifdef GTA5SYNC_DEBUG + qDebug() << "setAddingCrews" << addingCrews; +#endif + addProcess = addingCrews; +} + +bool CrewDatabase::isAddingCrews() +{ + QMutexLocker locker(&mutex); +#ifdef GTA5SYNC_DEBUG + qDebug() << "isAddingCrews"; +#endif + return addProcess; +} diff --git a/CrewDatabase.h b/CrewDatabase.h index 471b236..b5c7ee0 100755 --- a/CrewDatabase.h +++ b/CrewDatabase.h @@ -1,43 +1,53 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef CREWDATABASE_H -#define CREWDATABASE_H - -#include <QSettings> -#include <QObject> -#include <QMap> - -class CrewDatabase : public QObject -{ - Q_OBJECT -public: - explicit CrewDatabase(QObject *parent = 0); - void setCrewName(int crewID, QString crewName); - QString getCrewName(int crewID); - QStringList getCrews(); - ~CrewDatabase(); - -private: - QSettings *crewDB; - -public slots: - void addCrew(int crewID); -}; - -#endif // CREWDATABASE_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef CREWDATABASE_H +#define CREWDATABASE_H + +#include <QSettings> +#include <QObject> +#include <QMutex> +#include <QMap> + +class CrewDatabase : public QObject +{ + Q_OBJECT +public: + explicit CrewDatabase(QObject *parent = 0); + QString getCrewName(int crewID); + QStringList getCompatibleCrews(); + QStringList getCrews(); + void setAddingCrews(bool addingCrews); + bool isCompatibleCrew(QString crewNID); + bool isCompatibleCrew(int crewID); + bool isAddingCrews(); + ~CrewDatabase(); + +private: + mutable QMutex mutex; + bool addProcess; + QSettings *crewDB; + QStringList getCrews_p(); + QStringList getCompatibleCrews_p(); + +public slots: + void setCrewName(int crewID, QString crewName); + void addCrew(int crewID); +}; + +#endif // CREWDATABASE_H diff --git a/DatabaseThread.cpp b/DatabaseThread.cpp index 0b090d0..4e7d90d 100755 --- a/DatabaseThread.cpp +++ b/DatabaseThread.cpp @@ -1,296 +1,276 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "DatabaseThread.h" -#include "CrewDatabase.h" -#include "AppEnv.h" -#include <QNetworkAccessManager> -#include <QNetworkRequest> -#include <QNetworkReply> -#include <QJsonDocument> -#include <QJsonObject> -#include <QStringList> -#include <QVariantMap> -#include <QEventLoop> -#include <QTimer> -#include <QDebug> -#include <QUrl> - -DatabaseThread::DatabaseThread(CrewDatabase *crewDB, QObject *parent) : QThread(parent), crewDB(crewDB) -{ - crewMaxPages = 83; - threadRunning = true; -} - -void DatabaseThread::run() -{ - QEventLoop threadLoop; - QStringList crewList; - - // Register thread loop end signal - QObject::connect(this, SIGNAL(threadEndCommited()), &threadLoop, SLOT(quit())); - - // Quick time scan - if (crewList.length() <= 3) - { - scanCrewReference(crewList, 2500); - scanCrewMembersList(crewList, 3, 2500); - emit playerNameUpdated(); - } - else if (crewList.length() <= 5) - { - scanCrewReference(crewList, 2500); - scanCrewMembersList(crewList, 2, 2500); - emit playerNameUpdated(); - } - - QEventLoop *waitingLoop = new QEventLoop(); - QTimer::singleShot(10000, waitingLoop, SLOT(quit())); - QObject::connect(this, SIGNAL(threadEndCommited()), waitingLoop, SLOT(quit())); - waitingLoop->exec(); - delete waitingLoop; - - while (threadRunning) - { - crewList = crewDB->getCrews(); - - // Long time scan - scanCrewReference(crewList, 10000); - scanCrewMembersList(crewList, crewMaxPages, 10000); - emit playerNameUpdated(); - - if (threadRunning) - { - QTimer::singleShot(300000, &threadLoop, SLOT(quit())); - threadLoop.exec(); - } - } -} - -// void DatabaseThread::scanCrewReference(QStringList crewList, int requestDelay) -// { -// foreach (const QString &crewID, crewList) -// { -// if (threadRunning && crewID != "0") -// { -// QNetworkAccessManager *netManager = new QNetworkAccessManager(); - -// QNetworkRequest netRequest(AppEnv::getCrewFetchingUrl(crewID)); -// netRequest.setRawHeader("User-Agent", AppEnv::getUserAgent()); -// netRequest.setRawHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); -// netRequest.setRawHeader("Accept-Language", "en-US;q=0.5,en;q=0.3"); -// netRequest.setRawHeader("Connection", "keep-alive"); - -// QNetworkReply *netReply = netManager->get(netRequest); - -// QEventLoop *downloadLoop = new QEventLoop(); -// QObject::connect(netReply, SIGNAL(finished()), downloadLoop, SLOT(quit())); -// QObject::connect(this, SIGNAL(threadEndCommited()), downloadLoop, SLOT(quit())); -// QTimer::singleShot(30000, downloadLoop, SLOT(quit())); -// downloadLoop->exec(); -// delete downloadLoop; - -// if (netReply->isFinished()) -// { -// QByteArray crewJson = netReply->readAll(); -// QJsonDocument crewDocument = QJsonDocument::fromJson(crewJson); -// QJsonObject crewObject = crewDocument.object(); -// QVariantMap crewMap = crewObject.toVariantMap(); -// QString crewName; -// bool isFound = false; - -// if (crewMap.contains("activities")) -// { -// QList<QVariant> activitiesList = crewMap["activities"].toList(); -// foreach (const QVariant &activitiesVariant, activitiesList) -// { -// QMap<QString, QVariant> activityRootMap = activitiesVariant.toMap(); -// foreach(const QVariant &activityRootVariant, activityRootMap) -// { -// QMap<QString, QVariant> activityMap = activityRootVariant.toMap(); -// foreach(const QVariant &activityVariant, activityMap) -// { -// QMap<QString, QVariant> activityFinalMap = activityVariant.toMap(); -// if (activityFinalMap.contains("id") && activityFinalMap["id"] == crewID) -// { -// if (activityFinalMap.contains("name") && isFound == false) -// { -// isFound = true; -// crewName = activityFinalMap["name"].toString(); -// } -// } -// } -// } -// } -// } -// if (!crewName.isNull()) -// { -// crewDB->setCrewName(crewID.toInt(), crewName); -// } -// } - -// QEventLoop *waitingLoop = new QEventLoop(); -// QTimer::singleShot(requestDelay, waitingLoop, SLOT(quit())); -// QObject::connect(this, SIGNAL(threadEndCommited()), waitingLoop, SLOT(quit())); -// waitingLoop->exec(); -// delete waitingLoop; - -// delete netReply; -// delete netManager; -// } -// } -// } - -void DatabaseThread::scanCrewReference(QStringList crewList, int requestDelay) -{ - foreach (const QString &crewID, crewList) - { - if (threadRunning && crewID != "0") - { - QNetworkAccessManager *netManager = new QNetworkAccessManager(); - - QNetworkRequest netRequest(AppEnv::getCrewFetchingUrl(crewID)); -#if QT_VERSION >= 0x050600 - netRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); -#endif - netRequest.setRawHeader("User-Agent", AppEnv::getUserAgent()); - netRequest.setRawHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); - netRequest.setRawHeader("Accept-Language", "en-US;q=0.5,en;q=0.3"); - netRequest.setRawHeader("Connection", "keep-alive"); - - QNetworkReply *netReply = netManager->get(netRequest); - - QEventLoop *downloadLoop = new QEventLoop(); - QObject::connect(netReply, SIGNAL(finished()), downloadLoop, SLOT(quit())); - QObject::connect(this, SIGNAL(threadEndCommited()), downloadLoop, SLOT(quit())); - QTimer::singleShot(30000, downloadLoop, SLOT(quit())); - downloadLoop->exec(); - delete downloadLoop; - - if (netReply->isFinished()) - { - QString crewName; - QByteArray crewHtml = netReply->readAll(); - QStringList crewHtmlSplit1 = QString::fromUtf8(crewHtml).split("<title>Rockstar Games Social Club - Crew : "); - if (crewHtmlSplit1.length() >= 2) - { - QStringList crewHtmlSplit2 = QString(crewHtmlSplit1.at(1)).split("</title>"); - if (crewHtmlSplit2.length() >= 1) - { - crewName = crewHtmlSplit2.at(0); - } - } - if (!crewName.isEmpty()) - { - crewDB->setCrewName(crewID.toInt(), crewName); - } - } - - QEventLoop *waitingLoop = new QEventLoop(); - QTimer::singleShot(requestDelay, waitingLoop, SLOT(quit())); - QObject::connect(this, SIGNAL(threadEndCommited()), waitingLoop, SLOT(quit())); - waitingLoop->exec(); - delete waitingLoop; - - delete netReply; - delete netManager; - } - } -} - -void DatabaseThread::scanCrewMembersList(QStringList crewList, int maxPages, int requestDelay) -{ - foreach (const QString &crewID, crewList) - { - if (threadRunning && crewID != "0") - { - int currentPage = 0; - int foundPlayers = 0; - int totalPlayers = 1000; - - while(foundPlayers < totalPlayers && currentPage < maxPages) - { - QNetworkAccessManager *netManager = new QNetworkAccessManager(); - - QNetworkRequest netRequest(AppEnv::getPlayerFetchingUrl(crewID, QString::number(currentPage))); -#if QT_VERSION >= 0x050600 - netRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); -#endif - netRequest.setRawHeader("User-Agent", AppEnv::getUserAgent()); - netRequest.setRawHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); - netRequest.setRawHeader("Accept-Language", "en-US;q=0.5,en;q=0.3"); - netRequest.setRawHeader("Connection", "keep-alive"); - - QNetworkReply *netReply = netManager->get(netRequest); - - QEventLoop *downloadLoop = new QEventLoop(); - QObject::connect(netReply, SIGNAL(finished()), downloadLoop, SLOT(quit())); - QObject::connect(this, SIGNAL(threadEndCommited()), downloadLoop, SLOT(quit())); - QTimer::singleShot(30000, downloadLoop, SLOT(quit())); - downloadLoop->exec(); - delete downloadLoop; - - if (netReply->isFinished()) - { - QByteArray crewJson = netReply->readAll(); - QJsonDocument crewDocument = QJsonDocument::fromJson(crewJson); - QJsonObject crewObject = crewDocument.object(); - QVariantMap crewMap = crewObject.toVariantMap(); - - if (crewMap.contains("Total")) { totalPlayers = crewMap["Total"].toInt(); } - - if (crewMap.contains("Members")) - { - QList<QVariant> memberList = crewMap["Members"].toList(); - foreach (const QVariant &memberVariant, memberList) - { - QMap<QString, QVariant> memberMap = memberVariant.toMap(); - foundPlayers++; - if (memberMap.contains("RockstarId") && memberMap.contains("Name")) - { - int RockstarId = memberMap["RockstarId"].toInt(); - QString memberName = memberMap["Name"].toString(); - if (memberName != "" && RockstarId != 0) - { - emit playerNameFound(RockstarId, memberName); - } - } - } - } - - QEventLoop *waitingLoop = new QEventLoop(); - QTimer::singleShot(requestDelay, waitingLoop, SLOT(quit())); - QObject::connect(this, SIGNAL(threadEndCommited()), waitingLoop, SLOT(quit())); - waitingLoop->exec(); - delete waitingLoop; - - currentPage++; - } - - delete netReply; - delete netManager; - } - } - } -} - -void DatabaseThread::doEndThread() -{ - threadRunning = false; - emit threadEndCommited(); -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "DatabaseThread.h" +#include "CrewDatabase.h" +#include "AppEnv.h" +#include <QNetworkAccessManager> +#include <QNetworkRequest> +#include <QNetworkReply> +#include <QJsonDocument> +#include <QJsonObject> +#include <QStringList> +#include <QVariantMap> +#include <QEventLoop> +#include <QTimer> +#include <QDebug> +#include <QUrl> + +#define crewMaxPages 83 + +DatabaseThread::DatabaseThread(CrewDatabase *crewDB, QObject *parent) : QThread(parent), crewDB(crewDB) +{ + threadRunning = true; +} + +void DatabaseThread::run() +{ + QEventLoop threadLoop; + + QStringList crewList; + QStringList crewListR; + + // Register thread loop end signal + QObject::connect(this, SIGNAL(threadEndCommited()), &threadLoop, SLOT(quit())); + + // Setup crewList for Quick time scan + crewList = crewDB->getCrews(); + if (!crewList.isEmpty()) + { + crewListR = deleteCompatibleCrews(crewList); + } + else + { + while (crewList.isEmpty() && threadRunning) + { + QTimer::singleShot(1000, &threadLoop, SLOT(quit())); + threadLoop.exec(); + if (!crewDB->isAddingCrews()) + { + crewList = crewDB->getCrews(); + } + } + if (threadRunning) + { + crewListR = deleteCompatibleCrews(crewList); + } + } + + // Only do QTS when Thread should be run + if (threadRunning) + { + // Quick time scan +#ifdef GTA5SYNC_DEBUG + qDebug() << "Start QTS"; +#endif + if (crewListR.length() <= 5) + { + scanCrewReference(crewListR, 2500); + emit crewNameUpdated(); + } + if (crewList.length() <= 3) + { + scanCrewMembersList(crewList, 3, 2500); + emit playerNameUpdated(); + } + else if (crewList.length() <= 5) + { + scanCrewMembersList(crewList, 2, 2500); + emit playerNameUpdated(); + } + + if (threadRunning) + { + QTimer::singleShot(10000, &threadLoop, SLOT(quit())); + threadLoop.exec(); + } + } + + while (threadRunning) + { + crewList = crewDB->getCrews(); + crewListR = deleteCompatibleCrews(crewList); + + // Long time scan +#ifdef GTA5SYNC_DEBUG + qDebug() << "Start LTS"; +#endif + scanCrewReference(crewListR, 10000); + emit crewNameUpdated(); + scanCrewMembersList(crewList, crewMaxPages, 10000); + emit playerNameUpdated(); + + if (threadRunning) + { + QTimer::singleShot(300000, &threadLoop, SLOT(quit())); + threadLoop.exec(); + } + } +} + +void DatabaseThread::scanCrewReference(const QStringList &crewList, const int &requestDelay) +{ + foreach (const QString &crewID, crewList) + { + if (threadRunning && crewID != "0") + { + QNetworkAccessManager *netManager = new QNetworkAccessManager(); + + QNetworkRequest netRequest(AppEnv::getCrewFetchingUrl(crewID)); +#if QT_VERSION >= 0x050600 + netRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); +#endif + netRequest.setRawHeader("User-Agent", AppEnv::getUserAgent()); + netRequest.setRawHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); + netRequest.setRawHeader("Accept-Language", "en-US;q=0.5,en;q=0.3"); + netRequest.setRawHeader("Connection", "keep-alive"); + + QNetworkReply *netReply = netManager->get(netRequest); + + QEventLoop *downloadLoop = new QEventLoop(); + QObject::connect(netReply, SIGNAL(finished()), downloadLoop, SLOT(quit())); + QObject::connect(this, SIGNAL(threadEndCommited()), downloadLoop, SLOT(quit())); + QTimer::singleShot(30000, downloadLoop, SLOT(quit())); + downloadLoop->exec(); + delete downloadLoop; + + if (netReply->isFinished()) + { + QString crewName; + QByteArray crewHtml = netReply->readAll(); + QStringList crewHtmlSplit1 = QString::fromUtf8(crewHtml).split("<title>Rockstar Games Social Club - Crew : "); + if (crewHtmlSplit1.length() >= 2) + { + QStringList crewHtmlSplit2 = QString(crewHtmlSplit1.at(1)).split("</title>"); + if (crewHtmlSplit2.length() >= 1) + { + crewName = crewHtmlSplit2.at(0); + } + } + if (!crewName.isEmpty()) + { + emit crewNameFound(crewID.toInt(), crewName); + } + } + + QEventLoop *waitingLoop = new QEventLoop(); + QTimer::singleShot(requestDelay, waitingLoop, SLOT(quit())); + QObject::connect(this, SIGNAL(threadEndCommited()), waitingLoop, SLOT(quit())); + waitingLoop->exec(); + delete waitingLoop; + + delete netReply; + delete netManager; + } + } +} + +void DatabaseThread::scanCrewMembersList(const QStringList &crewList, const int &maxPages, const int &requestDelay) +{ + foreach (const QString &crewID, crewList) + { + if (threadRunning && crewID != "0") + { + int currentPage = 0; + int foundPlayers = 0; + int totalPlayers = 1000; + + while(foundPlayers < totalPlayers && currentPage < maxPages) + { + QNetworkAccessManager *netManager = new QNetworkAccessManager(); + + QNetworkRequest netRequest(AppEnv::getPlayerFetchingUrl(crewID, currentPage)); +#if QT_VERSION >= 0x050600 + netRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); +#endif + netRequest.setRawHeader("User-Agent", AppEnv::getUserAgent()); + netRequest.setRawHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); + netRequest.setRawHeader("Accept-Language", "en-US;q=0.5,en;q=0.3"); + netRequest.setRawHeader("Connection", "keep-alive"); + + QNetworkReply *netReply = netManager->get(netRequest); + + QEventLoop *downloadLoop = new QEventLoop(); + QObject::connect(netReply, SIGNAL(finished()), downloadLoop, SLOT(quit())); + QObject::connect(this, SIGNAL(threadEndCommited()), downloadLoop, SLOT(quit())); + QTimer::singleShot(30000, downloadLoop, SLOT(quit())); + downloadLoop->exec(); + delete downloadLoop; + + if (netReply->isFinished()) + { + QByteArray crewJson = netReply->readAll(); + QJsonDocument crewDocument = QJsonDocument::fromJson(crewJson); + QJsonObject crewObject = crewDocument.object(); + QVariantMap crewMap = crewObject.toVariantMap(); + + if (crewMap.contains("Total")) { totalPlayers = crewMap["Total"].toInt(); } + + if (crewMap.contains("Members")) + { + QList<QVariant> memberList = crewMap["Members"].toList(); + foreach (const QVariant &memberVariant, memberList) + { + QMap<QString, QVariant> memberMap = memberVariant.toMap(); + foundPlayers++; + if (memberMap.contains("RockstarId") && memberMap.contains("Name")) + { + int RockstarId = memberMap["RockstarId"].toInt(); + QString memberName = memberMap["Name"].toString(); + if (memberName != "" && RockstarId != 0) + { + emit playerNameFound(RockstarId, memberName); + } + } + } + } + + QEventLoop *waitingLoop = new QEventLoop(); + QTimer::singleShot(requestDelay, waitingLoop, SLOT(quit())); + QObject::connect(this, SIGNAL(threadEndCommited()), waitingLoop, SLOT(quit())); + waitingLoop->exec(); + delete waitingLoop; + + currentPage++; + } + + delete netReply; + delete netManager; + } + } + } +} + +QStringList DatabaseThread::deleteCompatibleCrews(const QStringList &crewList) +{ + QStringList crewListR = crewList; + foreach(const QString &crewNID, crewListR) + { + if (crewDB->isCompatibleCrew(crewNID)) + { + crewListR.removeAll(crewNID); + } + } + return crewListR; +} + +void DatabaseThread::doEndThread() +{ + threadRunning = false; + emit threadEndCommited(); +} diff --git a/DatabaseThread.h b/DatabaseThread.h index 0009291..10a3b47 100755 --- a/DatabaseThread.h +++ b/DatabaseThread.h @@ -1,52 +1,54 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef DATABASETHREAD_H -#define DATABASETHREAD_H - -#include "CrewDatabase.h" -#include <QObject> -#include <QThread> - -class DatabaseThread : public QThread -{ - Q_OBJECT -public: - explicit DatabaseThread(CrewDatabase *crewDB, QObject *parent = 0); - -public slots: - void doEndThread(); - -private: - CrewDatabase *crewDB; - void scanCrewMembersList(QStringList crewList, int maxPages, int requestDelay); - void scanCrewReference(QStringList crewList, int requestDelay); - bool threadRunning; - int crewMaxPages; - int plyrPerReq; - -protected: - void run(); - -signals: - void playerNameFound(int playerID, QString playerName); - void playerNameUpdated(); - void threadEndCommited(); -}; - -#endif // DATABASETHREAD_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef DATABASETHREAD_H +#define DATABASETHREAD_H + +#include "CrewDatabase.h" +#include <QObject> +#include <QThread> + +class DatabaseThread : public QThread +{ + Q_OBJECT +public: + explicit DatabaseThread(CrewDatabase *crewDB, QObject *parent = 0); + +public slots: + void doEndThread(); + +private: + CrewDatabase *crewDB; + void scanCrewMembersList(const QStringList &crewList, const int &maxPages, const int &requestDelay); + void scanCrewReference(const QStringList &crewList, const int &requestDelay); + QStringList deleteCompatibleCrews(const QStringList &crewList); + bool threadRunning; + int plyrPerReq; + +protected: + void run(); + +signals: + void crewNameFound(int crewID, QString crewName); + void crewNameUpdated(); + void playerNameFound(int playerID, QString playerName); + void playerNameUpdated(); + void threadEndCommited(); +}; + +#endif // DATABASETHREAD_H diff --git a/ExportDialog.cpp b/ExportDialog.cpp index 6210ea3..9a93c58 100755 --- a/ExportDialog.cpp +++ b/ExportDialog.cpp @@ -1,48 +1,48 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "ExportDialog.h" -#include "ui_ExportDialog.h" - -ExportDialog::ExportDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::ExportDialog) -{ - ui->setupUi(this); - success = false; -} - -ExportDialog::~ExportDialog() -{ - delete ui; -} - -bool ExportDialog::isSucceeded() -{ - return success; -} - -void ExportDialog::on_cmdSnapmaticClose_clicked() -{ - this->close(); -} - -void ExportDialog::setupPictureExport() -{ - ui->swExport->setCurrentWidget(ui->pageSnapmatic); -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "ExportDialog.h" +#include "ui_ExportDialog.h" + +ExportDialog::ExportDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::ExportDialog) +{ + ui->setupUi(this); + success = false; +} + +ExportDialog::~ExportDialog() +{ + delete ui; +} + +bool ExportDialog::isSucceeded() +{ + return success; +} + +void ExportDialog::on_cmdSnapmaticClose_clicked() +{ + this->close(); +} + +void ExportDialog::setupPictureExport() +{ + ui->swExport->setCurrentWidget(ui->pageSnapmatic); +} diff --git a/ExportDialog.h b/ExportDialog.h index cf5a5cd..65354f0 100755 --- a/ExportDialog.h +++ b/ExportDialog.h @@ -1,46 +1,46 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef EXPORTDIALOG_H -#define EXPORTDIALOG_H - -#include <QDialog> - -namespace Ui { -class ExportDialog; -} - -class ExportDialog : public QDialog -{ - Q_OBJECT - -public: - explicit ExportDialog(QWidget *parent = 0); - void setupPictureExport(); - bool isSucceeded(); - ~ExportDialog(); - -private slots: - void on_cmdSnapmaticClose_clicked(); - -private: - Ui::ExportDialog *ui; - bool success; -}; - -#endif // EXPORTDIALOG_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef EXPORTDIALOG_H +#define EXPORTDIALOG_H + +#include <QDialog> + +namespace Ui { +class ExportDialog; +} + +class ExportDialog : public QDialog +{ + Q_OBJECT + +public: + explicit ExportDialog(QWidget *parent = 0); + void setupPictureExport(); + bool isSucceeded(); + ~ExportDialog(); + +private slots: + void on_cmdSnapmaticClose_clicked(); + +private: + Ui::ExportDialog *ui; + bool success; +}; + +#endif // EXPORTDIALOG_H diff --git a/ExportDialog.ui b/ExportDialog.ui index 6e8c254..d00b208 100755 --- a/ExportDialog.ui +++ b/ExportDialog.ui @@ -1,226 +1,226 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>ExportDialog</class> - <widget class="QDialog" name="ExportDialog"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>400</width> - <height>300</height> - </rect> - </property> - <property name="windowTitle"> - <string>Dialog</string> - </property> - <property name="modal"> - <bool>true</bool> - </property> - <layout class="QVBoxLayout" name="vlExport"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QStackedWidget" name="swExport"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <widget class="QWidget" name="pageSnapmatic"> - <layout class="QVBoxLayout" name="vlSnapmatic"> - <item> - <widget class="QGroupBox" name="gbSnapmaticFormat"> - <property name="title"> - <string>Export Format</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <widget class="QRadioButton" name="rbSystemPicture"> - <property name="text"> - <string>&JPEG/PNG format</string> - </property> - </widget> - </item> - <item> - <widget class="QRadioButton" name="rbSnapmaticPicture"> - <property name="text"> - <string>GTA &Snapmatic format</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="gbSnapmaticResolution"> - <property name="title"> - <string>Export Size</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_2"> - <item> - <widget class="QRadioButton" name="rbSnapmaticDefaultSize"> - <property name="text"> - <string>Default &Size</string> - </property> - </widget> - </item> - <item> - <widget class="QRadioButton" name="rbSnapmaticDesktopSize"> - <property name="text"> - <string>&Desktop Size</string> - </property> - </widget> - </item> - <item> - <widget class="QRadioButton" name="rbSnapmaticCustomSize"> - <property name="text"> - <string>&Custom Size</string> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="hlSnapmaticResolution"> - <item> - <widget class="QLabel" name="labSnapmaticResolutionSize"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="text"> - <string>Custom Size:</string> - </property> - </widget> - </item> - <item> - <widget class="QSpinBox" name="sbSnapmaticResoulutionWidth"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="minimum"> - <number>1</number> - </property> - <property name="maximum"> - <number>3840</number> - </property> - <property name="value"> - <number>960</number> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="labSnapmaticResolutionSizeX"> - <property name="text"> - <string>x</string> - </property> - </widget> - </item> - <item> - <widget class="QSpinBox" name="sbSnapmaticResoulutionHeight"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="minimum"> - <number>1</number> - </property> - <property name="maximum"> - <number>2160</number> - </property> - <property name="value"> - <number>536</number> - </property> - </widget> - </item> - <item> - <spacer name="hsSnapmaticResolution"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - </layout> - </widget> - </item> - <item> - <spacer name="vsSnapmatic"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <layout class="QHBoxLayout" name="hlSnapmaticButtons"> - <item> - <spacer name="hsSnapmaticButtons"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="cmdSnapmaticExport"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>&Export</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="cmdSnapmaticClose"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>&Close</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - <widget class="QWidget" name="pageSavegame"/> - </widget> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ExportDialog</class> + <widget class="QDialog" name="ExportDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <property name="modal"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="vlExport"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QStackedWidget" name="swExport"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <widget class="QWidget" name="pageSnapmatic"> + <layout class="QVBoxLayout" name="vlSnapmatic"> + <item> + <widget class="QGroupBox" name="gbSnapmaticFormat"> + <property name="title"> + <string>Export Format</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QRadioButton" name="rbSystemPicture"> + <property name="text"> + <string>&JPEG/PNG format</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="rbSnapmaticPicture"> + <property name="text"> + <string>GTA &Snapmatic format</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="gbSnapmaticResolution"> + <property name="title"> + <string>Export Size</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QRadioButton" name="rbSnapmaticDefaultSize"> + <property name="text"> + <string>Default &Size</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="rbSnapmaticDesktopSize"> + <property name="text"> + <string>&Desktop Size</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="rbSnapmaticCustomSize"> + <property name="text"> + <string>&Custom Size</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="hlSnapmaticResolution"> + <item> + <widget class="QLabel" name="labSnapmaticResolutionSize"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Custom Size:</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="sbSnapmaticResoulutionWidth"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>3840</number> + </property> + <property name="value"> + <number>960</number> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="labSnapmaticResolutionSizeX"> + <property name="text"> + <string>x</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="sbSnapmaticResoulutionHeight"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>2160</number> + </property> + <property name="value"> + <number>536</number> + </property> + </widget> + </item> + <item> + <spacer name="hsSnapmaticResolution"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="vsSnapmatic"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QHBoxLayout" name="hlSnapmaticButtons"> + <item> + <spacer name="hsSnapmaticButtons"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="cmdSnapmaticExport"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Export</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="cmdSnapmaticClose"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Close</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <widget class="QWidget" name="pageSavegame"/> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/ExportThread.cpp b/ExportThread.cpp index 5c39bc0..05af7db 100755 --- a/ExportThread.cpp +++ b/ExportThread.cpp @@ -1,184 +1,185 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "SnapmaticPicture.h" -#include "ProfileInterface.h" -#include "PictureExport.h" -#include "ProfileWidget.h" -#include "ExportThread.h" -#include "SavegameData.h" -#include "config.h" -#include <QDesktopWidget> -#include <QApplication> -#include <QFileInfo> -#include <QDebug> -#include <QFile> - -ExportThread::ExportThread(QMap<ProfileWidget*,QString> profileMap, QString exportDirectory, bool pictureCopyEnabled, bool pictureExportEnabled, int exportCount, QObject *parent) : QThread(parent), - profileMap(profileMap), exportDirectory(exportDirectory), pictureCopyEnabled(pictureCopyEnabled), pictureExportEnabled(pictureExportEnabled), exportCount(exportCount) -{ - -} - -void ExportThread::run() -{ - QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); - - // Picture Settings - // Quality Settings - settings.beginGroup("Pictures"); - int defaultQuality = 100; - QSize defExportSize = QSize(960, 536); - int customQuality = settings.value("CustomQuality", defaultQuality).toInt(); - if (customQuality < 1 || customQuality > 100) - { - customQuality = 100; - } - bool useCustomQuality = settings.value("CustomQualityEnabled", false).toBool(); - - // Size Settings - QSize cusExportSize = settings.value("CustomSize", defExportSize).toSize(); - if (cusExportSize.width() > 3840) - { - cusExportSize.setWidth(3840); - } - else if (cusExportSize.height() > 2160) - { - cusExportSize.setHeight(2160); - } - if (cusExportSize.width() < 1) - { - cusExportSize.setWidth(1); - } - else if (cusExportSize.height() < 1) - { - cusExportSize.setHeight(1); - } - QString sizeMode = settings.value("ExportSizeMode", "Default").toString(); - Qt::AspectRatioMode aspectRatio = (Qt::AspectRatioMode)settings.value("AspectRatio", Qt::KeepAspectRatio).toInt(); - settings.endGroup(); - // End Picture Settings - - int intExportProgress = 0; - foreach(ProfileWidget *widget, profileMap.keys()) - { - if (widget->isSelected()) - { - if (widget->getWidgetType() == "SnapmaticWidget") - { - SnapmaticWidget *picWidget = (SnapmaticWidget*)widget; - SnapmaticPicture *picture = picWidget->getPicture(); - - if (pictureExportEnabled) - { - QString exportFileName = PictureExport::getPictureFileName(picture); - if (exportFileName.right(4) != ".jpg" && exportFileName.right(4) != ".png") - { - exportFileName.append(".jpg"); - } - - intExportProgress++; - emit exportStringUpdate(ProfileInterface::tr("Export file %1 of %2 files").arg(QString::number(intExportProgress), QString::number(exportCount))); - emit exportProgressUpdate(intExportProgress); - - // Scale Picture - QImage exportPicture = picture->getImage(); - if (sizeMode == "Desktop") - { - QRect desktopResolution = QApplication::desktop()->screenGeometry(); - exportPicture = exportPicture.scaled(desktopResolution.width(), desktopResolution.height(), aspectRatio, Qt::SmoothTransformation); - } - else if (sizeMode == "Custom") - { - exportPicture = exportPicture.scaled(cusExportSize, aspectRatio, Qt::SmoothTransformation); - } - - bool isSaved; - if (useCustomQuality) - { - isSaved = exportPicture.save(exportDirectory + "/" + exportFileName, "JPEG", customQuality); - } - else - { - isSaved = exportPicture.save(exportDirectory + "/" + exportFileName, "JPEG", 100); - } - - if (!isSaved) - { - failedExportPictures.append(exportFileName); - } - } - if (pictureCopyEnabled) - { - QString exportFileName = PictureExport::getPictureFileName(picture); - if (exportFileName.right(4) != ".g5e") - { - exportFileName.append(".g5e"); - } - - intExportProgress++; - emit exportStringUpdate(ProfileInterface::tr("Export file %1 of %2 files").arg(QString::number(intExportProgress), QString::number(exportCount))); - emit exportProgressUpdate(intExportProgress); - - QString exportFilePath = exportDirectory + "/" + exportFileName; - if (QFile::exists(exportFilePath)) {QFile::remove(exportFilePath);} - if (!picture->exportPicture(exportDirectory + "/" + exportFileName, "G5E")) - { - failedCopyPictures.append(exportFileName); - } - } - } - else if (widget->getWidgetType() == "SavegameWidget") - { - SavegameWidget *sgdWidget = (SavegameWidget*)widget; - SavegameData *savegame = sgdWidget->getSavegame(); - - QString originalFileName = savegame->getSavegameFileName(); - QFileInfo originalFileInfo(originalFileName); - QString exportFileName = originalFileInfo.fileName(); - - intExportProgress++; - emit exportStringUpdate(ProfileInterface::tr("Export file %1 of %2 files").arg(QString::number(intExportProgress), QString::number(exportCount))); - emit exportProgressUpdate(intExportProgress); - - QString exportFilePath = exportDirectory + "/" + exportFileName; - if (QFile::exists(exportFilePath)) {QFile::remove(exportFilePath);} - if (!QFile::copy(originalFileName, exportFilePath)) - { - failedSavegames.append(exportFileName); - } - } - } - } - emit exportFinished(); -} - -QStringList ExportThread::getFailedCopyPictures() -{ - return failedCopyPictures; -} - -QStringList ExportThread::getFailedExportPictures() -{ - return failedExportPictures; -} - -QStringList ExportThread::getFailedSavegames() -{ - return failedSavegames; -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "SnapmaticPicture.h" +#include "ProfileInterface.h" +#include "PictureExport.h" +#include "ProfileWidget.h" +#include "ExportThread.h" +#include "SavegameData.h" +#include "config.h" +#include <QStringBuilder> +#include <QDesktopWidget> +#include <QApplication> +#include <QFileInfo> +#include <QDebug> +#include <QFile> + +ExportThread::ExportThread(QMap<ProfileWidget*,QString> profileMap, QString exportDirectory, bool pictureCopyEnabled, bool pictureExportEnabled, int exportCount, QObject *parent) : QThread(parent), + profileMap(profileMap), exportDirectory(exportDirectory), pictureCopyEnabled(pictureCopyEnabled), pictureExportEnabled(pictureExportEnabled), exportCount(exportCount) +{ + +} + +void ExportThread::run() +{ + QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); + + // Picture Settings + // Quality Settings + settings.beginGroup("Pictures"); + int defaultQuality = 100; + QSize defExportSize = QSize(960, 536); + int customQuality = settings.value("CustomQuality", defaultQuality).toInt(); + if (customQuality < 1 || customQuality > 100) + { + customQuality = 100; + } + bool useCustomQuality = settings.value("CustomQualityEnabled", false).toBool(); + + // Size Settings + QSize cusExportSize = settings.value("CustomSize", defExportSize).toSize(); + if (cusExportSize.width() > 3840) + { + cusExportSize.setWidth(3840); + } + else if (cusExportSize.height() > 2160) + { + cusExportSize.setHeight(2160); + } + if (cusExportSize.width() < 1) + { + cusExportSize.setWidth(1); + } + else if (cusExportSize.height() < 1) + { + cusExportSize.setHeight(1); + } + QString sizeMode = settings.value("ExportSizeMode", "Default").toString(); + Qt::AspectRatioMode aspectRatio = (Qt::AspectRatioMode)settings.value("AspectRatio", Qt::KeepAspectRatio).toInt(); + settings.endGroup(); + // End Picture Settings + + int intExportProgress = 0; + foreach(ProfileWidget *widget, profileMap.keys()) + { + if (widget->isSelected()) + { + if (widget->getWidgetType() == "SnapmaticWidget") + { + SnapmaticWidget *picWidget = qobject_cast<SnapmaticWidget*>(widget); + SnapmaticPicture *picture = picWidget->getPicture(); + + if (pictureExportEnabled) + { + QString exportFileName = PictureExport::getPictureFileName(picture); + if (exportFileName.right(4) != ".jpg" && exportFileName.right(4) != ".png") + { + exportFileName += ".jpg"; + } + + intExportProgress++; + emit exportStringUpdate(ProfileInterface::tr("Export file %1 of %2 files").arg(QString::number(intExportProgress), QString::number(exportCount))); + emit exportProgressUpdate(intExportProgress); + + // Scale Picture + QImage exportPicture = picture->getImage(); + if (sizeMode == "Desktop") + { + QRect desktopResolution = qApp->desktop()->screenGeometry(); + exportPicture = exportPicture.scaled(desktopResolution.width(), desktopResolution.height(), aspectRatio, Qt::SmoothTransformation); + } + else if (sizeMode == "Custom") + { + exportPicture = exportPicture.scaled(cusExportSize, aspectRatio, Qt::SmoothTransformation); + } + + bool isSaved; + if (useCustomQuality) + { + isSaved = exportPicture.save(exportDirectory % "/" % exportFileName, "JPEG", customQuality); + } + else + { + isSaved = exportPicture.save(exportDirectory % "/" % exportFileName, "JPEG", 100); + } + + if (!isSaved) + { + failedExportPictures += exportFileName; + } + } + if (pictureCopyEnabled) + { + QString exportFileName = PictureExport::getPictureFileName(picture); + if (exportFileName.right(4) != ".g5e") + { + exportFileName += ".g5e"; + } + + intExportProgress++; + emit exportStringUpdate(ProfileInterface::tr("Export file %1 of %2 files").arg(QString::number(intExportProgress), QString::number(exportCount))); + emit exportProgressUpdate(intExportProgress); + + QString exportFilePath = exportDirectory % "/" % exportFileName; + if (QFile::exists(exportFilePath)) {QFile::remove(exportFilePath);} + if (!picture->exportPicture(exportDirectory % "/" % exportFileName, SnapmaticFormat::G5E_Format)) + { + failedCopyPictures += exportFileName; + } + } + } + else if (widget->getWidgetType() == "SavegameWidget") + { + SavegameWidget *sgdWidget = qobject_cast<SavegameWidget*>(widget); + SavegameData *savegame = sgdWidget->getSavegame(); + + QString originalFileName = savegame->getSavegameFileName(); + QFileInfo originalFileInfo(originalFileName); + QString exportFileName = originalFileInfo.fileName(); + + intExportProgress++; + emit exportStringUpdate(ProfileInterface::tr("Export file %1 of %2 files").arg(QString::number(intExportProgress), QString::number(exportCount))); + emit exportProgressUpdate(intExportProgress); + + QString exportFilePath = exportDirectory % "/" % exportFileName; + if (QFile::exists(exportFilePath)) {QFile::remove(exportFilePath);} + if (!QFile::copy(originalFileName, exportFilePath)) + { + failedSavegames += exportFileName; + } + } + } + } + emit exportFinished(); +} + +QStringList ExportThread::getFailedCopyPictures() +{ + return failedCopyPictures; +} + +QStringList ExportThread::getFailedExportPictures() +{ + return failedExportPictures; +} + +QStringList ExportThread::getFailedSavegames() +{ + return failedSavegames; +} diff --git a/ExportThread.h b/ExportThread.h index ecd0cd7..f5837a7 100755 --- a/ExportThread.h +++ b/ExportThread.h @@ -1,56 +1,56 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef EXPORTTHREAD_H -#define EXPORTTHREAD_H - -#include "SnapmaticWidget.h" -#include "SavegameWidget.h" -#include "ProfileWidget.h" -#include <QThread> -#include <QMap> - -class ExportThread : public QThread -{ - Q_OBJECT -public: - explicit ExportThread(QMap<ProfileWidget*,QString> profileMap, QString exportDirectory, bool pictureCopyEnabled, bool pictureExportEnabled, int exportCount, QObject *parent = 0); - QStringList getFailedSavegames(); - QStringList getFailedCopyPictures(); - QStringList getFailedExportPictures(); - -protected: - void run(); - -private: - QMap <ProfileWidget*, QString> profileMap; - QString exportDirectory; - bool pictureCopyEnabled; - bool pictureExportEnabled; - int exportCount; - QStringList failedSavegames; - QStringList failedCopyPictures; - QStringList failedExportPictures; - -signals: - void exportStringUpdate(QString currentFileName); - void exportProgressUpdate(int currentProgressValue); - void exportFinished(); -}; - -#endif // EXPORTTHREAD_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef EXPORTTHREAD_H +#define EXPORTTHREAD_H + +#include "SnapmaticWidget.h" +#include "SavegameWidget.h" +#include "ProfileWidget.h" +#include <QThread> +#include <QMap> + +class ExportThread : public QThread +{ + Q_OBJECT +public: + explicit ExportThread(QMap<ProfileWidget*,QString> profileMap, QString exportDirectory, bool pictureCopyEnabled, bool pictureExportEnabled, int exportCount, QObject *parent = 0); + QStringList getFailedSavegames(); + QStringList getFailedCopyPictures(); + QStringList getFailedExportPictures(); + +protected: + void run(); + +private: + QMap <ProfileWidget*, QString> profileMap; + QString exportDirectory; + bool pictureCopyEnabled; + bool pictureExportEnabled; + int exportCount; + QStringList failedSavegames; + QStringList failedCopyPictures; + QStringList failedExportPictures; + +signals: + void exportStringUpdate(QString currentFileName); + void exportProgressUpdate(int currentProgressValue); + void exportFinished(); +}; + +#endif // EXPORTTHREAD_H diff --git a/GlobalString.cpp b/GlobalString.cpp index 00289c3..fb94678 100755 --- a/GlobalString.cpp +++ b/GlobalString.cpp @@ -1,89 +1,85 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include <QLocale> -#include <QSettings> -#include <QFileInfo> -#include <QStringList> -#include "GlobalString.h" -#include "config.h" - -GlobalString::GlobalString() -{ - -} - -QMap<QString, QString> GlobalString::getGlobalMap() -{ - QMap<QString, QString> globalMap; - QSettings globalFile(getLanguageFile(), QSettings::IniFormat); - globalFile.setIniCodec("UTF-8"); - globalFile.beginGroup("Global"); - QStringList globalStrList = globalFile.childKeys(); - foreach(const QString &globalStr, globalStrList) - { - globalMap[globalStr] = globalFile.value(globalStr, globalStr).toString(); - } - globalFile.endGroup(); - return globalMap; -} - -QString GlobalString::getString(QString valueStr, bool *ok) -{ - QString globalString = valueStr; - QSettings globalFile(getLanguageFile(), QSettings::IniFormat); - globalFile.setIniCodec("UTF-8"); - globalFile.beginGroup("Global"); - QStringList globalStrList = globalFile.childKeys(); - if (globalStrList.contains(valueStr)) - { - if (ok != 0) *ok = true; - globalString = globalFile.value(valueStr, valueStr).toString(); - } - globalFile.endGroup(); - return globalString; -} - -QString GlobalString::getLanguageFile() -{ - QString language = getLanguage(); - QString languageFile = ":/global/global." + language + ".ini"; - if (!QFileInfo(languageFile).exists()) - { - languageFile = ":/global/global.en.ini"; - } - return languageFile; -} - -QString GlobalString::getLanguage() -{ - QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); - settings.beginGroup("Interface"); - QString language = settings.value("Language","System").toString(); - settings.endGroup(); - if (language == "System" || language.trimmed() == "") - { - QString languageName = QLocale::system().name(); - QStringList langList = languageName.split("_"); - if (langList.length() >= 1) - { - language = langList.at(0); - } - } - return language; -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "TranslationClass.h" +#include "GlobalString.h" +#include "config.h" +#include <QStringBuilder> +#include <QStringList> +#include <QFileInfo> +#include <QSettings> +#include <QLocale> +#include <QDebug> + +GlobalString::GlobalString() +{ + +} + +QMap<QString, QString> GlobalString::getGlobalMap() +{ + QMap<QString, QString> globalMap; + QSettings globalFile(getLanguageFile(), QSettings::IniFormat); + globalFile.setIniCodec("UTF-8"); + globalFile.beginGroup("Global"); + QStringList globalStrList = globalFile.childKeys(); + foreach(const QString &globalStr, globalStrList) + { + globalMap[globalStr] = globalFile.value(globalStr, globalStr).toString(); + } + globalFile.endGroup(); + return globalMap; +} + +QString GlobalString::getString(QString valueStr, bool *ok) +{ + QString globalString = valueStr; + QSettings globalFile(getLanguageFile(), QSettings::IniFormat); + globalFile.setIniCodec("UTF-8"); + globalFile.beginGroup("Global"); + QStringList globalStrList = globalFile.childKeys(); + if (globalStrList.contains(valueStr)) + { + if (ok != NULL) *ok = true; + globalString = globalFile.value(valueStr, valueStr).toString(); + } + globalFile.endGroup(); + return globalString; +} + +QString GlobalString::getLanguageFile() +{ + QString language = getLanguage(); + QString languageFile = ":/global/global." % language % ".ini"; + if (!QFileInfo(languageFile).exists()) + { + languageFile = ":/global/global.en.ini"; + } + return languageFile; +} + +QString GlobalString::getLanguage() +{ + QString language = TCInstance->getCurrentLanguage(); + QStringList langList = QString(language).replace("-", "_").split("_"); + if (langList.length() >= 1) + { + language = langList.at(0); + } + return language; +} diff --git a/GlobalString.h b/GlobalString.h index c9b5bde..9c2d77c 100755 --- a/GlobalString.h +++ b/GlobalString.h @@ -1,35 +1,35 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef GLOBALSTRING_H -#define GLOBALSTRING_H - -#include <QString> -#include <QMap> - -class GlobalString -{ -public: - GlobalString(); - static QString getString(QString valueStr, bool *ok = 0); - static QString getLanguageFile(); - static QString getLanguage(); - static QMap<QString, QString> getGlobalMap(); -}; - -#endif // GLOBALSTRING_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef GLOBALSTRING_H +#define GLOBALSTRING_H + +#include <QString> +#include <QMap> + +class GlobalString +{ +public: + GlobalString(); + static QString getString(QString valueStr, bool *ok = 0); + static QString getLanguageFile(); + static QString getLanguage(); + static QMap<QString, QString> getGlobalMap(); +}; + +#endif // GLOBALSTRING_H diff --git a/IconLoader.cpp b/IconLoader.cpp index 13ef339..4de091d 100755 --- a/IconLoader.cpp +++ b/IconLoader.cpp @@ -1,40 +1,50 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "IconLoader.h" -#include <QIcon> - -IconLoader::IconLoader() -{ - -} - -QIcon IconLoader::loadingAppIcon() -{ - QIcon appIcon; - appIcon.addFile(":/img/5sync-16.png", QSize(16, 16)); - appIcon.addFile(":/img/5sync-24.png", QSize(24, 24)); - appIcon.addFile(":/img/5sync-32.png", QSize(32, 32)); - appIcon.addFile(":/img/5sync-40.png", QSize(40, 40)); - appIcon.addFile(":/img/5sync-48.png", QSize(48, 48)); - appIcon.addFile(":/img/5sync-64.png", QSize(64, 64)); - appIcon.addFile(":/img/5sync-96.png", QSize(96, 96)); - appIcon.addFile(":/img/5sync-128.png", QSize(128, 128)); - appIcon.addFile(":/img/5sync-256.png", QSize(256, 256)); - return appIcon; -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "IconLoader.h" +#include <QIcon> + +IconLoader::IconLoader() +{ + +} + +QIcon IconLoader::loadingAppIcon() +{ + QIcon appIcon; + appIcon.addFile(":/img/5sync-16.png", QSize(16, 16)); + appIcon.addFile(":/img/5sync-24.png", QSize(24, 24)); + appIcon.addFile(":/img/5sync-32.png", QSize(32, 32)); + appIcon.addFile(":/img/5sync-40.png", QSize(40, 40)); + appIcon.addFile(":/img/5sync-48.png", QSize(48, 48)); + appIcon.addFile(":/img/5sync-64.png", QSize(64, 64)); + appIcon.addFile(":/img/5sync-96.png", QSize(96, 96)); + appIcon.addFile(":/img/5sync-128.png", QSize(128, 128)); + appIcon.addFile(":/img/5sync-256.png", QSize(256, 256)); + return appIcon; +} + +QIcon IconLoader::loadingPointmakerIcon() +{ + QIcon pointmakerIcon; + pointmakerIcon.addFile(":/img/pointmaker-8.png", QSize(8, 8)); + pointmakerIcon.addFile(":/img/pointmaker-16.png", QSize(16, 16)); + pointmakerIcon.addFile(":/img/pointmaker-24.png", QSize(24, 24)); + pointmakerIcon.addFile(":/img/pointmaker-32.png", QSize(32, 32)); + return pointmakerIcon; +} diff --git a/IconLoader.h b/IconLoader.h index c7d5107..fe8669b 100755 --- a/IconLoader.h +++ b/IconLoader.h @@ -1,31 +1,32 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef ICONLOADER_H -#define ICONLOADER_H - -#include <QIcon> - -class IconLoader -{ -public: - IconLoader(); - static QIcon loadingAppIcon(); -}; - -#endif // ICONLOADER_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef ICONLOADER_H +#define ICONLOADER_H + +#include <QIcon> + +class IconLoader +{ +public: + IconLoader(); + static QIcon loadingAppIcon(); + static QIcon loadingPointmakerIcon(); +}; + +#endif // ICONLOADER_H diff --git a/ImportDialog.cpp b/ImportDialog.cpp index 19de296..5f485a1 100644 --- a/ImportDialog.cpp +++ b/ImportDialog.cpp @@ -1,190 +1,219 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "ImportDialog.h" -#include "ui_ImportDialog.h" -#include "AppEnv.h" -#include <QPainter> -#include <QPixmap> -#include <QImage> -#include <QDebug> - -// IMAGES VALUES -#define snapmaticResolutionW 960 -#define snapmaticResolutionH 536 -#define snapmaticAvatarResolution 470 -#define snapmaticAvatarPlacementW 145 -#define snapmaticAvatarPlacementH 66 - -ImportDialog::ImportDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::ImportDialog) -{ - ui->setupUi(this); - doImport = false; - avatarAreaImage = QImage(":/img/avatarareaimport.png"); - - if (QIcon::hasThemeIcon("dialog-ok")) - { - ui->cmdOK->setIcon(QIcon::fromTheme("dialog-ok")); - } - if (QIcon::hasThemeIcon("dialog-cancel")) - { - ui->cmdCancel->setIcon(QIcon::fromTheme("dialog-cancel")); - } - - ui->rbKeep->setChecked(true); - - qreal screenRatio = AppEnv::screenRatio(); - snapmaticResolutionLW = 430 * screenRatio; - snapmaticResolutionLH = 240 * screenRatio; - setMinimumSize(430 * screenRatio, 380 * screenRatio); - setMaximumSize(430 * screenRatio, 380 * screenRatio); - setFixedSize(430 * screenRatio, 380 * screenRatio); - ui->vlButtom->setSpacing(6 * screenRatio); - ui->vlButtom->setContentsMargins(9 * screenRatio, 6 * screenRatio, 9 * screenRatio, 9 * screenRatio); -} - -ImportDialog::~ImportDialog() -{ - delete ui; -} - -void ImportDialog::processImage() -{ - QImage snapmaticImage = workImage; - QPixmap snapmaticPixmap(snapmaticResolutionW, snapmaticResolutionH); - snapmaticPixmap.fill(Qt::black); - QPainter snapmaticPainter(&snapmaticPixmap); - if (ui->cbAvatar->isChecked()) - { - // Avatar mode - int diffWidth = 0; - int diffHeight = 0; - if (ui->rbKeep->isChecked()) - { - snapmaticImage = snapmaticImage.scaled(snapmaticAvatarResolution, snapmaticAvatarResolution, Qt::KeepAspectRatio, Qt::SmoothTransformation); - if (snapmaticImage.width() > snapmaticImage.height()) - { - diffHeight = snapmaticAvatarResolution - snapmaticImage.height(); - diffHeight = diffHeight / 2; - } - else if (snapmaticImage.width() < snapmaticImage.height()) - { - diffWidth = snapmaticAvatarResolution - snapmaticImage.width(); - diffWidth = diffWidth / 2; - } - } - else - { - snapmaticImage = snapmaticImage.scaled(snapmaticAvatarResolution, snapmaticAvatarResolution, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); - } - snapmaticPainter.drawImage(snapmaticAvatarPlacementW + diffWidth, snapmaticAvatarPlacementH + diffHeight, snapmaticImage); - imageTitle = "Custom Avatar"; - } - else - { - // Picture mode - int diffWidth = 0; - int diffHeight = 0; - if (ui->rbKeep->isChecked()) - { - snapmaticImage = snapmaticImage.scaled(snapmaticResolutionW, snapmaticResolutionH, Qt::KeepAspectRatio, Qt::SmoothTransformation); - if (snapmaticImage.width() != snapmaticResolutionW) - { - diffWidth = snapmaticResolutionW - snapmaticImage.width(); - diffWidth = diffWidth / 2; - } - else if (snapmaticImage.height() != snapmaticResolutionH) - { - diffHeight = snapmaticResolutionH - snapmaticImage.height(); - diffHeight = diffHeight / 2; - } - } - else - { - snapmaticImage = snapmaticImage.scaled(snapmaticResolutionW, snapmaticResolutionH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); - } - snapmaticPainter.drawImage(0 + diffWidth, 0 + diffHeight, snapmaticImage); - imageTitle = "Custom Picture"; - } - snapmaticPainter.end(); - newImage = snapmaticPixmap.toImage(); - ui->labPicture->setPixmap(snapmaticPixmap.scaled(snapmaticResolutionLW, snapmaticResolutionLH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); -} - -QImage ImportDialog::image() -{ - return newImage; -} - -void ImportDialog::setImage(const QImage &image_) -{ - workImage = image_; - if (workImage.width() == workImage.height()) - { - ui->cbAvatar->setChecked(true); - } - processImage(); -} - -bool ImportDialog::isDoImport() -{ - return doImport; -} - -QString ImportDialog::getImageTitle() -{ - return imageTitle; -} - -void ImportDialog::on_rbIgnore_clicked() -{ - processImage(); -} - -void ImportDialog::on_rbKeep_clicked() -{ - processImage(); -} - -void ImportDialog::on_cbAvatar_clicked() -{ - processImage(); -} - -void ImportDialog::on_cmdCancel_clicked() -{ - close(); -} - -void ImportDialog::on_cmdOK_clicked() -{ - doImport = true; - close(); -} - -void ImportDialog::on_labPicture_labelPainted() -{ - if (ui->cbAvatar->isChecked()) - { - QPainter labelPainter(ui->labPicture); - labelPainter.drawImage(0, 0, avatarAreaImage.scaled(snapmaticResolutionLW, snapmaticResolutionLH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); - labelPainter.end(); - } -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "ImportDialog.h" +#include "ui_ImportDialog.h" +#include "AppEnv.h" +#include <QColorDialog> +#include <QMessageBox> +#include <QPainter> +#include <QPixmap> +#include <QImage> +#include <QDebug> +#include <QRgb> + +// IMAGES VALUES +#define snapmaticResolutionW 960 +#define snapmaticResolutionH 536 +#define snapmaticAvatarResolution 470 +#define snapmaticAvatarPlacementW 145 +#define snapmaticAvatarPlacementH 66 + +ImportDialog::ImportDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::ImportDialog) +{ + ui->setupUi(this); + importAgreed = false; + insideAvatarZone = false; + avatarAreaImage = QImage(":/img/avatarareaimport.png"); + selectedColour = QColor::fromRgb(0, 0, 0, 255); + + if (QIcon::hasThemeIcon("dialog-ok")) + { + ui->cmdOK->setIcon(QIcon::fromTheme("dialog-ok")); + } + if (QIcon::hasThemeIcon("dialog-cancel")) + { + ui->cmdCancel->setIcon(QIcon::fromTheme("dialog-cancel")); + } + + ui->cbIgnore->setChecked(false); + ui->labColour->setText(tr("Background Colour: <span style=\"color: %1\">%1</span>").arg(selectedColour.name())); + + qreal screenRatio = AppEnv::screenRatio(); + snapmaticResolutionLW = 430 * screenRatio; + snapmaticResolutionLH = 240 * screenRatio; + setMinimumSize(430 * screenRatio, 380 * screenRatio); + setMaximumSize(430 * screenRatio, 380 * screenRatio); + setFixedSize(430 * screenRatio, 380 * screenRatio); + ui->vlButtom->setSpacing(6 * screenRatio); + ui->vlButtom->setContentsMargins(9 * screenRatio, 6 * screenRatio, 9 * screenRatio, 9 * screenRatio); +} + +ImportDialog::~ImportDialog() +{ + delete ui; +} + +void ImportDialog::processImage() +{ + QImage snapmaticImage = workImage; + QPixmap snapmaticPixmap(snapmaticResolutionW, snapmaticResolutionH); + snapmaticPixmap.fill(selectedColour); + QPainter snapmaticPainter(&snapmaticPixmap); + if (insideAvatarZone) + { + // Avatar mode + int diffWidth = 0; + int diffHeight = 0; + if (!ui->cbIgnore->isChecked()) + { + snapmaticImage = snapmaticImage.scaled(snapmaticAvatarResolution, snapmaticAvatarResolution, Qt::KeepAspectRatio, Qt::SmoothTransformation); + if (snapmaticImage.width() > snapmaticImage.height()) + { + diffHeight = snapmaticAvatarResolution - snapmaticImage.height(); + diffHeight = diffHeight / 2; + } + else if (snapmaticImage.width() < snapmaticImage.height()) + { + diffWidth = snapmaticAvatarResolution - snapmaticImage.width(); + diffWidth = diffWidth / 2; + } + } + else + { + snapmaticImage = snapmaticImage.scaled(snapmaticAvatarResolution, snapmaticAvatarResolution, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + } + snapmaticPainter.drawImage(snapmaticAvatarPlacementW + diffWidth, snapmaticAvatarPlacementH + diffHeight, snapmaticImage); + imageTitle = "Custom Avatar"; + } + else + { + // Picture mode + int diffWidth = 0; + int diffHeight = 0; + if (!ui->cbIgnore->isChecked()) + { + snapmaticImage = snapmaticImage.scaled(snapmaticResolutionW, snapmaticResolutionH, Qt::KeepAspectRatio, Qt::SmoothTransformation); + if (snapmaticImage.width() != snapmaticResolutionW) + { + diffWidth = snapmaticResolutionW - snapmaticImage.width(); + diffWidth = diffWidth / 2; + } + else if (snapmaticImage.height() != snapmaticResolutionH) + { + diffHeight = snapmaticResolutionH - snapmaticImage.height(); + diffHeight = diffHeight / 2; + } + } + else + { + snapmaticImage = snapmaticImage.scaled(snapmaticResolutionW, snapmaticResolutionH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + } + snapmaticPainter.drawImage(0 + diffWidth, 0 + diffHeight, snapmaticImage); + imageTitle = "Custom Picture"; + } + snapmaticPainter.end(); + newImage = snapmaticPixmap.toImage(); + ui->labPicture->setPixmap(snapmaticPixmap.scaled(snapmaticResolutionLW, snapmaticResolutionLH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); +} + +QImage ImportDialog::image() +{ + return newImage; +} + +void ImportDialog::setImage(const QImage &image_) +{ + workImage = image_; + if (workImage.width() == workImage.height()) + { + insideAvatarZone = true; + ui->cbAvatar->setChecked(true); + } + processImage(); +} + +bool ImportDialog::isImportAgreed() +{ + return importAgreed; +} + +QString ImportDialog::getImageTitle() +{ + return imageTitle; +} + +void ImportDialog::on_cbIgnore_toggled(bool checked) +{ + Q_UNUSED(checked) + processImage(); +} + +void ImportDialog::on_cbAvatar_toggled(bool checked) +{ + if (workImage.width() == workImage.height() && !checked) + { + if (QMessageBox::No == QMessageBox::warning(this, tr("Snapmatic Avatar Zone"), tr("Are you sure to use a square image outside of the Avatar Zone?\nWhen you want to use it as Avatar the image will be detached!"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No)) + { + ui->cbAvatar->setChecked(true); + insideAvatarZone = true; + return; + } + } + insideAvatarZone = ui->cbAvatar->isChecked(); + processImage(); +} + +void ImportDialog::on_cmdCancel_clicked() +{ + close(); +} + +void ImportDialog::on_cmdOK_clicked() +{ + importAgreed = true; + close(); +} + +void ImportDialog::on_labPicture_labelPainted() +{ + if (insideAvatarZone) + { + QImage avatarAreaFinalImage(avatarAreaImage); + if (selectedColour.lightness() > 127) + { + avatarAreaFinalImage.setColor(1, qRgb(0, 0, 0)); + } + QPainter labelPainter(ui->labPicture); + labelPainter.drawImage(0, 0, avatarAreaFinalImage.scaled(snapmaticResolutionLW, snapmaticResolutionLH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + labelPainter.end(); + } +} + +void ImportDialog::on_cmdColourChange_clicked() +{ + QColor newSelectedColour = QColorDialog::getColor(selectedColour, this, tr("Select Colour...")); + if (newSelectedColour.isValid()) + { + selectedColour = newSelectedColour; + ui->labColour->setText(tr("Background Colour: <span style=\"color: %1\">%1</span>").arg(selectedColour.name())); + processImage(); + } +} diff --git a/ImportDialog.h b/ImportDialog.h index 1da27fd..7953490 100644 --- a/ImportDialog.h +++ b/ImportDialog.h @@ -1,60 +1,62 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef IMPORTDIALOG_H -#define IMPORTDIALOG_H - -#include <QDialog> - -namespace Ui { -class ImportDialog; -} - -class ImportDialog : public QDialog -{ - Q_OBJECT - -public: - explicit ImportDialog(QWidget *parent = 0); - ~ImportDialog(); - QImage image(); - QString getImageTitle(); - void setImage(const QImage &image); - bool isDoImport(); - -private slots: - void processImage(); - void on_rbIgnore_clicked(); - void on_rbKeep_clicked(); - void on_cbAvatar_clicked(); - void on_cmdCancel_clicked(); - void on_cmdOK_clicked(); - void on_labPicture_labelPainted(); - -private: - Ui::ImportDialog *ui; - QImage avatarAreaImage; - QString imageTitle; - QImage workImage; - QImage newImage; - bool doImport; - int snapmaticResolutionLW; - int snapmaticResolutionLH; -}; - -#endif // IMPORTDIALOG_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef IMPORTDIALOG_H +#define IMPORTDIALOG_H + +#include <QDialog> + +namespace Ui { +class ImportDialog; +} + +class ImportDialog : public QDialog +{ + Q_OBJECT + +public: + explicit ImportDialog(QWidget *parent = 0); + ~ImportDialog(); + QImage image(); + QString getImageTitle(); + void setImage(const QImage &image); + bool isImportAgreed(); + +private slots: + void processImage(); + void on_cbIgnore_toggled(bool checked); + void on_cbAvatar_toggled(bool checked); + void on_cmdCancel_clicked(); + void on_cmdOK_clicked(); + void on_labPicture_labelPainted(); + void on_cmdColourChange_clicked(); + +private: + Ui::ImportDialog *ui; + QImage avatarAreaImage; + QString imageTitle; + QImage workImage; + QImage newImage; + QColor selectedColour; + bool insideAvatarZone; + bool importAgreed; + int snapmaticResolutionLW; + int snapmaticResolutionLH; +}; + +#endif // IMPORTDIALOG_H diff --git a/ImportDialog.ui b/ImportDialog.ui index dc42083..3f95cad 100644 --- a/ImportDialog.ui +++ b/ImportDialog.ui @@ -1,187 +1,239 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>ImportDialog</class> - <widget class="QDialog" name="ImportDialog"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>430</width> - <height>380</height> - </rect> - </property> - <property name="minimumSize"> - <size> - <width>430</width> - <height>380</height> - </size> - </property> - <property name="maximumSize"> - <size> - <width>430</width> - <height>380</height> - </size> - </property> - <property name="windowTitle"> - <string>Import...</string> - </property> - <property name="modal"> - <bool>true</bool> - </property> - <layout class="QVBoxLayout" name="vlImport"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="UiModLabel" name="labPicture"> - <property name="minimumSize"> - <size> - <width>430</width> - <height>240</height> - </size> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item> - <widget class="QFrame" name="buttomFrame"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Plain</enum> - </property> - <property name="lineWidth"> - <number>0</number> - </property> - <layout class="QVBoxLayout" name="vlButtom"> - <property name="leftMargin"> - <number>9</number> - </property> - <property name="topMargin"> - <number>6</number> - </property> - <property name="rightMargin"> - <number>9</number> - </property> - <property name="bottomMargin"> - <number>9</number> - </property> - <item> - <widget class="QGroupBox" name="gbSettings"> - <property name="title"> - <string>Settings</string> - </property> - <layout class="QGridLayout" name="gdSettings"> - <item row="1" column="0"> - <widget class="QRadioButton" name="rbKeep"> - <property name="text"> - <string>&Keep Aspect Ratio</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QRadioButton" name="rbIgnore"> - <property name="text"> - <string>&Ignore Aspect Ratio</string> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QCheckBox" name="cbAvatar"> - <property name="text"> - <string>&Avatar</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <spacer name="vsDialog"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <layout class="QHBoxLayout" name="hlButtons"> - <item> - <spacer name="hsButtons"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="cmdOK"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>&OK</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="cmdCancel"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>&Cancel</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - <customwidgets> - <customwidget> - <class>UiModLabel</class> - <extends>QLabel</extends> - <header>UiModLabel.h</header> - </customwidget> - </customwidgets> - <resources/> - <connections/> -</ui> +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ImportDialog</class> + <widget class="QDialog" name="ImportDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>430</width> + <height>380</height> + </rect> + </property> + <property name="minimumSize"> + <size> + <width>430</width> + <height>380</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>430</width> + <height>380</height> + </size> + </property> + <property name="windowTitle"> + <string>Import...</string> + </property> + <property name="modal"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="vlImport"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="UiModLabel" name="labPicture"> + <property name="minimumSize"> + <size> + <width>430</width> + <height>240</height> + </size> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item> + <widget class="QFrame" name="buttomFrame"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <layout class="QVBoxLayout" name="vlButtom"> + <property name="leftMargin"> + <number>9</number> + </property> + <property name="topMargin"> + <number>6</number> + </property> + <property name="rightMargin"> + <number>9</number> + </property> + <property name="bottomMargin"> + <number>9</number> + </property> + <item> + <widget class="QGroupBox" name="gbSettings"> + <property name="title"> + <string>Settings</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="hlColor"> + <item> + <widget class="QLabel" name="labColour"> + <property name="text"> + <string>Background Colour: <span style="color: %1">%1</span></string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="cmdColourChange"> + <property name="text"> + <string>...</string> + </property> + </widget> + </item> + <item> + <spacer name="hsColourSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="hlCheckboxes"> + <item> + <widget class="QCheckBox" name="cbAvatar"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Avatar</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="cbIgnore"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Ignore Aspect Ratio</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="vsDialog"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QHBoxLayout" name="hlButtons"> + <item> + <spacer name="hsButtons"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="cmdOK"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Import picture</string> + </property> + <property name="text"> + <string>&OK</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="cmdCancel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Discard picture</string> + </property> + <property name="text"> + <string>&Cancel</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>UiModLabel</class> + <extends>QLabel</extends> + <header>uimod/UiModLabel.h</header> + <slots> + <signal>mouseMoved()</signal> + <signal>mouseReleased()</signal> + <signal>mousePressed()</signal> + <signal>mouseDoubleClicked()</signal> + </slots> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/MapPreviewDialog.cpp b/MapPreviewDialog.cpp new file mode 100644 index 0000000..1efd416 --- /dev/null +++ b/MapPreviewDialog.cpp @@ -0,0 +1,76 @@ +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "MapPreviewDialog.h" +#include "ui_MapPreviewDialog.h" +#include "IconLoader.h" +#include "AppEnv.h" +#include <QPainter> +#include <QDebug> +#ifdef __MINGW32__ +#include <cmath> +#endif + +MapPreviewDialog::MapPreviewDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::MapPreviewDialog) +{ + // Set Window Flags + setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint); + + ui->setupUi(this); + + // DPI calculation + qreal screenRatio = AppEnv::screenRatio(); + setMinimumSize(500 * screenRatio, 600 * screenRatio); + setMaximumSize(500 * screenRatio, 600 * screenRatio); + setFixedSize(500 * screenRatio, 600 * screenRatio); +} + +MapPreviewDialog::~MapPreviewDialog() +{ + delete ui; +} + +void MapPreviewDialog::drawPointOnMap(double xpos_d, double ypos_d) +{ + qreal screenRatio = AppEnv::screenRatio(); + int pointMakerSize = 8 * screenRatio; + QPixmap pointMakerPixmap = IconLoader::loadingPointmakerIcon().pixmap(QSize(pointMakerSize, pointMakerSize)); + QSize mapPixelSize = size(); + + int pointMakerHalfSize = pointMakerSize / 2; + long xpos_ms = std::round(xpos_d); + long ypos_ms = std::round(ypos_d); + double xpos_ma = xpos_ms + 4000; + double ypos_ma = ypos_ms + 4000; + double xrat = (double)mapPixelSize.width() / 10000; + double yrat = (double)mapPixelSize.height() / 12000; + long xpos_mp = std::round(xpos_ma * xrat); + long ypos_mp = std::round(ypos_ma * yrat); + long xpos_pr = xpos_mp - pointMakerHalfSize; + long ypos_pr = ypos_mp + pointMakerHalfSize; + + QPixmap mapPixmap(mapPixelSize); + QPainter mapPainter(&mapPixmap); + mapPainter.drawPixmap(0, 0, mapPixelSize.width(), mapPixelSize.height(), QPixmap(":/img/mappreview.jpg").scaled(mapPixelSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + mapPainter.drawPixmap(xpos_pr, mapPixelSize.height() - ypos_pr, pointMakerSize, pointMakerSize, pointMakerPixmap); + mapPainter.end(); + + ui->labPicture->setPixmap(mapPixmap); +} diff --git a/MapPreviewDialog.h b/MapPreviewDialog.h new file mode 100644 index 0000000..e69666b --- /dev/null +++ b/MapPreviewDialog.h @@ -0,0 +1,41 @@ +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef MAPPREVIEWDIALOG_H +#define MAPPREVIEWDIALOG_H + +#include <QDialog> + +namespace Ui { +class MapPreviewDialog; +} + +class MapPreviewDialog : public QDialog +{ + Q_OBJECT + +public: + explicit MapPreviewDialog(QWidget *parent = 0); + void drawPointOnMap(double x, double y); + ~MapPreviewDialog(); + +private: + Ui::MapPreviewDialog *ui; +}; + +#endif // MAPPREVIEWDIALOG_H diff --git a/MapPreviewDialog.ui b/MapPreviewDialog.ui new file mode 100644 index 0000000..35fed61 --- /dev/null +++ b/MapPreviewDialog.ui @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MapPreviewDialog</class> + <widget class="QDialog" name="MapPreviewDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>500</width> + <height>600</height> + </rect> + </property> + <property name="minimumSize"> + <size> + <width>500</width> + <height>600</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>500</width> + <height>600</height> + </size> + </property> + <property name="windowTitle"> + <string>Snapmatic Map Viewer</string> + </property> + <layout class="QVBoxLayout" name="vlMapPreview"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="UiModLabel" name="labPicture"> + <property name="text"> + <string/> + </property> + <property name="scaledContents"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>UiModLabel</class> + <extends>QLabel</extends> + <header>uimod/UiModLabel.h</header> + <slots> + <signal>mouseMoved()</signal> + <signal>mouseReleased()</signal> + <signal>mousePressed()</signal> + <signal>mouseDoubleClicked()</signal> + </slots> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/OptionsDialog.cpp b/OptionsDialog.cpp index f42c3c3..76f1105 100755 --- a/OptionsDialog.cpp +++ b/OptionsDialog.cpp @@ -1,457 +1,439 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "OptionsDialog.h" -#include "ui_OptionsDialog.h" -#include "StandardPaths.h" -#include "UserInterface.h" -#include "AppEnv.h" -#include "config.h" -#include <QDesktopWidget> -#include <QApplication> -#include <QFileDialog> -#include <QMessageBox> -#include <QStringList> -#include <QLocale> -#include <QString> -#include <QDebug> -#include <QList> -#include <QDir> - -OptionsDialog::OptionsDialog(ProfileDatabase *profileDB, QWidget *parent) : - QDialog(parent), profileDB(profileDB), - ui(new Ui::OptionsDialog) -{ - // Set Window Flags - setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint); - - // Setup User Interface - ui->setupUi(this); - ui->tabWidget->setCurrentIndex(0); - ui->labPicCustomRes->setVisible(false); - - QRect desktopResolution = QApplication::desktop()->screenGeometry(parent); - int desktopSizeWidth = desktopResolution.width(); - int desktopSizeHeight = desktopResolution.height(); - aspectRatio = Qt::KeepAspectRatio; - defExportSize = QSize(960, 536); - cusExportSize = defExportSize; - defaultQuality = 100; - customQuality = 100; - contentMode = 0; - settings = new QSettings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); - - percentString = ui->labPicQuality->text(); - ui->labPicQuality->setText(percentString.arg(QString::number(defaultQuality))); - ui->rbPicDesktopRes->setText(ui->rbPicDesktopRes->text().arg(QString::number(desktopSizeWidth), QString::number(desktopSizeHeight))); - ui->rbPicDefaultRes->setText(ui->rbPicDefaultRes->text().arg(QString::number(defExportSize.width()), QString::number(defExportSize.height()))); - - if (QIcon::hasThemeIcon("dialog-ok")) - { - ui->cmdOK->setIcon(QIcon::fromTheme("dialog-ok")); - } - if (QIcon::hasThemeIcon("dialog-cancel")) - { - ui->cmdCancel->setIcon(QIcon::fromTheme("dialog-cancel")); - } - - // DPI calculation - qreal screenRatio = AppEnv::screenRatio(); - resize(435 * screenRatio, 405 * screenRatio); - - setupTreeWidget(); - setupLanguageBox(); - setupRadioButtons(); - setupDefaultProfile(); - setupPictureSettings(); - setupCustomGTAFolder(); - setupSnapmaticPictureViewer(); - -#ifdef GTA5SYNC_DISABLED - ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->tabSync)); -#endif - - this->setWindowTitle(windowTitle().arg(GTA5SYNC_APPSTR)); -} - -OptionsDialog::~OptionsDialog() -{ - delete settings; - foreach(QTreeWidgetItem *playerItem, playerItems) - { - delete playerItem; - } - delete ui; -} - -void OptionsDialog::setupTreeWidget() -{ - foreach(const QString &playerIDStr, profileDB->getPlayers()) - { - bool ok; - int playerID = playerIDStr.toInt(&ok); - if (ok) - { - QString playerName = profileDB->getPlayerName(playerID); - - QStringList playerTreeViewList; - playerTreeViewList << playerIDStr; - playerTreeViewList << playerName; - - QTreeWidgetItem *playerItem = new QTreeWidgetItem(playerTreeViewList); - ui->twPlayers->addTopLevelItem(playerItem); - playerItems.append(playerItem); - } - } - ui->twPlayers->sortItems(1, Qt::AscendingOrder); -} - -void OptionsDialog::setupLanguageBox() -{ - settings->beginGroup("Interface"); - currentLanguage = settings->value("Language","System").toString(); - settings->endGroup(); - - QStringList langList = QLocale::system().name().split("_"); - if (langList.length() > 0) - { - QString cbSysStr = tr("%1 (%2 if available)", "System like PC System = %1, System Language like Deutsch = %2").arg(tr("System", - "System like PC System"), QLocale::languageToString(QLocale(langList.at(0)).language())); - ui->cbLanguage->addItem(cbSysStr, "System"); - } - - QString cbEngStr = "English (English) [en]"; - ui->cbLanguage->addItem(QIcon::fromTheme("flag-us"), cbEngStr, "en"); - if (currentLanguage == "en") - { -#if QT_VERSION >= 0x050000 - ui->cbLanguage->setCurrentText(cbEngStr); -#else - int indexOfEnglish = ui->cbLanguage->findText(cbEngStr); - ui->cbLanguage->setCurrentIndex(indexOfEnglish); -#endif - } - - QDir langDir; - langDir.setNameFilters(QStringList("gta5sync_*.qm")); - langDir.setPath(AppEnv::getLangFolder()); - QStringList langFiles; - langFiles << langDir.entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::NoSort); - langDir.setPath(":/tr"); - langFiles << langDir.entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::NoSort); - langFiles.removeDuplicates(); - - foreach(const QString &langFile, langFiles) - { - QString lang = langFile; - lang.remove("gta5sync_"); - lang.remove(".qm"); - - QLocale langLocale(lang); - QString languageNameInternational = QLocale::languageToString(langLocale.language()); - QString languageNameNative = langLocale.nativeLanguageName(); - - QString cbLangStr = languageNameNative + " (" + languageNameInternational + ") [" + lang + "]"; - QString langIconStr = "flag-" + lang; - - ui->cbLanguage->addItem(QIcon::fromTheme(langIconStr), cbLangStr, lang); - if (currentLanguage == lang) - { -#if QT_VERSION >= 0x050000 - ui->cbLanguage->setCurrentText(cbLangStr); -#else - int indexOfLang = ui->cbLanguage->findText(cbLangStr); - ui->cbLanguage->setCurrentIndex(indexOfLang); -#endif - } - } -} - -void OptionsDialog::setupRadioButtons() -{ - bool contentModeOk; - settings->beginGroup("Profile"); - contentMode = settings->value("ContentMode", 0).toInt(&contentModeOk); - settings->endGroup(); - - if (contentModeOk) - { - if (contentMode == 0) - { - ui->rbOpenWithSC->setChecked(true); - } - else if (contentMode == 1) - { - ui->rbOpenWithDC->setChecked(true); - } - else if (contentMode == 2) - { - ui->rbSelectWithSC->setChecked(true); - } - } -} - -void OptionsDialog::on_cmdOK_clicked() -{ - applySettings(); - close(); -} - -void OptionsDialog::applySettings() -{ - settings->beginGroup("Interface"); -#if QT_VERSION >= 0x050000 - settings->setValue("Language", ui->cbLanguage->currentData()); -#else - settings->setValue("Language", ui->cbLanguage->itemData(ui->cbLanguage->currentIndex())); -#endif -#ifdef GTA5SYNC_WIN -#if QT_VERSION >= 0x050200 - settings->setValue("NavigationBar", ui->cbSnapmaticNavigationBar->isChecked()); -#endif -#endif - settings->endGroup(); - - settings->beginGroup("Profile"); - int newContentMode = 0; - if (ui->rbOpenWithSC->isChecked()) - { - newContentMode = 0; - } - else if (ui->rbOpenWithDC->isChecked()) - { - newContentMode = 1; - } - else if (ui->rbSelectWithSC->isChecked()) - { - newContentMode = 2; - } - settings->setValue("ContentMode", newContentMode); -#if QT_VERSION >= 0x050000 - settings->setValue("Default", ui->cbProfiles->currentData()); -#else - settings->setValue("Default", ui->cbProfiles->itemData(ui->cbProfiles->currentIndex())); -#endif - settings->endGroup(); - - settings->beginGroup("Pictures"); - if (ui->cbPicCustomQuality->isChecked()) - { - settings->setValue("CustomQuality", ui->hsPicQuality->value()); - } - settings->setValue("CustomQualityEnabled", ui->cbPicCustomQuality->isChecked()); - QString sizeMode = "Default"; - if (ui->rbPicDesktopRes->isChecked()) - { - sizeMode = "Desktop"; - } - else if (ui->rbPicCustomRes->isChecked()) - { - sizeMode = "Custom"; - settings->setValue("CustomSize", QSize(ui->sbPicExportWidth->value(), ui->sbPicExportHeight->value())); - } - settings->setValue("ExportSizeMode", sizeMode); - settings->setValue("AspectRatio", aspectRatio); - settings->endGroup(); - - bool forceCustomFolder = ui->cbForceCustomFolder->isChecked(); - settings->beginGroup("dir"); - settings->setValue("dir", ui->txtFolder->text()); - settings->setValue("force", forceCustomFolder); - settings->endGroup(); - -#if QT_VERSION >= 0x050000 - emit settingsApplied(newContentMode, ui->cbLanguage->currentData().toString()); -#else - emit settingsApplied(newContentMode, ui->cbLanguage->itemData(ui->cbLanguage->currentIndex()).toString()); -#endif - -#if QT_VERSION >= 0x050000 - bool languageChanged = ui->cbLanguage->currentData().toString() != currentLanguage; -#else - bool languageChanged = ui->cbLanguage->itemData(ui->cbLanguage->currentIndex()).toString() != currentLanguage; -#endif - - if ((forceCustomFolder && ui->txtFolder->text() != currentCFolder) || (forceCustomFolder != currentFFolder && forceCustomFolder)) - { - QMessageBox::information(this, tr("%1", "%1").arg(GTA5SYNC_APPSTR), tr("The new Custom Folder will initialize after you restart %1.").arg(GTA5SYNC_APPSTR)); - } - if (languageChanged) - { - QMessageBox::information(this, tr("%1", "%1").arg(GTA5SYNC_APPSTR), tr("The language change will take effect after you restart %1.").arg(GTA5SYNC_APPSTR)); - } -} - -void OptionsDialog::setupDefaultProfile() -{ - settings->beginGroup("Profile"); - defaultProfile = settings->value("Default", "").toString(); - settings->endGroup(); - - QString cbNoneStr = tr("No Profile", "No Profile, as default"); - ui->cbProfiles->addItem(cbNoneStr, ""); -} - -void OptionsDialog::commitProfiles(QStringList profiles) -{ - foreach(const QString &profile, profiles) - { - ui->cbProfiles->addItem(tr("Profile: %1").arg(profile), profile); - if (defaultProfile == profile) - { -#if QT_VERSION >= 0x050000 - ui->cbProfiles->setCurrentText(tr("Profile: %1").arg(profile)); -#else - int indexOfProfile = ui->cbProfiles->findText(tr("Profile: %1").arg(profile)); - ui->cbProfiles->setCurrentIndex(indexOfProfile); -#endif - } - } -} - -void OptionsDialog::on_rbPicCustomRes_toggled(bool checked) -{ - ui->labPicCustomRes->setEnabled(checked); - ui->sbPicExportWidth->setEnabled(checked); - ui->sbPicExportHeight->setEnabled(checked); - ui->labPicXDescription->setEnabled(checked); -} - -void OptionsDialog::on_cbPicCustomQuality_toggled(bool checked) -{ - ui->hsPicQuality->setEnabled(checked); - ui->labPicQuality->setEnabled(checked); - ui->labPicQualityDescription->setEnabled(checked); -} - -void OptionsDialog::on_hsPicQuality_valueChanged(int value) -{ - customQuality = value; - ui->labPicQuality->setText(percentString.arg(QString::number(value))); -} - -void OptionsDialog::setupPictureSettings() -{ - settings->beginGroup("Pictures"); - - // Quality Settings - customQuality = settings->value("CustomQuality", defaultQuality).toInt(); - if (customQuality < 1 || customQuality > 100) - { - customQuality = 100; - } - ui->hsPicQuality->setValue(customQuality); - ui->cbPicCustomQuality->setChecked(settings->value("CustomQualityEnabled", false).toBool()); - - // Size Settings - cusExportSize = settings->value("CustomSize", defExportSize).toSize(); - if (cusExportSize.width() > 3840) - { - cusExportSize.setWidth(3840); - } - else if (cusExportSize.height() > 2160) - { - cusExportSize.setHeight(2160); - } - if (cusExportSize.width() < 1) - { - cusExportSize.setWidth(1); - } - else if (cusExportSize.height() < 1) - { - cusExportSize.setHeight(1); - } - ui->sbPicExportWidth->setValue(cusExportSize.width()); - ui->sbPicExportHeight->setValue(cusExportSize.height()); - - QString sizeMode = settings->value("ExportSizeMode", "Default").toString(); - if (sizeMode == "Desktop") - { - ui->rbPicDesktopRes->setChecked(true); - } - else if (sizeMode == "Custom") - { - ui->rbPicCustomRes->setChecked(true); - } - else - { - ui->rbPicDefaultRes->setChecked(true); - } - - aspectRatio = (Qt::AspectRatioMode)settings->value("AspectRatio", Qt::KeepAspectRatio).toInt(); - if (aspectRatio == Qt::IgnoreAspectRatio) - { - ui->cbIgnoreAspectRatio->setChecked(true); - } - - settings->endGroup(); -} - -void OptionsDialog::on_cbIgnoreAspectRatio_toggled(bool checked) -{ - if (checked) - { - aspectRatio = Qt::IgnoreAspectRatio; - } - else - { - aspectRatio = Qt::KeepAspectRatio; - } -} - -void OptionsDialog::setupCustomGTAFolder() -{ - bool ok; - QString defaultGameFolder = AppEnv::getGameFolder(&ok); - settings->beginGroup("dir"); - currentCFolder = settings->value("dir", "").toString(); - currentFFolder = settings->value("force", false).toBool(); - if (currentCFolder == "" && ok) - { - currentCFolder = defaultGameFolder; - } - ui->txtFolder->setText(currentCFolder); - ui->cbForceCustomFolder->setChecked(currentFFolder); - settings->endGroup(); -} - -void OptionsDialog::setupSnapmaticPictureViewer() -{ -#ifdef GTA5SYNC_WIN -#if QT_VERSION >= 0x050200 - settings->beginGroup("Interface"); - ui->cbSnapmaticNavigationBar->setChecked(settings->value("NavigationBar", false).toBool()); - settings->endGroup(); -#else - ui->cbSnapmaticNavigationBar->setVisible(false); - ui->gbSnapmaticPictureViewer->setVisible(false); -#endif -#else - ui->cbSnapmaticNavigationBar->setVisible(false); - ui->gbSnapmaticPictureViewer->setVisible(false); -#endif -} - -void OptionsDialog::on_cmdExploreFolder_clicked() -{ - QString GTAV_Folder = QFileDialog::getExistingDirectory(this, UserInterface::tr("Select GTA V Folder..."), StandardPaths::documentsLocation(), QFileDialog::ShowDirsOnly); - if (QFileInfo(GTAV_Folder).exists()) - { - ui->txtFolder->setText(GTAV_Folder); - } -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "OptionsDialog.h" +#include "ui_OptionsDialog.h" +#include "TranslationClass.h" +#include "StandardPaths.h" +#include "UserInterface.h" +#include "AppEnv.h" +#include "config.h" +#include <QStringBuilder> +#include <QDesktopWidget> +#include <QApplication> +#include <QFileDialog> +#include <QMessageBox> +#include <QStringList> +#include <QLocale> +#include <QString> +#include <QDebug> +#include <QList> +#include <QDir> + +OptionsDialog::OptionsDialog(ProfileDatabase *profileDB, QWidget *parent) : + QDialog(parent), profileDB(profileDB), + ui(new Ui::OptionsDialog) +{ + // Set Window Flags + setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint); + + // Setup User Interface + ui->setupUi(this); + ui->tabWidget->setCurrentIndex(0); + ui->labPicCustomRes->setVisible(false); + + QRect desktopResolution = qApp->desktop()->screenGeometry(parent); + int desktopSizeWidth = desktopResolution.width(); + int desktopSizeHeight = desktopResolution.height(); + aspectRatio = Qt::KeepAspectRatio; + defExportSize = QSize(960, 536); + cusExportSize = defExportSize; + defaultQuality = 100; + customQuality = 100; + contentMode = 0; + settings = new QSettings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); + + percentString = ui->labPicQuality->text(); + ui->labPicQuality->setText(percentString.arg(QString::number(defaultQuality))); + ui->rbPicDesktopRes->setText(ui->rbPicDesktopRes->text().arg(QString::number(desktopSizeWidth), QString::number(desktopSizeHeight))); + ui->rbPicDefaultRes->setText(ui->rbPicDefaultRes->text().arg(QString::number(defExportSize.width()), QString::number(defExportSize.height()))); + + if (QIcon::hasThemeIcon("dialog-ok")) + { + ui->cmdOK->setIcon(QIcon::fromTheme("dialog-ok")); + } + if (QIcon::hasThemeIcon("dialog-cancel")) + { + ui->cmdCancel->setIcon(QIcon::fromTheme("dialog-cancel")); + } + + // DPI calculation + qreal screenRatio = AppEnv::screenRatio(); + resize(435 * screenRatio, 405 * screenRatio); + + setupTreeWidget(); + setupLanguageBox(); + setupRadioButtons(); + setupDefaultProfile(); + setupPictureSettings(); + setupCustomGTAFolder(); + setupSnapmaticPictureViewer(); + +#ifdef GTA5SYNC_DISABLED + ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->tabSync)); +#endif + + this->setWindowTitle(windowTitle().arg(GTA5SYNC_APPSTR)); +} + +OptionsDialog::~OptionsDialog() +{ + delete settings; + foreach(QTreeWidgetItem *playerItem, playerItems) + { + delete playerItem; + } + delete ui; +} + +void OptionsDialog::setupTreeWidget() +{ + foreach(const QString &playerIDStr, profileDB->getPlayers()) + { + bool ok; + int playerID = playerIDStr.toInt(&ok); + if (ok) + { + QString playerName = profileDB->getPlayerName(playerID); + + QStringList playerTreeViewList; + playerTreeViewList << playerIDStr; + playerTreeViewList << playerName; + + QTreeWidgetItem *playerItem = new QTreeWidgetItem(playerTreeViewList); + ui->twPlayers->addTopLevelItem(playerItem); + playerItems += playerItem; + } + } + ui->twPlayers->sortItems(1, Qt::AscendingOrder); +} + +void OptionsDialog::setupLanguageBox() +{ + settings->beginGroup("Interface"); + currentLanguage = settings->value("Language","System").toString(); + settings->endGroup(); + + QString cbSysStr = tr("%1 (Next Closest Language)", "First language a person can talk with a different person/application. \"Native\" or \"Not Native\".").arg(tr("System", + "System in context of System default")); + ui->cbLanguage->addItem(cbSysStr, "System"); + + QStringList availableLanguages; + availableLanguages << QString("en_GB"); +#ifndef GTA5SYNC_QCONF + availableLanguages << TCInstance->listTranslations(AppEnv::getExLangFolder()); +#endif + availableLanguages << TCInstance->listTranslations(AppEnv::getInLangFolder()); + availableLanguages.removeDuplicates(); + availableLanguages.sort(); + + foreach(const QString &lang, availableLanguages) + { + QLocale langLocale(lang); + QString cbLangStr = langLocale.nativeLanguageName() % " (" % langLocale.nativeCountryName() % ") [" % lang % "]"; + + QString langIconStr = "flag-" % TranslationClass::getCountryCode(langLocale); + + ui->cbLanguage->addItem(QIcon::fromTheme(langIconStr), cbLangStr, lang); + if (currentLanguage == lang) + { +#if QT_VERSION >= 0x050000 + ui->cbLanguage->setCurrentText(cbLangStr); +#else + int indexOfLang = ui->cbLanguage->findText(cbLangStr); + ui->cbLanguage->setCurrentIndex(indexOfLang); +#endif + } + } +} + +void OptionsDialog::setupRadioButtons() +{ + bool contentModeOk; + settings->beginGroup("Profile"); + contentMode = settings->value("ContentMode", 0).toInt(&contentModeOk); + settings->endGroup(); + + if (contentModeOk) + { + if (contentMode == 0) + { + ui->rbOpenWithSC->setChecked(true); + } + else if (contentMode == 1) + { + ui->rbOpenWithDC->setChecked(true); + } + else if (contentMode == 2) + { + ui->rbSelectWithSC->setChecked(true); + } + } +} + +void OptionsDialog::on_cmdOK_clicked() +{ + applySettings(); + close(); +} + +void OptionsDialog::applySettings() +{ + settings->beginGroup("Interface"); +#if QT_VERSION >= 0x050000 + settings->setValue("Language", ui->cbLanguage->currentData()); +#else + settings->setValue("Language", ui->cbLanguage->itemData(ui->cbLanguage->currentIndex())); +#endif +#ifdef GTA5SYNC_WIN +#if QT_VERSION >= 0x050200 + settings->setValue("NavigationBar", ui->cbSnapmaticNavigationBar->isChecked()); +#endif +#endif + settings->endGroup(); + + settings->beginGroup("Profile"); + int newContentMode = 0; + if (ui->rbOpenWithSC->isChecked()) + { + newContentMode = 0; + } + else if (ui->rbOpenWithDC->isChecked()) + { + newContentMode = 1; + } + else if (ui->rbSelectWithSC->isChecked()) + { + newContentMode = 2; + } + settings->setValue("ContentMode", newContentMode); +#if QT_VERSION >= 0x050000 + settings->setValue("Default", ui->cbProfiles->currentData()); +#else + settings->setValue("Default", ui->cbProfiles->itemData(ui->cbProfiles->currentIndex())); +#endif + settings->endGroup(); + + settings->beginGroup("Pictures"); + if (ui->cbPicCustomQuality->isChecked()) + { + settings->setValue("CustomQuality", ui->hsPicQuality->value()); + } + settings->setValue("CustomQualityEnabled", ui->cbPicCustomQuality->isChecked()); + QString sizeMode = "Default"; + if (ui->rbPicDesktopRes->isChecked()) + { + sizeMode = "Desktop"; + } + else if (ui->rbPicCustomRes->isChecked()) + { + sizeMode = "Custom"; + settings->setValue("CustomSize", QSize(ui->sbPicExportWidth->value(), ui->sbPicExportHeight->value())); + } + settings->setValue("ExportSizeMode", sizeMode); + settings->setValue("AspectRatio", aspectRatio); + settings->endGroup(); + + bool forceCustomFolder = ui->cbForceCustomFolder->isChecked(); + settings->beginGroup("dir"); + settings->setValue("dir", ui->txtFolder->text()); + settings->setValue("force", forceCustomFolder); + settings->endGroup(); + +#if QT_VERSION >= 0x050000 + bool languageChanged = ui->cbLanguage->currentData().toString() != currentLanguage; +#else + bool languageChanged = ui->cbLanguage->itemData(ui->cbLanguage->currentIndex()).toString() != currentLanguage; +#endif + if (languageChanged) + { + TCInstance->unloadTranslation(qApp); + TCInstance->initUserLanguage(); + TCInstance->loadTranslation(qApp); + } + +#if QT_VERSION >= 0x050000 + emit settingsApplied(newContentMode, ui->cbLanguage->currentData().toString()); +#else + emit settingsApplied(newContentMode, ui->cbLanguage->itemData(ui->cbLanguage->currentIndex()).toString()); +#endif + + if ((forceCustomFolder && ui->txtFolder->text() != currentCFolder) || (forceCustomFolder != currentFFolder && forceCustomFolder)) + { + QMessageBox::information(this, tr("%1", "%1").arg(GTA5SYNC_APPSTR), tr("The new Custom Folder will initialise after you restart %1.").arg(GTA5SYNC_APPSTR)); + } +} + +void OptionsDialog::setupDefaultProfile() +{ + settings->beginGroup("Profile"); + defaultProfile = settings->value("Default", "").toString(); + settings->endGroup(); + + QString cbNoneStr = tr("No Profile", "No Profile, as default"); + ui->cbProfiles->addItem(cbNoneStr, ""); +} + +void OptionsDialog::commitProfiles(QStringList profiles) +{ + foreach(const QString &profile, profiles) + { + ui->cbProfiles->addItem(tr("Profile: %1").arg(profile), profile); + if (defaultProfile == profile) + { +#if QT_VERSION >= 0x050000 + ui->cbProfiles->setCurrentText(tr("Profile: %1").arg(profile)); +#else + int indexOfProfile = ui->cbProfiles->findText(tr("Profile: %1").arg(profile)); + ui->cbProfiles->setCurrentIndex(indexOfProfile); +#endif + } + } +} + +void OptionsDialog::on_rbPicCustomRes_toggled(bool checked) +{ + ui->labPicCustomRes->setEnabled(checked); + ui->sbPicExportWidth->setEnabled(checked); + ui->sbPicExportHeight->setEnabled(checked); + ui->labPicXDescription->setEnabled(checked); +} + +void OptionsDialog::on_cbPicCustomQuality_toggled(bool checked) +{ + ui->hsPicQuality->setEnabled(checked); + ui->labPicQuality->setEnabled(checked); + ui->labPicQualityDescription->setEnabled(checked); +} + +void OptionsDialog::on_hsPicQuality_valueChanged(int value) +{ + customQuality = value; + ui->labPicQuality->setText(percentString.arg(QString::number(value))); +} + +void OptionsDialog::setupPictureSettings() +{ + settings->beginGroup("Pictures"); + + // Quality Settings + customQuality = settings->value("CustomQuality", defaultQuality).toInt(); + if (customQuality < 1 || customQuality > 100) + { + customQuality = 100; + } + ui->hsPicQuality->setValue(customQuality); + ui->cbPicCustomQuality->setChecked(settings->value("CustomQualityEnabled", false).toBool()); + + // Size Settings + cusExportSize = settings->value("CustomSize", defExportSize).toSize(); + if (cusExportSize.width() > 3840) + { + cusExportSize.setWidth(3840); + } + else if (cusExportSize.height() > 2160) + { + cusExportSize.setHeight(2160); + } + if (cusExportSize.width() < 1) + { + cusExportSize.setWidth(1); + } + else if (cusExportSize.height() < 1) + { + cusExportSize.setHeight(1); + } + ui->sbPicExportWidth->setValue(cusExportSize.width()); + ui->sbPicExportHeight->setValue(cusExportSize.height()); + + QString sizeMode = settings->value("ExportSizeMode", "Default").toString(); + if (sizeMode == "Desktop") + { + ui->rbPicDesktopRes->setChecked(true); + } + else if (sizeMode == "Custom") + { + ui->rbPicCustomRes->setChecked(true); + } + else + { + ui->rbPicDefaultRes->setChecked(true); + } + + aspectRatio = (Qt::AspectRatioMode)settings->value("AspectRatio", Qt::KeepAspectRatio).toInt(); + if (aspectRatio == Qt::IgnoreAspectRatio) + { + ui->cbIgnoreAspectRatio->setChecked(true); + } + + settings->endGroup(); +} + +void OptionsDialog::on_cbIgnoreAspectRatio_toggled(bool checked) +{ + if (checked) + { + aspectRatio = Qt::IgnoreAspectRatio; + } + else + { + aspectRatio = Qt::KeepAspectRatio; + } +} + +void OptionsDialog::setupCustomGTAFolder() +{ + bool ok; + QString defaultGameFolder = AppEnv::getGameFolder(&ok); + settings->beginGroup("dir"); + currentCFolder = settings->value("dir", "").toString(); + currentFFolder = settings->value("force", false).toBool(); + if (currentCFolder == "" && ok) + { + currentCFolder = defaultGameFolder; + } + ui->txtFolder->setText(currentCFolder); + ui->cbForceCustomFolder->setChecked(currentFFolder); + settings->endGroup(); +} + +void OptionsDialog::setupSnapmaticPictureViewer() +{ +#ifdef GTA5SYNC_WIN +#if QT_VERSION >= 0x050200 + settings->beginGroup("Interface"); + ui->cbSnapmaticNavigationBar->setChecked(settings->value("NavigationBar", false).toBool()); + settings->endGroup(); +#else + ui->cbSnapmaticNavigationBar->setVisible(false); + ui->gbSnapmaticPictureViewer->setVisible(false); +#endif +#else + ui->cbSnapmaticNavigationBar->setVisible(false); + ui->gbSnapmaticPictureViewer->setVisible(false); +#endif +} + +void OptionsDialog::on_cmdExploreFolder_clicked() +{ + QString GTAV_Folder = QFileDialog::getExistingDirectory(this, UserInterface::tr("Select GTA V Folder..."), StandardPaths::documentsLocation(), QFileDialog::ShowDirsOnly); + if (QFileInfo(GTAV_Folder).exists()) + { + ui->txtFolder->setText(GTAV_Folder); + } +} diff --git a/OptionsDialog.h b/OptionsDialog.h index 83aa3e3..763d1df 100755 --- a/OptionsDialog.h +++ b/OptionsDialog.h @@ -1,79 +1,79 @@ -/****************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef OPTIONSDIALOG_H -#define OPTIONSDIALOG_H - -#include <QSize> -#include <QList> -#include <QDialog> -#include <QSettings> -#include <QTreeWidgetItem> -#include "ProfileDatabase.h" - -namespace Ui { -class OptionsDialog; -} - -class OptionsDialog : public QDialog -{ - Q_OBJECT - -public: - explicit OptionsDialog(ProfileDatabase *profileDB, QWidget *parent = 0); - void commitProfiles(QStringList profiles); - ~OptionsDialog(); - -private slots: - void on_cmdOK_clicked(); - void on_rbPicCustomRes_toggled(bool checked); - void on_cbPicCustomQuality_toggled(bool checked); - void on_hsPicQuality_valueChanged(int value); - void on_cbIgnoreAspectRatio_toggled(bool checked); - void on_cmdExploreFolder_clicked(); - -signals: - void settingsApplied(int contentMode, QString language); - -private: - ProfileDatabase *profileDB; - Ui::OptionsDialog *ui; - QList<QTreeWidgetItem*> playerItems; - Qt::AspectRatioMode aspectRatio; - QString currentLanguage; - QString currentCFolder; - QString defaultProfile; - QString percentString; - QSettings *settings; - bool currentFFolder; - int contentMode; - int customQuality; - int defaultQuality; - QSize defExportSize; - QSize cusExportSize; - void setupTreeWidget(); - void setupLanguageBox(); - void setupRadioButtons(); - void setupDefaultProfile(); - void setupPictureSettings(); - void setupCustomGTAFolder(); - void setupSnapmaticPictureViewer(); - void applySettings(); -}; - -#endif // OPTIONSDIALOG_H +/****************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef OPTIONSDIALOG_H +#define OPTIONSDIALOG_H + +#include <QSize> +#include <QList> +#include <QDialog> +#include <QSettings> +#include <QTreeWidgetItem> +#include "ProfileDatabase.h" + +namespace Ui { +class OptionsDialog; +} + +class OptionsDialog : public QDialog +{ + Q_OBJECT + +public: + explicit OptionsDialog(ProfileDatabase *profileDB, QWidget *parent = 0); + void commitProfiles(QStringList profiles); + ~OptionsDialog(); + +private slots: + void on_cmdOK_clicked(); + void on_rbPicCustomRes_toggled(bool checked); + void on_cbPicCustomQuality_toggled(bool checked); + void on_hsPicQuality_valueChanged(int value); + void on_cbIgnoreAspectRatio_toggled(bool checked); + void on_cmdExploreFolder_clicked(); + +signals: + void settingsApplied(int contentMode, QString language); + +private: + ProfileDatabase *profileDB; + Ui::OptionsDialog *ui; + QList<QTreeWidgetItem*> playerItems; + Qt::AspectRatioMode aspectRatio; + QString currentLanguage; + QString currentCFolder; + QString defaultProfile; + QString percentString; + QSettings *settings; + bool currentFFolder; + int contentMode; + int customQuality; + int defaultQuality; + QSize defExportSize; + QSize cusExportSize; + void setupTreeWidget(); + void setupLanguageBox(); + void setupRadioButtons(); + void setupDefaultProfile(); + void setupPictureSettings(); + void setupCustomGTAFolder(); + void setupSnapmaticPictureViewer(); + void applySettings(); +}; + +#endif // OPTIONSDIALOG_H diff --git a/OptionsDialog.ui b/OptionsDialog.ui index 995ae79..7025371 100755 --- a/OptionsDialog.ui +++ b/OptionsDialog.ui @@ -1,503 +1,509 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>OptionsDialog</class> - <widget class="QDialog" name="OptionsDialog"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>435</width> - <height>405</height> - </rect> - </property> - <property name="windowTitle"> - <string>%1 - Settings</string> - </property> - <property name="modal"> - <bool>true</bool> - </property> - <layout class="QVBoxLayout" name="vlOptions"> - <item> - <widget class="QTabWidget" name="tabWidget"> - <property name="currentIndex"> - <number>0</number> - </property> - <widget class="QWidget" name="tabProfile"> - <attribute name="title"> - <string>Profiles</string> - </attribute> - <layout class="QVBoxLayout" name="vlProfile"> - <item> - <widget class="QGroupBox" name="gbWidgets"> - <property name="title"> - <string>Content Open/Select Mode</string> - </property> - <layout class="QVBoxLayout" name="vlProfileContentMode"> - <item> - <widget class="QRadioButton" name="rbOpenWithSC"> - <property name="text"> - <string>Open with Singleclick</string> - </property> - <property name="checked"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QRadioButton" name="rbOpenWithDC"> - <property name="text"> - <string>Open with Doubleclick</string> - </property> - </widget> - </item> - <item> - <widget class="QRadioButton" name="rbSelectWithSC"> - <property name="text"> - <string>Select with Singleclick</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="gbDefaultProfile"> - <property name="title"> - <string>Default Profile</string> - </property> - <layout class="QVBoxLayout" name="vlDefaultProfile"> - <item> - <widget class="QComboBox" name="cbProfiles"/> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="gbDefaultFolder"> - <property name="title"> - <string>Custom GTA V Folder</string> - </property> - <layout class="QVBoxLayout" name="vlCustomGTAVFolder"> - <item> - <widget class="QCheckBox" name="cbForceCustomFolder"> - <property name="text"> - <string>Force using Custom Folder</string> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="hlDefaultFolder"> - <item> - <widget class="QLineEdit" name="txtFolder"/> - </item> - <item> - <widget class="QToolButton" name="cmdExploreFolder"> - <property name="text"> - <string>...</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - </item> - <item> - <spacer name="vsProfile"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - <widget class="QWidget" name="tabPictures"> - <attribute name="title"> - <string>Pictures</string> - </attribute> - <layout class="QVBoxLayout" name="vlTabPictures"> - <item> - <widget class="QGroupBox" name="gbPicResolution"> - <property name="title"> - <string>Export Size</string> - </property> - <layout class="QVBoxLayout" name="vlGbPicRes"> - <item> - <widget class="QRadioButton" name="rbPicDefaultRes"> - <property name="text"> - <string>Default: %1x%2</string> - </property> - <property name="checked"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QRadioButton" name="rbPicDesktopRes"> - <property name="text"> - <string>Screen Resolution: %1x%2</string> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="hlCustomRes"> - <item> - <widget class="QRadioButton" name="rbPicCustomRes"> - <property name="text"> - <string>Custom Size:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="labPicCustomRes"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="text"> - <string>Custom Size:</string> - </property> - </widget> - </item> - <item> - <widget class="QSpinBox" name="sbPicExportWidth"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="minimum"> - <number>1</number> - </property> - <property name="maximum"> - <number>3840</number> - </property> - <property name="value"> - <number>960</number> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="labPicXDescription"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="text"> - <string>x</string> - </property> - </widget> - </item> - <item> - <widget class="QSpinBox" name="sbPicExportHeight"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="minimum"> - <number>1</number> - </property> - <property name="maximum"> - <number>2160</number> - </property> - <property name="value"> - <number>536</number> - </property> - </widget> - </item> - <item> - <spacer name="hsPicCustomSize"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="hlAspectRatio"> - <item> - <widget class="QCheckBox" name="cbIgnoreAspectRatio"> - <property name="text"> - <string>Ignore Aspect Ratio</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="gbPicQuality"> - <property name="title"> - <string>Export Quality</string> - </property> - <layout class="QVBoxLayout" name="vlHlPicQuality"> - <item> - <widget class="QCheckBox" name="cbPicCustomQuality"> - <property name="text"> - <string>Enable Custom Quality</string> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="hlPicQuality"> - <item> - <widget class="QLabel" name="labPicQualityDescription"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="text"> - <string>Quality:</string> - </property> - </widget> - </item> - <item> - <widget class="QSlider" name="hsPicQuality"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="minimum"> - <number>1</number> - </property> - <property name="maximum"> - <number>100</number> - </property> - <property name="value"> - <number>100</number> - </property> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="labPicQuality"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="text"> - <string>%1%</string> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="gbSnapmaticPictureViewer"> - <property name="title"> - <string>Picture Viewer</string> - </property> - <layout class="QVBoxLayout" name="vlSnapmaticPictureViewer"> - <item> - <widget class="QCheckBox" name="cbSnapmaticNavigationBar"> - <property name="text"> - <string>Enable Navigation Bar</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <spacer name="vsTabPictures"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - <widget class="QWidget" name="tabPlayers"> - <attribute name="title"> - <string>Players</string> - </attribute> - <layout class="QVBoxLayout" name="vlPlayers"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QTreeWidget" name="twPlayers"> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Plain</enum> - </property> - <property name="lineWidth"> - <number>0</number> - </property> - <property name="editTriggers"> - <set>QAbstractItemView::NoEditTriggers</set> - </property> - <property name="verticalScrollMode"> - <enum>QAbstractItemView::ScrollPerPixel</enum> - </property> - <property name="sortingEnabled"> - <bool>true</bool> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - <column> - <property name="text"> - <string>ID</string> - </property> - </column> - <column> - <property name="text"> - <string>Name</string> - </property> - </column> - </widget> - </item> - </layout> - </widget> - <widget class="QWidget" name="tabLocalization"> - <attribute name="title"> - <string>Language</string> - </attribute> - <layout class="QVBoxLayout" name="vlLocalization"> - <item> - <widget class="QGroupBox" name="gbLanguage"> - <property name="title"> - <string>Language</string> - </property> - <layout class="QVBoxLayout" name="vlLanguage"> - <item> - <widget class="QComboBox" name="cbLanguage"/> - </item> - </layout> - </widget> - </item> - <item> - <spacer name="vsInterface"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - <widget class="QWidget" name="tabSync"> - <attribute name="title"> - <string>Sync</string> - </attribute> - <layout class="QVBoxLayout" name="vlSync"> - <item> - <widget class="QLabel" name="labSync"> - <property name="text"> - <string>Sync is not implemented at current time</string> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </widget> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="hlButtons"> - <item> - <spacer name="hsButtons"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="cmdOK"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string extracomment="OK, Cancel, Apply">&OK</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="cmdCancel"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string extracomment="OK, Cancel, Apply">&Cancel</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - <resources/> - <connections> - <connection> - <sender>cmdCancel</sender> - <signal>clicked()</signal> - <receiver>OptionsDialog</receiver> - <slot>close()</slot> - <hints> - <hint type="sourcelabel"> - <x>352</x> - <y>328</y> - </hint> - <hint type="destinationlabel"> - <x>199</x> - <y>174</y> - </hint> - </hints> - </connection> - </connections> -</ui> +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>OptionsDialog</class> + <widget class="QDialog" name="OptionsDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>435</width> + <height>405</height> + </rect> + </property> + <property name="windowTitle"> + <string>%1 - Settings</string> + </property> + <property name="modal"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="vlOptions"> + <item> + <widget class="QTabWidget" name="tabWidget"> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="tabProfile"> + <attribute name="title"> + <string>Profiles</string> + </attribute> + <layout class="QVBoxLayout" name="vlProfile"> + <item> + <widget class="QGroupBox" name="gbWidgets"> + <property name="title"> + <string>Content Open/Select Mode</string> + </property> + <layout class="QVBoxLayout" name="vlProfileContentMode"> + <item> + <widget class="QRadioButton" name="rbOpenWithSC"> + <property name="text"> + <string>Open with Singleclick</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="rbOpenWithDC"> + <property name="text"> + <string>Open with Doubleclick</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="rbSelectWithSC"> + <property name="text"> + <string>Select with Singleclick</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="gbDefaultProfile"> + <property name="title"> + <string>Default Profile</string> + </property> + <layout class="QVBoxLayout" name="vlDefaultProfile"> + <item> + <widget class="QComboBox" name="cbProfiles"/> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="gbDefaultFolder"> + <property name="title"> + <string>Custom GTA V Folder</string> + </property> + <layout class="QVBoxLayout" name="vlCustomGTAVFolder"> + <item> + <widget class="QCheckBox" name="cbForceCustomFolder"> + <property name="text"> + <string>Force using Custom Folder</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="hlDefaultFolder"> + <item> + <widget class="QLineEdit" name="txtFolder"/> + </item> + <item> + <widget class="QToolButton" name="cmdExploreFolder"> + <property name="text"> + <string>...</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="vsProfile"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="tabPictures"> + <attribute name="title"> + <string>Pictures</string> + </attribute> + <layout class="QVBoxLayout" name="vlTabPictures"> + <item> + <widget class="QGroupBox" name="gbPicResolution"> + <property name="title"> + <string>Export Size</string> + </property> + <layout class="QVBoxLayout" name="vlGbPicRes"> + <item> + <widget class="QRadioButton" name="rbPicDefaultRes"> + <property name="text"> + <string>Default: %1x%2</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="rbPicDesktopRes"> + <property name="text"> + <string>Screen Resolution: %1x%2</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="hlCustomRes"> + <item> + <widget class="QRadioButton" name="rbPicCustomRes"> + <property name="text"> + <string>Custom Size:</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="labPicCustomRes"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Custom Size:</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="sbPicExportWidth"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>3840</number> + </property> + <property name="value"> + <number>960</number> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="labPicXDescription"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>x</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="sbPicExportHeight"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>2160</number> + </property> + <property name="value"> + <number>536</number> + </property> + </widget> + </item> + <item> + <spacer name="hsPicCustomSize"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="hlAspectRatio"> + <item> + <widget class="QCheckBox" name="cbIgnoreAspectRatio"> + <property name="text"> + <string>Ignore Aspect Ratio</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="gbPicQuality"> + <property name="title"> + <string>Export Quality</string> + </property> + <layout class="QVBoxLayout" name="vlHlPicQuality"> + <item> + <widget class="QCheckBox" name="cbPicCustomQuality"> + <property name="text"> + <string>Enable Custom Quality</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="hlPicQuality"> + <item> + <widget class="QLabel" name="labPicQualityDescription"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Quality:</string> + </property> + </widget> + </item> + <item> + <widget class="QSlider" name="hsPicQuality"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>100</number> + </property> + <property name="value"> + <number>100</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="labPicQuality"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>%1%</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="gbSnapmaticPictureViewer"> + <property name="title"> + <string>Picture Viewer</string> + </property> + <layout class="QVBoxLayout" name="vlSnapmaticPictureViewer"> + <item> + <widget class="QCheckBox" name="cbSnapmaticNavigationBar"> + <property name="text"> + <string>Enable Navigation Bar</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="vsTabPictures"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="tabPlayers"> + <attribute name="title"> + <string>Players</string> + </attribute> + <layout class="QVBoxLayout" name="vlPlayers"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QTreeWidget" name="twPlayers"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="editTriggers"> + <set>QAbstractItemView::NoEditTriggers</set> + </property> + <property name="verticalScrollMode"> + <enum>QAbstractItemView::ScrollPerPixel</enum> + </property> + <property name="sortingEnabled"> + <bool>true</bool> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + <column> + <property name="text"> + <string>ID</string> + </property> + </column> + <column> + <property name="text"> + <string>Name</string> + </property> + </column> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="tabLocalization"> + <attribute name="title"> + <string>Language</string> + </attribute> + <layout class="QVBoxLayout" name="vlLocalization"> + <item> + <widget class="QGroupBox" name="gbLanguage"> + <property name="title"> + <string>Language</string> + </property> + <layout class="QVBoxLayout" name="vlLanguage"> + <item> + <widget class="QComboBox" name="cbLanguage"/> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="vsInterface"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="tabSync"> + <attribute name="title"> + <string>Sync</string> + </attribute> + <layout class="QVBoxLayout" name="vlSync"> + <item> + <widget class="QLabel" name="labSync"> + <property name="text"> + <string>Sync is not implemented at current time</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="hlButtons"> + <item> + <spacer name="hsButtons"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="cmdOK"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Apply changes</string> + </property> + <property name="text"> + <string extracomment="OK, Cancel, Apply">&OK</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="cmdCancel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Discard changes</string> + </property> + <property name="text"> + <string extracomment="OK, Cancel, Apply">&Cancel</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>cmdCancel</sender> + <signal>clicked()</signal> + <receiver>OptionsDialog</receiver> + <slot>close()</slot> + <hints> + <hint type="sourcelabel"> + <x>352</x> + <y>328</y> + </hint> + <hint type="destinationlabel"> + <x>199</x> + <y>174</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/PictureDialog.cpp b/PictureDialog.cpp index edba768..dd9cc28 100755 --- a/PictureDialog.cpp +++ b/PictureDialog.cpp @@ -1,689 +1,744 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "PictureDialog.h" -#include "PictureWidget.h" -#include "ProfileDatabase.h" -#include "ui_PictureDialog.h" -#include "SidebarGenerator.h" -#include "StandardPaths.h" -#include "PictureExport.h" -#include "StringParser.h" -#include "GlobalString.h" -#include "UiModLabel.h" -#include "AppEnv.h" - -#ifdef GTA5SYNC_WIN -#if QT_VERSION >= 0x050200 -#include <QtWinExtras/QtWin> -#include <QtWinExtras/QWinEvent> -#endif -#endif - -#include <QDesktopWidget> -#include <QJsonDocument> -#include <QApplication> -#include <QStaticText> -#include <QFileDialog> -#include <QMessageBox> -#include <QJsonObject> -#include <QVariantMap> -#include <QJsonArray> -#include <QKeyEvent> -#include <QMimeData> -#include <QToolBar> -#include <QPainter> -#include <QPicture> -#include <QBitmap> -#include <QBuffer> -#include <QImage> -#include <QDebug> -#include <QList> -#include <QDrag> -#include <QIcon> -#include <QUrl> -#include <QDir> - -PictureDialog::PictureDialog(ProfileDatabase *profileDB, CrewDatabase *crewDB, QWidget *parent) : - QDialog(parent), profileDB(profileDB), crewDB(crewDB), - ui(new Ui::PictureDialog) -{ - primaryWindow = false; - setupPictureDialog(true); -} - -PictureDialog::PictureDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::PictureDialog) -{ - primaryWindow = false; - setupPictureDialog(false); -} - -PictureDialog::PictureDialog(bool primaryWindow, ProfileDatabase *profileDB, CrewDatabase *crewDB, QWidget *parent) : - QDialog(parent), primaryWindow(primaryWindow), profileDB(profileDB), crewDB(crewDB), - ui(new Ui::PictureDialog) -{ - setupPictureDialog(true); -} - -PictureDialog::PictureDialog(bool primaryWindow, QWidget *parent) : - QDialog(parent), primaryWindow(primaryWindow), - ui(new Ui::PictureDialog) -{ - setupPictureDialog(false); -} - -void PictureDialog::setupPictureDialog(bool withDatabase_) -{ - // Set Window Flags - setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint); - - // Setup User Interface - ui->setupUi(this); - windowTitleStr = this->windowTitle(); - jsonDrawString = ui->labJSON->text(); - ui->cmdExport->setEnabled(0); - plyrsList = QStringList(); - fullscreenWidget = 0; - rqFullscreen = 0; - previewMode = 0; - naviEnabled = 0; - indexed = 0; - picArea = ""; - picTitl = ""; - picPath = ""; - created = ""; - crewID = ""; - locX = ""; - locY = ""; - locZ = ""; - smpic = 0; - - // With datebase - withDatabase = withDatabase_; - - // Avatar area - qreal screenRatio = AppEnv::screenRatio(); - if (screenRatio != 1) - { - avatarAreaPicture = QImage(":/img/avatararea.png").scaledToHeight(536 * screenRatio, Qt::FastTransformation); - } - else - { - avatarAreaPicture = QImage(":/img/avatararea.png"); - } - avatarLocX = 145; - avatarLocY = 66; - avatarSize = 470; - - // Overlay area - renderOverlayPicture(); - overlayEnabled = 1; - - // Export menu - exportMenu = new QMenu(this); - jpegExportAction = exportMenu->addAction(tr("Export as &JPG picture..."), this, SLOT(exportSnapmaticPicture())); - pgtaExportAction = exportMenu->addAction(tr("Export as >A Snapmatic..."), this, SLOT(copySnapmaticPicture())); - ui->cmdExport->setMenu(exportMenu); - - // Global map - globalMap = GlobalString::getGlobalMap(); - - // Event connects - connect(ui->labJSON, SIGNAL(resized(QSize)), this, SLOT(adaptNewDialogSize(QSize))); - - // Dialog buttons - if (QIcon::hasThemeIcon("dialog-close")) - { - ui->cmdClose->setIcon(QIcon::fromTheme("dialog-close")); - } - - installEventFilter(this); - installEventFilter(ui->labPicture); - ui->labPicture->setFixedSize(960 * screenRatio, 536 * screenRatio); - ui->labPicture->setFocusPolicy(Qt::StrongFocus); - - // Pre-adapt window for DPI - setFixedWidth(960 * screenRatio); - setFixedHeight(536 * screenRatio); -} - -PictureDialog::~PictureDialog() -{ - delete jpegExportAction; - delete pgtaExportAction; - delete exportMenu; - delete ui; -} - -void PictureDialog::closeEvent(QCloseEvent *ev) -{ - Q_UNUSED(ev) - if (primaryWindow && withDatabase) - { - emit endDatabaseThread(); - } -} - -void PictureDialog::addPreviousNextButtons() -{ - // Windows Vista additions -#ifdef GTA5SYNC_WIN -#if QT_VERSION >= 0x050200 - QPalette palette; - QToolBar *uiToolbar = new QToolBar("Picture Toolbar", this); - layout()->setMenuBar(uiToolbar); - uiToolbar->addAction(QIcon(":/img/back.png"), "", this, SLOT(previousPictureRequestedSlot())); - uiToolbar->addAction(QIcon(":/img/next.png"), "", this, SLOT(nextPictureRequestedSlot())); - ui->jsonFrame->setStyleSheet(QString("QFrame { background: %1; }").arg(palette.window().color().name())); - naviEnabled = true; -#endif -#endif -} - -void PictureDialog::adaptNewDialogSize(QSize newLabelSize) -{ - Q_UNUSED(newLabelSize) - int newDialogHeight = ui->labPicture->pixmap()->height(); - newDialogHeight = newDialogHeight + ui->jsonFrame->height(); - if (naviEnabled) newDialogHeight = newDialogHeight + layout()->menuBar()->height(); - setMinimumSize(width(), newDialogHeight); - setMaximumSize(width(), newDialogHeight); - setFixedHeight(newDialogHeight); - ui->labPicture->updateGeometry(); - ui->jsonFrame->updateGeometry(); - updateGeometry(); -} - -void PictureDialog::stylizeDialog() -{ -#ifdef GTA5SYNC_WIN -#if QT_VERSION >= 0x050200 - if (QtWin::isCompositionEnabled()) - { - QtWin::extendFrameIntoClientArea(this, 0, this->layout()->menuBar()->height(), 0, 0); - setAttribute(Qt::WA_TranslucentBackground, true); - setAttribute(Qt::WA_NoSystemBackground, false); - setStyleSheet("PictureDialog { background: transparent; }"); - } - else - { - QtWin::resetExtendedFrame(this); - setAttribute(Qt::WA_TranslucentBackground, false); - setStyleSheet(QString("PictureDialog { background: %1; }").arg(QtWin::realColorizationColor().name())); - } -#endif -#endif -} - -bool PictureDialog::event(QEvent *event) -{ -#ifdef GTA5SYNC_WIN -#if QT_VERSION >= 0x050200 - if (naviEnabled) - { - if (event->type() == QWinEvent::CompositionChange || event->type() == QWinEvent::ColorizationChange) - { - stylizeDialog(); - } - } -#endif -#endif - return QDialog::event(event); -} - -void PictureDialog::nextPictureRequestedSlot() -{ - emit nextPictureRequested(); -} - -void PictureDialog::previousPictureRequestedSlot() -{ - emit previousPictureRequested(); -} - -bool PictureDialog::eventFilter(QObject *obj, QEvent *ev) -{ - bool returnValue = false; - if (obj == this || obj == ui->labPicture) - { - if (ev->type() == QEvent::KeyPress) - { - QKeyEvent *keyEvent = (QKeyEvent*)ev; - switch (keyEvent->key()){ - case Qt::Key_Left: - emit previousPictureRequested(); - returnValue = true; - break; - case Qt::Key_Right: - emit nextPictureRequested(); - returnValue = true; - break; - case Qt::Key_E: case Qt::Key_S: case Qt::Key_Save: - ui->cmdExport->click(); - returnValue = true; - break; - case Qt::Key_1: - if (previewMode) - { - previewMode = false; - renderPicture(); - } - else - { - previewMode = true; - renderPicture(); - } - break; - case Qt::Key_2: - if (overlayEnabled) - { - overlayEnabled = false; - if (!previewMode) renderPicture(); - } - else - { - overlayEnabled = true; - if (!previewMode) renderPicture(); - } - break; -#if QT_VERSION >= 0x050300 - case Qt::Key_Exit: - ui->cmdClose->click(); - returnValue = true; - break; -#endif - case Qt::Key_Enter: case Qt::Key_Return: - on_labPicture_mouseDoubleClicked(Qt::LeftButton); - returnValue = true; - break; - case Qt::Key_Escape: - ui->cmdClose->click(); - returnValue = true; - break; - } - } - } - return returnValue; -} - -void PictureDialog::triggerFullscreenDoubeClick() -{ - on_labPicture_mouseDoubleClicked(Qt::LeftButton); -} - -void PictureDialog::exportCustomContextMenuRequestedPrivate(const QPoint &pos, bool fullscreen) -{ - rqFullscreen = fullscreen; - exportMenu->popup(pos); -} - -void PictureDialog::exportCustomContextMenuRequested(const QPoint &pos) -{ - exportCustomContextMenuRequestedPrivate(pos, true); -} - -void PictureDialog::mousePressEvent(QMouseEvent *ev) -{ - QDialog::mousePressEvent(ev); -} - -void PictureDialog::dialogNextPictureRequested() -{ - emit nextPictureRequested(); -} - -void PictureDialog::dialogPreviousPictureRequested() -{ - emit previousPictureRequested(); -} - -void PictureDialog::renderOverlayPicture() -{ - // Generating Overlay Preview - qreal screenRatio = AppEnv::screenRatio(); - QRect preferedRect = QRect(0, 0, 200 * screenRatio, 160 * screenRatio); - QString overlayText = tr("Key 1 - Avatar Preview Mode\nKey 2 - Toggle Overlay\nArrow Keys - Navigate"); - QImage overlayImage(1, 1, QImage::Format_ARGB32_Premultiplied); - overlayImage.fill(Qt::transparent); - - QPainter overlayPainter(&overlayImage); - QFont overlayPainterFont; - overlayPainterFont.setPixelSize(12 * screenRatio); - overlayPainter.setFont(overlayPainterFont); - QRect overlaySpace = overlayPainter.boundingRect(preferedRect, Qt::AlignLeft | Qt::AlignTop | Qt::TextDontClip | Qt::TextWordWrap, overlayText); - overlayPainter.end(); - - int hOverlay = Qt::AlignTop; - if (overlaySpace.height() < 74 * screenRatio) - { - hOverlay = Qt::AlignVCenter; - preferedRect.setHeight(71 * screenRatio); - overlaySpace.setHeight(80 * screenRatio); - } - else - { - overlaySpace.setHeight(overlaySpace.height() + 6 * screenRatio); - } - - overlayImage = overlayImage.scaled(overlaySpace.size()); - overlayPainter.begin(&overlayImage); - overlayPainter.setPen(QColor::fromRgb(255, 255, 255, 255)); - overlayPainter.setFont(overlayPainterFont); - overlayPainter.drawText(preferedRect, Qt::AlignLeft | hOverlay | Qt::TextDontClip | Qt::TextWordWrap, overlayText); - overlayPainter.end(); - - if (overlaySpace.width() < 194 * screenRatio) - { - overlaySpace.setWidth(200 * screenRatio); - } - else - { - overlaySpace.setWidth(overlaySpace.width() + 6 * screenRatio); - } - - QImage overlayBorderImage(overlaySpace.width(), overlaySpace.height(), QImage::Format_ARGB6666_Premultiplied); - overlayBorderImage.fill(QColor(15, 15, 15, 162)); - - overlayTempImage = QImage(overlaySpace.width(), overlaySpace.height(), QImage::Format_ARGB6666_Premultiplied); - overlayTempImage.fill(Qt::transparent); - QPainter overlayTempPainter(&overlayTempImage); - overlayTempPainter.drawImage(0, 0, overlayBorderImage); - overlayTempPainter.drawImage(3 * screenRatio, 3 * screenRatio, overlayImage); - overlayTempPainter.end(); -} - -void PictureDialog::setSnapmaticPicture(SnapmaticPicture *picture, bool readOk, bool _indexed, int _index) -{ - snapmaticPicture = QImage(); - indexed = _indexed; - index = _index; - picPath = picture->getPictureFilePath(); - smpic = picture; - if (!readOk) - { - QMessageBox::warning(this, tr("Snapmatic Picture Viewer"), tr("Failed at %1").arg(picture->getLastStep())); - return; - } - if (picture->isPicOk()) - { - snapmaticPicture = picture->getImage(); - renderPicture(); - ui->cmdExport->setEnabled(true); - } - if (picture->isJsonOk()) - { - locX = QString::number(picture->getSnapmaticProperties().location.x); - locY = QString::number(picture->getSnapmaticProperties().location.y); - locZ = QString::number(picture->getSnapmaticProperties().location.z); - if (withDatabase) - { - crewID = crewDB->getCrewName(picture->getSnapmaticProperties().crewID); - } - else - { - crewID = QString::number(picture->getSnapmaticProperties().crewID); - } - created = picture->getSnapmaticProperties().createdDateTime.toString(Qt::DefaultLocaleShortDate); - plyrsList = picture->getSnapmaticProperties().playersList; - picTitl = StringParser::escapeString(picture->getPictureTitle()); - picArea = picture->getSnapmaticProperties().location.area; - if (globalMap.contains(picArea)) - { - picAreaStr = globalMap[picArea]; - } - else - { - picAreaStr = picArea; - } - - QString plyrsStr; - if (plyrsList.length() >= 1) - { - foreach (const QString &player, plyrsList) - { - QString playerName; - if (withDatabase) - { - playerName = profileDB->getPlayerName(player.toInt()); - } - else - { - playerName = player; - } - plyrsStr.append(", <a href=\"https://socialclub.rockstargames.com/member/"); - plyrsStr.append(playerName); - plyrsStr.append("/"); - plyrsStr.append(player); - plyrsStr.append("\">"); - plyrsStr.append(playerName); - plyrsStr.append("</a>"); - } - plyrsStr.remove(0,2); - } - else - { - plyrsStr = tr("No player"); - } - - if (crewID == "") { crewID = tr("No crew"); } - - this->setWindowTitle(windowTitleStr.arg(picture->getPictureStr())); - ui->labJSON->setText(jsonDrawString.arg(locX, locY, locZ, plyrsStr, crewID, picTitl, picAreaStr, created)); - } - else - { - ui->labJSON->setText(jsonDrawString.arg("0.0", "0.0", "0.0", tr("No player"), tr("No crew"), tr("Unknown Location"))); - QMessageBox::warning(this,tr("Snapmatic Picture Viewer"),tr("Failed at %1").arg(picture->getLastStep())); - } - emit newPictureCommited(snapmaticPicture); -} - -void PictureDialog::setSnapmaticPicture(SnapmaticPicture *picture, bool readOk, int index) -{ - setSnapmaticPicture(picture, readOk, true, index); -} - -void PictureDialog::setSnapmaticPicture(SnapmaticPicture *picture, bool readOk) -{ - setSnapmaticPicture(picture, readOk, false, 0); -} - -void PictureDialog::setSnapmaticPicture(SnapmaticPicture *picture, int index) -{ - setSnapmaticPicture(picture, true, index); -} - -void PictureDialog::setSnapmaticPicture(SnapmaticPicture *picture) -{ - setSnapmaticPicture(picture, true); -} - -void PictureDialog::renderPicture() -{ - qreal screenRatio = AppEnv::screenRatio(); - if (!previewMode) - { - if (overlayEnabled) - { - QPixmap shownImagePixmap(960 * screenRatio, 536 * screenRatio); - shownImagePixmap.fill(Qt::transparent); - QPainter shownImagePainter(&shownImagePixmap); - if (screenRatio == 1) - { - shownImagePainter.drawImage(0, 0, snapmaticPicture); - shownImagePainter.drawImage(3 * screenRatio, 3 * screenRatio, overlayTempImage); - } - else - { - shownImagePainter.drawImage(0, 0, snapmaticPicture.scaledToHeight(536 * screenRatio, Qt::SmoothTransformation)); - shownImagePainter.drawImage(3 * screenRatio, 3 * screenRatio, overlayTempImage); - } - shownImagePainter.end(); - ui->labPicture->setPixmap(shownImagePixmap); - } - else - { - if (screenRatio != 1) - { - QPixmap shownImagePixmap(960 * screenRatio, 536 * screenRatio); - shownImagePixmap.fill(Qt::transparent); - QPainter shownImagePainter(&shownImagePixmap); - shownImagePainter.drawImage(0, 0, snapmaticPicture.scaledToHeight(536 * screenRatio, Qt::SmoothTransformation)); - shownImagePainter.end(); - ui->labPicture->setPixmap(shownImagePixmap); - } - else - { - ui->labPicture->setPixmap(QPixmap::fromImage(snapmaticPicture)); - } - } - } - else - { - // Generating Avatar Preview - QPixmap avatarPixmap(960 * screenRatio, 536 * screenRatio); - QPainter snapPainter(&avatarPixmap); - QFont snapPainterFont; - snapPainterFont.setPixelSize(12 * screenRatio); - if (screenRatio == 1) - { - snapPainter.drawImage(0, 0, snapmaticPicture); - } - else - { - snapPainter.drawImage(0, 0, snapmaticPicture.scaledToHeight(536 * screenRatio, Qt::SmoothTransformation)); - } - snapPainter.drawImage(0, 0, avatarAreaPicture); - snapPainter.setPen(QColor::fromRgb(255, 255, 255, 255)); - snapPainter.setFont(snapPainterFont); - snapPainter.drawText(QRect(3 * screenRatio, 3 * screenRatio, 140 * screenRatio, 60 * screenRatio), Qt::AlignLeft | Qt::TextWordWrap, tr("Avatar Preview Mode\nPress 1 for Default View")); - snapPainter.end(); - ui->labPicture->setPixmap(avatarPixmap); - } -} - -void PictureDialog::playerNameUpdated() -{ - if (plyrsList.count() >= 1) - { - QString plyrsStr; - foreach (const QString &player, plyrsList) - { - QString playerName; - if (withDatabase) - { - playerName = profileDB->getPlayerName(player.toInt()); - } - else - { - playerName = player; - } - plyrsStr.append(", <a href=\"https://socialclub.rockstargames.com/member/"); - if (playerName != player) - { - plyrsStr.append(playerName); - } - else - { - plyrsStr.append("id"); - } - plyrsStr.append("/"); - plyrsStr.append(player); - plyrsStr.append("\">"); - plyrsStr.append(playerName); - plyrsStr.append("</a>"); - } - plyrsStr.remove(0,2); - ui->labJSON->setText(jsonDrawString.arg(locX, locY, locZ, plyrsStr, crewID, picTitl, picAreaStr, created)); - } -} - -void PictureDialog::exportSnapmaticPicture() -{ - if (rqFullscreen && fullscreenWidget) - { - PictureExport::exportAsPicture(fullscreenWidget, smpic); - } - else - { - PictureExport::exportAsPicture(this, smpic); - } -} - -void PictureDialog::copySnapmaticPicture() -{ - if (rqFullscreen && fullscreenWidget) - { - PictureExport::exportAsSnapmatic(fullscreenWidget, smpic); - } - else - { - PictureExport::exportAsSnapmatic(this, smpic); - } -} - -void PictureDialog::on_labPicture_mouseDoubleClicked(Qt::MouseButton button) -{ - if (button == Qt::LeftButton) - { - QRect desktopRect = QApplication::desktop()->screenGeometry(this); - PictureWidget *pictureWidget = new PictureWidget(this); // Work! - pictureWidget->setObjectName("PictureWidget"); -#if QT_VERSION >= 0x050600 - pictureWidget->setWindowFlags(pictureWidget->windowFlags()^Qt::FramelessWindowHint^Qt::WindowStaysOnTopHint^Qt::MaximizeUsingFullscreenGeometryHint); -#else - pictureWidget->setWindowFlags(pictureWidget->windowFlags()^Qt::FramelessWindowHint^Qt::WindowStaysOnTopHint); -#endif - pictureWidget->setWindowTitle(this->windowTitle()); - pictureWidget->setStyleSheet("QLabel#pictureLabel{background-color: black;}"); - pictureWidget->setImage(snapmaticPicture, desktopRect); - pictureWidget->setModal(true); - - fullscreenWidget = pictureWidget; - QObject::connect(this, SIGNAL(newPictureCommited(QImage)), pictureWidget, SLOT(setImage(QImage))); - QObject::connect(pictureWidget, SIGNAL(nextPictureRequested()), this, SLOT(dialogNextPictureRequested())); - QObject::connect(pictureWidget, SIGNAL(previousPictureRequested()), this, SLOT(dialogPreviousPictureRequested())); - - pictureWidget->move(desktopRect.x(), desktopRect.y()); - pictureWidget->resize(desktopRect.width(), desktopRect.height()); - pictureWidget->showFullScreen(); - pictureWidget->setFocus(); - pictureWidget->raise(); - pictureWidget->exec(); - - fullscreenWidget = 0; // Work! - delete pictureWidget; // Work! - } -} - -void PictureDialog::on_labPicture_customContextMenuRequested(const QPoint &pos) -{ - exportCustomContextMenuRequestedPrivate(ui->labPicture->mapToGlobal(pos), false); -} - -bool PictureDialog::isIndexed() -{ - return indexed; -} - -int PictureDialog::getIndex() -{ - return index; -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "PictureDialog.h" +#include "PictureWidget.h" +#include "ProfileDatabase.h" +#include "ui_PictureDialog.h" +#include "SidebarGenerator.h" +#include "MapPreviewDialog.h" +#include "SnapmaticEditor.h" +#include "StandardPaths.h" +#include "PictureExport.h" +#include "StringParser.h" +#include "GlobalString.h" +#include "UiModLabel.h" +#include "AppEnv.h" + +#ifdef GTA5SYNC_WIN +#if QT_VERSION >= 0x050200 +#include <QtWinExtras/QtWin> +#include <QtWinExtras/QWinEvent> +#endif +#endif + +#include <QStringBuilder> +#include <QDesktopWidget> +#include <QJsonDocument> +#include <QApplication> +#include <QStaticText> +#include <QFileDialog> +#include <QMessageBox> +#include <QJsonObject> +#include <QVariantMap> +#include <QJsonArray> +#include <QKeyEvent> +#include <QMimeData> +#include <QToolBar> +#include <QPainter> +#include <QPicture> +#include <QBitmap> +#include <QBuffer> +#include <QImage> +#include <QDebug> +#include <QList> +#include <QDrag> +#include <QIcon> +#include <QUrl> +#include <QDir> + +PictureDialog::PictureDialog(ProfileDatabase *profileDB, CrewDatabase *crewDB, QWidget *parent) : + QDialog(parent), profileDB(profileDB), crewDB(crewDB), + ui(new Ui::PictureDialog) +{ + primaryWindow = false; + setupPictureDialog(true); +} + +PictureDialog::PictureDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::PictureDialog) +{ + primaryWindow = false; + setupPictureDialog(false); +} + +PictureDialog::PictureDialog(bool primaryWindow, ProfileDatabase *profileDB, CrewDatabase *crewDB, QWidget *parent) : + QDialog(parent), primaryWindow(primaryWindow), profileDB(profileDB), crewDB(crewDB), + ui(new Ui::PictureDialog) +{ + setupPictureDialog(true); +} + +PictureDialog::PictureDialog(bool primaryWindow, QWidget *parent) : + QDialog(parent), primaryWindow(primaryWindow), + ui(new Ui::PictureDialog) +{ + setupPictureDialog(false); +} + +void PictureDialog::setupPictureDialog(bool withDatabase_) +{ + // Set Window Flags + setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint); + + // Setup User Interface + ui->setupUi(this); + windowTitleStr = this->windowTitle(); + jsonDrawString = ui->labJSON->text(); + ui->cmdManage->setEnabled(false); + plyrsList = QStringList(); + fullscreenWidget = nullptr; + rqFullscreen = false; + previewMode = false; + naviEnabled = false; + indexed = false; + picArea = ""; + picTitl = ""; + picPath = ""; + created = ""; + crewStr = ""; + crewID = ""; + locX = ""; + locY = ""; + locZ = ""; + smpic = nullptr; + + // With datebase + withDatabase = withDatabase_; + + // Avatar area + qreal screenRatio = AppEnv::screenRatio(); + if (screenRatio != 1) + { + avatarAreaPicture = QImage(":/img/avatararea.png").scaledToHeight(536 * screenRatio, Qt::FastTransformation); + } + else + { + avatarAreaPicture = QImage(":/img/avatararea.png"); + } + avatarLocX = 145; + avatarLocY = 66; + avatarSize = 470; + + // Overlay area + renderOverlayPicture(); + overlayEnabled = true; + + // Manage menu + manageMenu = new QMenu(this); + jpegExportAction = manageMenu->addAction(tr("Export as &Picture..."), this, SLOT(exportSnapmaticPicture())); + pgtaExportAction = manageMenu->addAction(tr("Export as &Snapmatic..."), this, SLOT(copySnapmaticPicture())); + manageMenuSep1 = manageMenu->addSeparator(); + openViewerAction = manageMenu->addAction(tr("Open &Map View..."), this, SLOT(openPreviewMap())); + openViewerAction->setShortcut(Qt::Key_M); + propEditorAction = manageMenu->addAction(tr("&Edit Properties..."), this, SLOT(editSnapmaticProperties())); + ui->cmdManage->setMenu(manageMenu); + + // Global map + globalMap = GlobalString::getGlobalMap(); + + // Event connects + connect(ui->labJSON, SIGNAL(resized(QSize)), this, SLOT(adaptNewDialogSize(QSize))); + + // Dialog buttons + if (QIcon::hasThemeIcon("dialog-close")) + { + ui->cmdClose->setIcon(QIcon::fromTheme("dialog-close")); + } + + installEventFilter(this); + installEventFilter(ui->labPicture); + ui->labPicture->setFixedSize(960 * screenRatio, 536 * screenRatio); + ui->labPicture->setFocusPolicy(Qt::StrongFocus); + + // Pre-adapt window for DPI + setFixedWidth(960 * screenRatio); + setFixedHeight(536 * screenRatio); +} + +PictureDialog::~PictureDialog() +{ + delete propEditorAction; + delete openViewerAction; + delete jpegExportAction; + delete pgtaExportAction; + delete manageMenuSep1; + delete manageMenu; + delete ui; +} + +void PictureDialog::closeEvent(QCloseEvent *ev) +{ + Q_UNUSED(ev) + if (primaryWindow && withDatabase) + { + emit endDatabaseThread(); + } +} + +void PictureDialog::addPreviousNextButtons() +{ + // Windows Vista additions +#ifdef GTA5SYNC_WIN +#if QT_VERSION >= 0x050200 + QPalette palette; + QToolBar *uiToolbar = new QToolBar("Picture Toolbar", this); + layout()->setMenuBar(uiToolbar); + uiToolbar->addAction(QIcon(":/img/back.png"), "", this, SLOT(previousPictureRequestedSlot())); + uiToolbar->addAction(QIcon(":/img/next.png"), "", this, SLOT(nextPictureRequestedSlot())); + ui->jsonFrame->setStyleSheet(QString("QFrame { background: %1; }").arg(palette.window().color().name())); + naviEnabled = true; +#endif +#endif +} + +void PictureDialog::adaptNewDialogSize(QSize newLabelSize) +{ + Q_UNUSED(newLabelSize) + int newDialogHeight = ui->labPicture->pixmap()->height(); + newDialogHeight = newDialogHeight + ui->jsonFrame->height(); + if (naviEnabled) newDialogHeight = newDialogHeight + layout()->menuBar()->height(); + setMinimumSize(width(), newDialogHeight); + setMaximumSize(width(), newDialogHeight); + setFixedHeight(newDialogHeight); + ui->labPicture->updateGeometry(); + ui->jsonFrame->updateGeometry(); + updateGeometry(); +} + +void PictureDialog::stylizeDialog() +{ +#ifdef GTA5SYNC_WIN +#if QT_VERSION >= 0x050200 + if (QtWin::isCompositionEnabled()) + { + QtWin::extendFrameIntoClientArea(this, 0, this->layout()->menuBar()->height(), 0, 0); + setAttribute(Qt::WA_TranslucentBackground, true); + setAttribute(Qt::WA_NoSystemBackground, false); + setStyleSheet("PictureDialog { background: transparent; }"); + } + else + { + QtWin::resetExtendedFrame(this); + setAttribute(Qt::WA_TranslucentBackground, false); + setStyleSheet(QString("PictureDialog { background: %1; }").arg(QtWin::realColorizationColor().name())); + } +#endif +#endif +} + +bool PictureDialog::event(QEvent *event) +{ +#ifdef GTA5SYNC_WIN +#if QT_VERSION >= 0x050200 + if (naviEnabled) + { + if (event->type() == QWinEvent::CompositionChange || event->type() == QWinEvent::ColorizationChange) + { + stylizeDialog(); + } + } +#endif +#endif + return QDialog::event(event); +} + +void PictureDialog::nextPictureRequestedSlot() +{ + emit nextPictureRequested(); +} + +void PictureDialog::previousPictureRequestedSlot() +{ + emit previousPictureRequested(); +} + +bool PictureDialog::eventFilter(QObject *obj, QEvent *ev) +{ + bool returnValue = false; + if (obj == this || obj == ui->labPicture) + { + if (ev->type() == QEvent::KeyPress) + { + QKeyEvent *keyEvent = (QKeyEvent*)ev; + switch (keyEvent->key()){ + case Qt::Key_Left: + emit previousPictureRequested(); + returnValue = true; + break; + case Qt::Key_Right: + emit nextPictureRequested(); + returnValue = true; + break; + case Qt::Key_1: + if (previewMode) + { + previewMode = false; + renderPicture(); + } + else + { + previewMode = true; + renderPicture(); + } + break; + case Qt::Key_2: + if (overlayEnabled) + { + overlayEnabled = false; + if (!previewMode) renderPicture(); + } + else + { + overlayEnabled = true; + if (!previewMode) renderPicture(); + } + break; + case Qt::Key_M: + openPreviewMap(); + returnValue = true; + break; +#if QT_VERSION >= 0x050300 + case Qt::Key_Exit: + ui->cmdClose->click(); + returnValue = true; + break; +#endif + case Qt::Key_Enter: case Qt::Key_Return: + on_labPicture_mouseDoubleClicked(Qt::LeftButton); + returnValue = true; + break; + case Qt::Key_Escape: + ui->cmdClose->click(); + returnValue = true; + break; + } + } + } + return returnValue; +} + +void PictureDialog::triggerFullscreenDoubeClick() +{ + on_labPicture_mouseDoubleClicked(Qt::LeftButton); +} + +void PictureDialog::exportCustomContextMenuRequestedPrivate(const QPoint &pos, bool fullscreen) +{ + rqFullscreen = fullscreen; + manageMenu->popup(pos); +} + +void PictureDialog::exportCustomContextMenuRequested(const QPoint &pos) +{ + exportCustomContextMenuRequestedPrivate(pos, true); +} + +void PictureDialog::mousePressEvent(QMouseEvent *ev) +{ + QDialog::mousePressEvent(ev); +} + +void PictureDialog::dialogNextPictureRequested() +{ + emit nextPictureRequested(); +} + +void PictureDialog::dialogPreviousPictureRequested() +{ + emit previousPictureRequested(); +} + +void PictureDialog::renderOverlayPicture() +{ + // Generating Overlay Preview + qreal screenRatio = AppEnv::screenRatio(); + QRect preferedRect = QRect(0, 0, 200 * screenRatio, 160 * screenRatio); + QString overlayText = tr("Key 1 - Avatar Preview Mode\nKey 2 - Toggle Overlay\nArrow Keys - Navigate"); + QImage overlayImage(1, 1, QImage::Format_ARGB32_Premultiplied); + overlayImage.fill(Qt::transparent); + + QPainter overlayPainter(&overlayImage); + QFont overlayPainterFont; + overlayPainterFont.setPixelSize(12 * screenRatio); + overlayPainter.setFont(overlayPainterFont); + QRect overlaySpace = overlayPainter.boundingRect(preferedRect, Qt::AlignLeft | Qt::AlignTop | Qt::TextDontClip | Qt::TextWordWrap, overlayText); + overlayPainter.end(); + + int hOverlay = Qt::AlignTop; + if (overlaySpace.height() < 74 * screenRatio) + { + hOverlay = Qt::AlignVCenter; + preferedRect.setHeight(71 * screenRatio); + overlaySpace.setHeight(80 * screenRatio); + } + else + { + overlaySpace.setHeight(overlaySpace.height() + 6 * screenRatio); + } + + overlayImage = overlayImage.scaled(overlaySpace.size()); + overlayPainter.begin(&overlayImage); + overlayPainter.setPen(QColor::fromRgb(255, 255, 255, 255)); + overlayPainter.setFont(overlayPainterFont); + overlayPainter.drawText(preferedRect, Qt::AlignLeft | hOverlay | Qt::TextDontClip | Qt::TextWordWrap, overlayText); + overlayPainter.end(); + + if (overlaySpace.width() < 194 * screenRatio) + { + overlaySpace.setWidth(200 * screenRatio); + } + else + { + overlaySpace.setWidth(overlaySpace.width() + 6 * screenRatio); + } + + QImage overlayBorderImage(overlaySpace.width(), overlaySpace.height(), QImage::Format_ARGB6666_Premultiplied); + overlayBorderImage.fill(QColor(15, 15, 15, 162)); + + overlayTempImage = QImage(overlaySpace.width(), overlaySpace.height(), QImage::Format_ARGB6666_Premultiplied); + overlayTempImage.fill(Qt::transparent); + QPainter overlayTempPainter(&overlayTempImage); + overlayTempPainter.drawImage(0, 0, overlayBorderImage); + overlayTempPainter.drawImage(3 * screenRatio, 3 * screenRatio, overlayImage); + overlayTempPainter.end(); +} + +void PictureDialog::setSnapmaticPicture(SnapmaticPicture *picture, bool readOk, bool _indexed, int _index) +{ + if (smpic != nullptr) smpic->disconnect(this, SLOT(updated())); + snapmaticPicture = QImage(); + indexed = _indexed; + index = _index; + picPath = picture->getPictureFilePath(); + smpic = picture; + if (!readOk) + { + QMessageBox::warning(this, tr("Snapmatic Picture Viewer"), tr("Failed at %1").arg(picture->getLastStep())); + return; + } + if (picture->isPicOk()) + { + snapmaticPicture = picture->getImage(); + renderPicture(); + ui->cmdManage->setEnabled(true); + } + if (picture->isJsonOk()) + { + locX = QString::number(picture->getSnapmaticProperties().location.x); + locY = QString::number(picture->getSnapmaticProperties().location.y); + locZ = QString::number(picture->getSnapmaticProperties().location.z); + if (withDatabase) + { + crewID = QString::number(picture->getSnapmaticProperties().crewID); + crewStr = crewDB->getCrewName(picture->getSnapmaticProperties().crewID); + } + else + { + crewID = QString::number(picture->getSnapmaticProperties().crewID); + crewStr = QString::number(picture->getSnapmaticProperties().crewID); + } + created = picture->getSnapmaticProperties().createdDateTime.toString(Qt::DefaultLocaleShortDate); + plyrsList = picture->getSnapmaticProperties().playersList; + picTitl = StringParser::escapeString(picture->getPictureTitle()); + picArea = picture->getSnapmaticProperties().location.area; + if (globalMap.contains(picArea)) + { + picAreaStr = globalMap[picArea]; + } + else + { + picAreaStr = picArea; + } + + this->setWindowTitle(windowTitleStr.arg(picture->getPictureStr())); + ui->labJSON->setText(jsonDrawString.arg(locX, locY, locZ, generatePlayersString(), generateCrewString(), picTitl, picAreaStr, created)); + } + else + { + ui->labJSON->setText(jsonDrawString.arg("0", "0", "0", tr("No Players"), tr("No Crew"), tr("Unknown Location"))); + QMessageBox::warning(this,tr("Snapmatic Picture Viewer"),tr("Failed at %1").arg(picture->getLastStep())); + } + QObject::connect(smpic, SIGNAL(updated()), this, SLOT(updated())); + emit newPictureCommited(snapmaticPicture); +} + +void PictureDialog::setSnapmaticPicture(SnapmaticPicture *picture, bool readOk, int index) +{ + setSnapmaticPicture(picture, readOk, true, index); +} + +void PictureDialog::setSnapmaticPicture(SnapmaticPicture *picture, bool readOk) +{ + setSnapmaticPicture(picture, readOk, false, 0); +} + +void PictureDialog::setSnapmaticPicture(SnapmaticPicture *picture, int index) +{ + setSnapmaticPicture(picture, true, index); +} + +void PictureDialog::setSnapmaticPicture(SnapmaticPicture *picture) +{ + setSnapmaticPicture(picture, true); +} + +void PictureDialog::renderPicture() +{ + qreal screenRatio = AppEnv::screenRatio(); + if (!previewMode) + { + if (overlayEnabled) + { + QPixmap shownImagePixmap(960 * screenRatio, 536 * screenRatio); + shownImagePixmap.fill(Qt::transparent); + QPainter shownImagePainter(&shownImagePixmap); + if (screenRatio == 1) + { + shownImagePainter.drawImage(0, 0, snapmaticPicture); + shownImagePainter.drawImage(3 * screenRatio, 3 * screenRatio, overlayTempImage); + } + else + { + shownImagePainter.drawImage(0, 0, snapmaticPicture.scaledToHeight(536 * screenRatio, Qt::SmoothTransformation)); + shownImagePainter.drawImage(3 * screenRatio, 3 * screenRatio, overlayTempImage); + } + shownImagePainter.end(); + ui->labPicture->setPixmap(shownImagePixmap); + } + else + { + if (screenRatio != 1) + { + QPixmap shownImagePixmap(960 * screenRatio, 536 * screenRatio); + shownImagePixmap.fill(Qt::transparent); + QPainter shownImagePainter(&shownImagePixmap); + shownImagePainter.drawImage(0, 0, snapmaticPicture.scaledToHeight(536 * screenRatio, Qt::SmoothTransformation)); + shownImagePainter.end(); + ui->labPicture->setPixmap(shownImagePixmap); + } + else + { + ui->labPicture->setPixmap(QPixmap::fromImage(snapmaticPicture)); + } + } + } + else + { + // Generating Avatar Preview + QPixmap avatarPixmap(960 * screenRatio, 536 * screenRatio); + QPainter snapPainter(&avatarPixmap); + QFont snapPainterFont; + snapPainterFont.setPixelSize(12 * screenRatio); + if (screenRatio == 1) + { + snapPainter.drawImage(0, 0, snapmaticPicture); + } + else + { + snapPainter.drawImage(0, 0, snapmaticPicture.scaledToHeight(536 * screenRatio, Qt::SmoothTransformation)); + } + snapPainter.drawImage(0, 0, avatarAreaPicture); + snapPainter.setPen(QColor::fromRgb(255, 255, 255, 255)); + snapPainter.setFont(snapPainterFont); + snapPainter.drawText(QRect(3 * screenRatio, 3 * screenRatio, 140 * screenRatio, 536 * screenRatio), Qt::AlignLeft | Qt::TextWordWrap, tr("Avatar Preview Mode\nPress 1 for Default View")); + snapPainter.end(); + ui->labPicture->setPixmap(avatarPixmap); + } +} + +void PictureDialog::crewNameUpdated() +{ + if (withDatabase && crewID == crewStr) + { + crewStr = crewDB->getCrewName(crewID.toInt()); + ui->labJSON->setText(jsonDrawString.arg(locX, locY, locZ, generatePlayersString(), generateCrewString(), picTitl, picAreaStr, created)); + } +} + +void PictureDialog::playerNameUpdated() +{ + if (plyrsList.count() >= 1) + { + ui->labJSON->setText(jsonDrawString.arg(locX, locY, locZ, generatePlayersString(), generateCrewString(), picTitl, picAreaStr, created)); + } +} + +QString PictureDialog::generateCrewString() +{ + if (crewID != "0" && !crewID.isEmpty()) + { + return QString("<a href=\"https://socialclub.rockstargames.com/crew/" % QString(crewStr).replace(" ", "_") % "/" % crewID % "\">" % crewStr % "</a>"); + } + return tr("No Crew"); +} + +QString PictureDialog::generatePlayersString() +{ + QString plyrsStr; + if (plyrsList.length() >= 1) + { + foreach (const QString &player, plyrsList) + { + QString playerName; + if (withDatabase) + { + playerName = profileDB->getPlayerName(player.toInt()); + } + else + { + playerName = player; + } + plyrsStr += ", <a href=\"https://socialclub.rockstargames.com/member/" % playerName % "/" % player % "\">" % playerName % "</a>"; + } + plyrsStr.remove(0,2); + } + else + { + plyrsStr = tr("No Players"); + } + return plyrsStr; +} + +void PictureDialog::exportSnapmaticPicture() +{ + if (rqFullscreen && fullscreenWidget != nullptr) + { + PictureExport::exportAsPicture(fullscreenWidget, smpic); + } + else + { + PictureExport::exportAsPicture(this, smpic); + } +} + +void PictureDialog::copySnapmaticPicture() +{ + if (rqFullscreen && fullscreenWidget != nullptr) + { + PictureExport::exportAsSnapmatic(fullscreenWidget, smpic); + } + else + { + PictureExport::exportAsSnapmatic(this, smpic); + } +} + +void PictureDialog::on_labPicture_mouseDoubleClicked(Qt::MouseButton button) +{ + if (button == Qt::LeftButton) + { + QRect desktopRect = QApplication::desktop()->screenGeometry(this); + PictureWidget *pictureWidget = new PictureWidget(this); // Work! + pictureWidget->setObjectName("PictureWidget"); +#if QT_VERSION >= 0x050600 + pictureWidget->setWindowFlags(pictureWidget->windowFlags()^Qt::FramelessWindowHint^Qt::WindowStaysOnTopHint^Qt::MaximizeUsingFullscreenGeometryHint); +#else + pictureWidget->setWindowFlags(pictureWidget->windowFlags()^Qt::FramelessWindowHint^Qt::WindowStaysOnTopHint); +#endif + pictureWidget->setWindowTitle(this->windowTitle()); + pictureWidget->setStyleSheet("QLabel#pictureLabel{background-color: black;}"); + pictureWidget->setImage(snapmaticPicture, desktopRect); + pictureWidget->setModal(true); + + fullscreenWidget = pictureWidget; + QObject::connect(this, SIGNAL(newPictureCommited(QImage)), pictureWidget, SLOT(setImage(QImage))); + QObject::connect(pictureWidget, SIGNAL(nextPictureRequested()), this, SLOT(dialogNextPictureRequested())); + QObject::connect(pictureWidget, SIGNAL(previousPictureRequested()), this, SLOT(dialogPreviousPictureRequested())); + + pictureWidget->move(desktopRect.x(), desktopRect.y()); + pictureWidget->resize(desktopRect.width(), desktopRect.height()); + pictureWidget->showFullScreen(); + pictureWidget->setFocus(); + pictureWidget->raise(); + pictureWidget->exec(); + + fullscreenWidget = nullptr; // Work! + delete pictureWidget; // Work! + } +} + +void PictureDialog::on_labPicture_customContextMenuRequested(const QPoint &pos) +{ + exportCustomContextMenuRequestedPrivate(ui->labPicture->mapToGlobal(pos), false); +} + +bool PictureDialog::isIndexed() +{ + return indexed; +} + +int PictureDialog::getIndex() +{ + return index; +} + +void PictureDialog::openPreviewMap() +{ + MapPreviewDialog *mapPreviewDialog; + if (rqFullscreen && fullscreenWidget != nullptr) + { + mapPreviewDialog = new MapPreviewDialog(fullscreenWidget); + } + else + { + mapPreviewDialog = new MapPreviewDialog(this); + } + mapPreviewDialog->setWindowIcon(windowIcon()); + mapPreviewDialog->setModal(true); + mapPreviewDialog->drawPointOnMap(smpic->getSnapmaticProperties().location.x, smpic->getSnapmaticProperties().location.y); + mapPreviewDialog->show(); + mapPreviewDialog->exec(); + delete mapPreviewDialog; +} + +void PictureDialog::editSnapmaticProperties() +{ + SnapmaticEditor *snapmaticEditor; + if (rqFullscreen && fullscreenWidget != nullptr) + { + snapmaticEditor = new SnapmaticEditor(crewDB, fullscreenWidget); + } + else + { + snapmaticEditor = new SnapmaticEditor(crewDB, this); + } + snapmaticEditor->setWindowFlags(snapmaticEditor->windowFlags()^Qt::WindowContextHelpButtonHint); + snapmaticEditor->setWindowIcon(windowIcon()); + snapmaticEditor->setSnapmaticPicture(smpic); + snapmaticEditor->setModal(true); + snapmaticEditor->exec(); + delete snapmaticEditor; +} + +void PictureDialog::updated() +{ + if (withDatabase) + { + crewID = QString::number(smpic->getSnapmaticProperties().crewID); + crewStr = crewDB->getCrewName(smpic->getSnapmaticProperties().crewID); + } + else + { + crewID = QString::number(smpic->getSnapmaticProperties().crewID); + crewStr = QString::number(smpic->getSnapmaticProperties().crewID); + } + picTitl = StringParser::escapeString(smpic->getPictureTitle()); + ui->labJSON->setText(jsonDrawString.arg(locX, locY, locZ, generatePlayersString(), generateCrewString(), picTitl, picAreaStr, created)); +} diff --git a/PictureDialog.h b/PictureDialog.h index 7cd6958..6a02338 100755 --- a/PictureDialog.h +++ b/PictureDialog.h @@ -1,123 +1,133 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef PICTUREDIALOG_H -#define PICTUREDIALOG_H - -#include "SnapmaticPicture.h" -#include "ProfileDatabase.h" -#include "CrewDatabase.h" -#include <QMouseEvent> -#include <QDialog> -#include <QEvent> -#include <QMenu> - -namespace Ui { -class PictureDialog; -} - -class PictureDialog : public QDialog -{ - Q_OBJECT -public: - explicit PictureDialog(ProfileDatabase *profileDB, CrewDatabase *crewDB, QWidget *parent = 0); - explicit PictureDialog(QWidget *parent = 0); - explicit PictureDialog(bool primaryWindow, ProfileDatabase *profileDB, CrewDatabase *crewDB, QWidget *parent = 0); - explicit PictureDialog(bool primaryWindow, QWidget *parent = 0); - void setupPictureDialog(bool withDatabase); - void setSnapmaticPicture(SnapmaticPicture *picture, bool readOk, bool indexed, int index); - void setSnapmaticPicture(SnapmaticPicture *picture, bool readOk, int index); - void setSnapmaticPicture(SnapmaticPicture *picture, bool readOk); - void setSnapmaticPicture(SnapmaticPicture *picture, int index); - void setSnapmaticPicture(SnapmaticPicture *picture); - void addPreviousNextButtons(); - void stylizeDialog(); - bool isIndexed(); - int getIndex(); - ~PictureDialog(); - -public slots: - void playerNameUpdated(); - void dialogNextPictureRequested(); - void dialogPreviousPictureRequested(); - void adaptNewDialogSize(QSize newLabelSize); - void exportCustomContextMenuRequested(const QPoint &pos); - -private slots: - void copySnapmaticPicture(); - void exportSnapmaticPicture(); - void triggerFullscreenDoubeClick(); - void on_labPicture_mouseDoubleClicked(Qt::MouseButton button); - void on_labPicture_customContextMenuRequested(const QPoint &pos); - void exportCustomContextMenuRequestedPrivate(const QPoint &pos, bool fullscreen); - void nextPictureRequestedSlot(); - void previousPictureRequestedSlot(); - void renderOverlayPicture(); - void renderPicture(); - -signals: - void nextPictureRequested(); - void previousPictureRequested(); - void newPictureCommited(QImage picture); - void endDatabaseThread(); - -protected: - void closeEvent(QCloseEvent *ev); - bool eventFilter(QObject *obj, QEvent *ev); - void mousePressEvent(QMouseEvent *ev); - bool event(QEvent *event); - -private: - bool primaryWindow; - ProfileDatabase *profileDB; - CrewDatabase *crewDB; - Ui::PictureDialog *ui; - QMap<QString, QString> globalMap; - SnapmaticPicture *smpic; - QWidget *fullscreenWidget; - QAction *jpegExportAction; - QAction *pgtaExportAction; - QImage avatarAreaPicture; - QImage snapmaticPicture; - QImage overlayTempImage; - QString jsonDrawString; - QString windowTitleStr; - QStringList plyrsList; - QString picAreaStr; - QString picArea; - QString picTitl; - QString picPath; - QString created; - QString crewID; - QString locX; - QString locY; - QString locZ; - bool overlayEnabled; - bool withDatabase; - bool rqFullscreen; - bool naviEnabled; - bool previewMode; - bool indexed; - int index; - int avatarLocX; - int avatarLocY; - int avatarSize; - QMenu *exportMenu; -}; - -#endif // PICTUREDIALOG_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef PICTUREDIALOG_H +#define PICTUREDIALOG_H + +#include "SnapmaticPicture.h" +#include "ProfileDatabase.h" +#include "CrewDatabase.h" +#include <QMouseEvent> +#include <QDialog> +#include <QEvent> +#include <QMenu> + +namespace Ui { +class PictureDialog; +} + +class PictureDialog : public QDialog +{ + Q_OBJECT +public: + explicit PictureDialog(ProfileDatabase *profileDB, CrewDatabase *crewDB, QWidget *parent = 0); + explicit PictureDialog(QWidget *parent = 0); + explicit PictureDialog(bool primaryWindow, ProfileDatabase *profileDB, CrewDatabase *crewDB, QWidget *parent = 0); + explicit PictureDialog(bool primaryWindow, QWidget *parent = 0); + void setupPictureDialog(bool withDatabase); + void setSnapmaticPicture(SnapmaticPicture *picture, bool readOk, bool indexed, int index); + void setSnapmaticPicture(SnapmaticPicture *picture, bool readOk, int index); + void setSnapmaticPicture(SnapmaticPicture *picture, bool readOk); + void setSnapmaticPicture(SnapmaticPicture *picture, int index); + void setSnapmaticPicture(SnapmaticPicture *picture); + void addPreviousNextButtons(); + void stylizeDialog(); + bool isIndexed(); + int getIndex(); + ~PictureDialog(); + +public slots: + void crewNameUpdated(); + void playerNameUpdated(); + void dialogNextPictureRequested(); + void dialogPreviousPictureRequested(); + void adaptNewDialogSize(QSize newLabelSize); + void exportCustomContextMenuRequested(const QPoint &pos); + +private slots: + void copySnapmaticPicture(); + void exportSnapmaticPicture(); + void triggerFullscreenDoubeClick(); + void on_labPicture_mouseDoubleClicked(Qt::MouseButton button); + void on_labPicture_customContextMenuRequested(const QPoint &pos); + void exportCustomContextMenuRequestedPrivate(const QPoint &pos, bool fullscreen); + void nextPictureRequestedSlot(); + void previousPictureRequestedSlot(); + void editSnapmaticProperties(); + void renderOverlayPicture(); + void renderPicture(); + void openPreviewMap(); + void updated(); + +signals: + void nextPictureRequested(); + void previousPictureRequested(); + void newPictureCommited(QImage picture); + void endDatabaseThread(); + +protected: + void closeEvent(QCloseEvent *ev); + bool eventFilter(QObject *obj, QEvent *ev); + void mousePressEvent(QMouseEvent *ev); + bool event(QEvent *event); + +private: + QString generateCrewString(); + QString generatePlayersString(); + bool primaryWindow; + ProfileDatabase *profileDB; + CrewDatabase *crewDB; + Ui::PictureDialog *ui; + QMap<QString, QString> globalMap; + SnapmaticPicture *smpic; + QWidget *fullscreenWidget; + QAction *jpegExportAction; + QAction *pgtaExportAction; + QAction *propEditorAction; + QAction *openViewerAction; + QAction *manageMenuSep1; + QImage avatarAreaPicture; + QImage snapmaticPicture; + QImage overlayTempImage; + QString jsonDrawString; + QString windowTitleStr; + QStringList plyrsList; + QString picAreaStr; + QString picArea; + QString picTitl; + QString picPath; + QString created; + QString crewStr; + QString crewID; + QString locX; + QString locY; + QString locZ; + bool overlayEnabled; + bool withDatabase; + bool rqFullscreen; + bool naviEnabled; + bool previewMode; + bool indexed; + int index; + int avatarLocX; + int avatarLocY; + int avatarSize; + QMenu *manageMenu; +}; + +#endif // PICTUREDIALOG_H diff --git a/PictureDialog.ui b/PictureDialog.ui index 44eb828..dc10eeb 100755 --- a/PictureDialog.ui +++ b/PictureDialog.ui @@ -1,254 +1,254 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>PictureDialog</class> - <widget class="QDialog" name="PictureDialog"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>960</width> - <height>602</height> - </rect> - </property> - <property name="windowTitle"> - <string>%1 - Snapmatic Picture Viewer</string> - </property> - <layout class="QVBoxLayout" name="vlPictureLayout"> - <property name="spacing"> - <number>0</number> - </property> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="UiModLabel" name="labPicture"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>1</verstretch> - </sizepolicy> - </property> - <property name="contextMenuPolicy"> - <enum>Qt::CustomContextMenu</enum> - </property> - <property name="text"> - <string/> - </property> - <property name="pixmap"> - <pixmap resource="res/app.qrc">:/img/960x536.png</pixmap> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - </widget> - </item> - <item> - <spacer name="vsJSONUpper"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QFrame" name="jsonFrame"> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Plain</enum> - </property> - <property name="lineWidth"> - <number>0</number> - </property> - <layout class="QHBoxLayout" name="hlJson"> - <property name="spacing"> - <number>0</number> - </property> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <layout class="QHBoxLayout" name="jsonLayout"> - <property name="leftMargin"> - <number>4</number> - </property> - <property name="topMargin"> - <number>10</number> - </property> - <property name="rightMargin"> - <number>4</number> - </property> - <property name="bottomMargin"> - <number>4</number> - </property> - <item> - <widget class="UiModLabel" name="labJSON"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string><span style=" font-weight:600;">Title: </span>%6<br/> -<span style=" font-weight:600;">Location: </span>%7 (%1, %2, %3)<br/> -<span style=" font-weight:600;">Players: </span>%4 (Crew %5)<br/> -<span style=" font-weight:600;">Created: </span>%8</string> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - <property name="openExternalLinks"> - <bool>true</bool> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - <item> - <layout class="QVBoxLayout" name="vlButtons"> - <property name="spacing"> - <number>6</number> - </property> - <property name="rightMargin"> - <number>5</number> - </property> - <property name="bottomMargin"> - <number>5</number> - </property> - <item> - <spacer name="vsButtons"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Expanding</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <layout class="QHBoxLayout" name="hlButtons"> - <property name="spacing"> - <number>6</number> - </property> - <item> - <widget class="QPushButton" name="cmdExport"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="focusPolicy"> - <enum>Qt::NoFocus</enum> - </property> - <property name="toolTip"> - <string>Export picture</string> - </property> - <property name="text"> - <string>&Export</string> - </property> - <property name="autoDefault"> - <bool>false</bool> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="cmdClose"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="focusPolicy"> - <enum>Qt::NoFocus</enum> - </property> - <property name="toolTip"> - <string>Close</string> - </property> - <property name="text"> - <string>&Close</string> - </property> - <property name="autoDefault"> - <bool>false</bool> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </item> - </layout> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - <customwidgets> - <customwidget> - <class>UiModLabel</class> - <extends>QLabel</extends> - <header>uimod/UiModLabel.h</header> - <slots> - <signal>mouseMoved()</signal> - <signal>mouseReleased()</signal> - <signal>mousePressed()</signal> - <signal>mouseDoubleClicked()</signal> - </slots> - </customwidget> - </customwidgets> - <resources> - <include location="res/app.qrc"/> - </resources> - <connections> - <connection> - <sender>cmdClose</sender> - <signal>clicked()</signal> - <receiver>PictureDialog</receiver> - <slot>close()</slot> - <hints> - <hint type="sourcelabel"> - <x>912</x> - <y>514</y> - </hint> - <hint type="destinationlabel"> - <x>479</x> - <y>267</y> - </hint> - </hints> - </connection> - </connections> -</ui> +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>PictureDialog</class> + <widget class="QDialog" name="PictureDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>960</width> + <height>618</height> + </rect> + </property> + <property name="windowTitle"> + <string>%1 - Snapmatic Picture Viewer</string> + </property> + <layout class="QVBoxLayout" name="vlPictureLayout"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="UiModLabel" name="labPicture"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>1</verstretch> + </sizepolicy> + </property> + <property name="contextMenuPolicy"> + <enum>Qt::CustomContextMenu</enum> + </property> + <property name="text"> + <string/> + </property> + <property name="pixmap"> + <pixmap resource="res/app.qrc">:/img/960x536.png</pixmap> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <spacer name="vsJSONUpper"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QFrame" name="jsonFrame"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <layout class="QHBoxLayout" name="hlJson"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <layout class="QHBoxLayout" name="jsonLayout"> + <property name="leftMargin"> + <number>4</number> + </property> + <property name="topMargin"> + <number>10</number> + </property> + <property name="rightMargin"> + <number>4</number> + </property> + <property name="bottomMargin"> + <number>4</number> + </property> + <item> + <widget class="UiModLabel" name="labJSON"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string><span style=" font-weight:600;">Title: </span>%6<br/> +<span style=" font-weight:600;">Location: </span>%7 (%1, %2, %3)<br/> +<span style=" font-weight:600;">Players: </span>%4 (Crew %5)<br/> +<span style=" font-weight:600;">Created: </span>%8</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + <property name="openExternalLinks"> + <bool>true</bool> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item> + <layout class="QVBoxLayout" name="vlButtons"> + <property name="spacing"> + <number>6</number> + </property> + <property name="rightMargin"> + <number>5</number> + </property> + <property name="bottomMargin"> + <number>5</number> + </property> + <item> + <spacer name="vsButtons"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QHBoxLayout" name="hlButtons"> + <property name="spacing"> + <number>6</number> + </property> + <item> + <widget class="QPushButton" name="cmdManage"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="focusPolicy"> + <enum>Qt::NoFocus</enum> + </property> + <property name="toolTip"> + <string>Manage picture</string> + </property> + <property name="text"> + <string>&Manage</string> + </property> + <property name="autoDefault"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="cmdClose"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="focusPolicy"> + <enum>Qt::NoFocus</enum> + </property> + <property name="toolTip"> + <string>Close viewer</string> + </property> + <property name="text"> + <string>&Close</string> + </property> + <property name="autoDefault"> + <bool>false</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>UiModLabel</class> + <extends>QLabel</extends> + <header>uimod/UiModLabel.h</header> + <slots> + <signal>mouseMoved()</signal> + <signal>mouseReleased()</signal> + <signal>mousePressed()</signal> + <signal>mouseDoubleClicked()</signal> + </slots> + </customwidget> + </customwidgets> + <resources> + <include location="res/app.qrc"/> + </resources> + <connections> + <connection> + <sender>cmdClose</sender> + <signal>clicked()</signal> + <receiver>PictureDialog</receiver> + <slot>close()</slot> + <hints> + <hint type="sourcelabel"> + <x>912</x> + <y>514</y> + </hint> + <hint type="destinationlabel"> + <x>479</x> + <y>267</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/PictureExport.cpp b/PictureExport.cpp index ad20e9a..d3fb040 100755 --- a/PictureExport.cpp +++ b/PictureExport.cpp @@ -1,310 +1,312 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "config.h" -#include "PictureExport.h" -#include "PictureDialog.h" -#include "StandardPaths.h" -#include "SidebarGenerator.h" -#include <QDesktopWidget> -#include <QApplication> -#include <QMessageBox> -#include <QFileDialog> -#include <QSettings> -#include <QDebug> - -PictureExport::PictureExport() -{ - -} - -void PictureExport::exportAsPicture(QWidget *parent, SnapmaticPicture *picture) -{ - QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); - - // Picture Settings - // Quality Settings - settings.beginGroup("Pictures"); - int defaultQuality = 100; - QSize defExportSize = QSize(960, 536); - int customQuality = settings.value("CustomQuality", defaultQuality).toInt(); - if (customQuality < 1 || customQuality > 100) - { - customQuality = 100; - } - bool useCustomQuality = settings.value("CustomQualityEnabled", false).toBool(); - - // Size Settings - QSize cusExportSize = settings.value("CustomSize", defExportSize).toSize(); - if (cusExportSize.width() > 3840) - { - cusExportSize.setWidth(3840); - } - else if (cusExportSize.height() > 2160) - { - cusExportSize.setHeight(2160); - } - if (cusExportSize.width() < 1) - { - cusExportSize.setWidth(1); - } - else if (cusExportSize.height() < 1) - { - cusExportSize.setHeight(1); - } - QString sizeMode = settings.value("ExportSizeMode", "Default").toString(); - Qt::AspectRatioMode aspectRatio = (Qt::AspectRatioMode)settings.value("AspectRatio", Qt::KeepAspectRatio).toInt(); - QString defaultExportFormat = settings.value("DefaultExportFormat", ".jpg").toString(); - settings.endGroup(); - // End Picture Settings - - settings.beginGroup("FileDialogs"); - settings.beginGroup("ExportAsPicture"); - -fileDialogPreSave: //Work? - QFileDialog fileDialog(parent); - fileDialog.setFileMode(QFileDialog::AnyFile); - fileDialog.setViewMode(QFileDialog::Detail); - fileDialog.setAcceptMode(QFileDialog::AcceptSave); - fileDialog.setOption(QFileDialog::DontUseNativeDialog, false); - fileDialog.setOption(QFileDialog::DontConfirmOverwrite, true); - fileDialog.setDefaultSuffix("suffix"); - fileDialog.setWindowFlags(fileDialog.windowFlags()^Qt::WindowContextHelpButtonHint); - fileDialog.setWindowTitle(PictureDialog::tr("Export as JPG picture...")); - fileDialog.setLabelText(QFileDialog::Accept, PictureDialog::tr("Export")); - - QStringList filters; - filters << PictureDialog::tr("JPEG picture (*.jpg)"); - filters << PictureDialog::tr("Portable Network Graphics (*.png)"); - fileDialog.setNameFilters(filters); - - QList<QUrl> sidebarUrls = SidebarGenerator::generateSidebarUrls(fileDialog.sidebarUrls()); - - fileDialog.setSidebarUrls(sidebarUrls); - fileDialog.setDirectory(settings.value("Directory", StandardPaths::picturesLocation()).toString()); - fileDialog.restoreGeometry(settings.value(parent->objectName() + "+Geomtery", "").toByteArray()); - - QString newPictureFileName = getPictureFileName(picture) + defaultExportFormat; - fileDialog.selectFile(newPictureFileName); - - if (fileDialog.exec()) - { - QStringList selectedFiles = fileDialog.selectedFiles(); - if (selectedFiles.length() == 1) - { - QString saveFileFormat; - QString selectedFile = selectedFiles.at(0); - - if (selectedFile.right(4) == ".jpg") - { - saveFileFormat = "JPEG"; - } - else if (selectedFile.right(4) == ".jpeg") - { - saveFileFormat = "JPEG"; - } - else if (selectedFile.right(4) == ".png") - { - saveFileFormat = "PNG"; - } - else if (selectedFile.right(7) == ".suffix") - { - if (fileDialog.selectedNameFilter() == "JPEG picture (*.jpg)") - { - selectedFile.replace(".suffix", ".jpg"); - } - else if (fileDialog.selectedNameFilter() == "Portable Network Graphics (*.png)") - { - selectedFile.replace(".suffix", ".png"); - } - else - { - selectedFile.replace(".suffix", ".jpg"); - } - } - - if (QFile::exists(selectedFile)) - { - if (QMessageBox::Yes == QMessageBox::warning(parent, PictureDialog::tr("Export as JPG picture"), PictureDialog::tr("Overwrite %1 with current Snapmatic picture?").arg("\""+selectedFile+"\""), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)) - { - if (!QFile::remove(selectedFile)) - { - QMessageBox::warning(parent, PictureDialog::tr("Export as JPG picture"), PictureDialog::tr("Failed to overwrite %1 with current Snapmatic picture").arg("\""+selectedFile+"\"")); - goto fileDialogPreSave; //Work? - } - } - else - { - goto fileDialogPreSave; //Work? - } - } - - // Scale Picture - QImage exportPicture = picture->getImage(); - if (sizeMode == "Desktop") - { - QRect desktopResolution = QApplication::desktop()->screenGeometry(); - exportPicture = exportPicture.scaled(desktopResolution.width(), desktopResolution.height(), aspectRatio, Qt::SmoothTransformation); - } - else if (sizeMode == "Custom") - { - exportPicture = exportPicture.scaled(cusExportSize, aspectRatio, Qt::SmoothTransformation); - } - - bool isSaved; - if (useCustomQuality) - { - isSaved = exportPicture.save(selectedFile, saveFileFormat.toStdString().c_str(), customQuality); - } - else - { - isSaved = exportPicture.save(selectedFile, saveFileFormat.toStdString().c_str(), 100); - } - - if (!isSaved) - { - QMessageBox::warning(parent, PictureDialog::tr("Export as JPG picture"), PictureDialog::tr("Failed to export current Snapmatic picture")); - goto fileDialogPreSave; //Work? - } - } - else - { - QMessageBox::warning(parent, PictureDialog::tr("Export as JPG picture"), PictureDialog::tr("No valid file is selected")); - goto fileDialogPreSave; //Work? - } - } - - settings.setValue(parent->objectName() + "+Geometry", fileDialog.saveGeometry()); - settings.setValue("Directory", fileDialog.directory().absolutePath()); - settings.endGroup(); - settings.endGroup(); -} - -void PictureExport::exportAsSnapmatic(QWidget *parent, SnapmaticPicture *picture) -{ - QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); - settings.beginGroup("FileDialogs"); - settings.beginGroup("ExportAsSnapmatic"); - - QString adjustedPicPath = picture->getPictureFileName(); - if (adjustedPicPath.right(7) == ".hidden") // for the hidden file system - { - adjustedPicPath.remove(adjustedPicPath.length() - 7, 7); - } - -fileDialogPreSave: //Work? - QFileInfo sgdFileInfo(adjustedPicPath); - QFileDialog fileDialog(parent); - fileDialog.setFileMode(QFileDialog::AnyFile); - fileDialog.setViewMode(QFileDialog::Detail); - fileDialog.setAcceptMode(QFileDialog::AcceptSave); - fileDialog.setOption(QFileDialog::DontUseNativeDialog, false); - fileDialog.setOption(QFileDialog::DontConfirmOverwrite, true); - fileDialog.setDefaultSuffix(".rem"); - fileDialog.setWindowFlags(fileDialog.windowFlags()^Qt::WindowContextHelpButtonHint); - fileDialog.setWindowTitle(PictureDialog::tr("Export as GTA Snapmatic...")); - fileDialog.setLabelText(QFileDialog::Accept, PictureDialog::tr("Export")); - - QStringList filters; - filters << PictureDialog::tr("GTA V Export (*.g5e)"); - filters << PictureDialog::tr("GTA V Raw Export (*.auto)"); - filters << PictureDialog::tr("Snapmatic pictures (PGTA*)"); - fileDialog.setNameFilters(filters); - - QList<QUrl> sidebarUrls = SidebarGenerator::generateSidebarUrls(fileDialog.sidebarUrls()); - - fileDialog.setSidebarUrls(sidebarUrls); - fileDialog.setDirectory(settings.value("Directory", StandardPaths::documentsLocation()).toString()); - fileDialog.selectFile(QString(picture->getExportPictureFileName() + ".g5e")); - fileDialog.restoreGeometry(settings.value(parent->objectName() + "+Geomtery", "").toByteArray()); - - - if (fileDialog.exec()) - { - QStringList selectedFiles = fileDialog.selectedFiles(); - if (selectedFiles.length() == 1) - { - QString selectedFile = selectedFiles.at(0); - - if (QFile::exists(selectedFile)) - { - if (QMessageBox::Yes == QMessageBox::warning(parent, PictureDialog::tr("Export as GTA Snapmatic"), PictureDialog::tr("Overwrite %1 with current Snapmatic picture?").arg("\""+selectedFile+"\""), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)) - { - if (!QFile::remove(selectedFile)) - { - QMessageBox::warning(parent, PictureDialog::tr("Export as GTA Snapmatic"), PictureDialog::tr("Failed to overwrite %1 with current Snapmatic picture").arg("\""+selectedFile+"\"")); - goto fileDialogPreSave; //Work? - } - } - else - { - goto fileDialogPreSave; //Work? - } - } - - if (selectedFile.right(4) == ".g5e") - { - bool isExported = picture->exportPicture(selectedFile, "G5E"); - if (!isExported) - { - QMessageBox::warning(parent, PictureDialog::tr("Export as GTA Snapmatic"), PictureDialog::tr("Failed to export current Snapmatic picture")); - goto fileDialogPreSave; //Work? - } - } - else - { - bool isAutoExt = false; - if (selectedFile.right(5) == ".auto") - { - isAutoExt = true; - QString dirPath = QFileInfo(selectedFile).dir().path(); - QString stockFileName = sgdFileInfo.fileName(); - selectedFile = dirPath + "/" + stockFileName; - } - else if (selectedFile.right(4) == ".rem") - { - selectedFile.remove(".rem"); - } - bool isCopied = picture->exportPicture(selectedFile, "PGTA"); - if (!isCopied) - { - QMessageBox::warning(parent, PictureDialog::tr("Export as GTA Snapmatic"), PictureDialog::tr("Failed to export current Snapmatic picture")); - goto fileDialogPreSave; //Work? - } - else - { - if (isAutoExt) QMessageBox::information(parent, PictureDialog::tr("Export as GTA Snapmatic"), PictureDialog::tr("Exported Snapmatic to \"%1\" because of using the .auto extension.").arg(selectedFile)); - } - } - } - else - { - QMessageBox::warning(parent, PictureDialog::tr("Export as GTA Snapmatic"), PictureDialog::tr("No valid file is selected")); - goto fileDialogPreSave; //Work? - } - } - - settings.setValue(parent->objectName() + "+Geometry", fileDialog.saveGeometry()); - settings.setValue("Directory", fileDialog.directory().absolutePath()); - settings.endGroup(); -} - -QString PictureExport::getPictureFileName(SnapmaticPicture *picture) -{ - return picture->getExportPictureFileName(); -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "config.h" +#include "PictureExport.h" +#include "PictureDialog.h" +#include "StandardPaths.h" +#include "SidebarGenerator.h" +#include <QStringBuilder> +#include <QDesktopWidget> +#include <QApplication> +#include <QMessageBox> +#include <QFileDialog> +#include <QSettings> +#include <QRegExp> +#include <QDebug> + +PictureExport::PictureExport() +{ + +} + +void PictureExport::exportAsPicture(QWidget *parent, SnapmaticPicture *picture) +{ + QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); + + // Picture Settings + // Quality Settings + settings.beginGroup("Pictures"); + int defaultQuality = 100; + QSize defExportSize = QSize(960, 536); + int customQuality = settings.value("CustomQuality", defaultQuality).toInt(); + if (customQuality < 1 || customQuality > 100) + { + customQuality = 100; + } + bool useCustomQuality = settings.value("CustomQualityEnabled", false).toBool(); + + // Size Settings + QSize cusExportSize = settings.value("CustomSize", defExportSize).toSize(); + if (cusExportSize.width() > 3840) + { + cusExportSize.setWidth(3840); + } + else if (cusExportSize.height() > 2160) + { + cusExportSize.setHeight(2160); + } + if (cusExportSize.width() < 1) + { + cusExportSize.setWidth(1); + } + else if (cusExportSize.height() < 1) + { + cusExportSize.setHeight(1); + } + QString sizeMode = settings.value("ExportSizeMode", "Default").toString(); + Qt::AspectRatioMode aspectRatio = (Qt::AspectRatioMode)settings.value("AspectRatio", Qt::KeepAspectRatio).toInt(); + QString defaultExportFormat = settings.value("DefaultExportFormat", ".jpg").toString(); + settings.endGroup(); + // End Picture Settings + + settings.beginGroup("FileDialogs"); + settings.beginGroup("ExportAsPicture"); + +fileDialogPreSave: //Work? + QFileDialog fileDialog(parent); + fileDialog.setFileMode(QFileDialog::AnyFile); + fileDialog.setViewMode(QFileDialog::Detail); + fileDialog.setAcceptMode(QFileDialog::AcceptSave); + fileDialog.setOption(QFileDialog::DontUseNativeDialog, false); + fileDialog.setOption(QFileDialog::DontConfirmOverwrite, true); + fileDialog.setDefaultSuffix("suffix"); + fileDialog.setWindowFlags(fileDialog.windowFlags()^Qt::WindowContextHelpButtonHint); + fileDialog.setWindowTitle(PictureDialog::tr("Export as Picture...")); + fileDialog.setLabelText(QFileDialog::Accept, PictureDialog::tr("Export")); + + QStringList filters; + filters << PictureDialog::tr("JPEG Graphics (*.jpg *.jpeg)"); + filters << PictureDialog::tr("Portable Network Graphics (*.png)"); + fileDialog.setNameFilters(filters); + + QList<QUrl> sidebarUrls = SidebarGenerator::generateSidebarUrls(fileDialog.sidebarUrls()); + + fileDialog.setSidebarUrls(sidebarUrls); + fileDialog.setDirectory(settings.value("Directory", StandardPaths::picturesLocation()).toString()); + fileDialog.restoreGeometry(settings.value(parent->objectName() % "+Geomtery", "").toByteArray()); + + QString newPictureFileName = getPictureFileName(picture) % defaultExportFormat; + fileDialog.selectFile(newPictureFileName); + + if (fileDialog.exec()) + { + QStringList selectedFiles = fileDialog.selectedFiles(); + if (selectedFiles.length() == 1) + { + QString saveFileFormat; + QString selectedFile = selectedFiles.at(0); + + if (selectedFile.right(4) == ".jpg") + { + saveFileFormat = "JPEG"; + } + else if (selectedFile.right(4) == ".jpeg") + { + saveFileFormat = "JPEG"; + } + else if (selectedFile.right(4) == ".png") + { + saveFileFormat = "PNG"; + } + else if (selectedFile.right(7) == ".suffix") + { + if (fileDialog.selectedNameFilter() == "JPEG picture (*.jpg)") + { + selectedFile.replace(".suffix", ".jpg"); + } + else if (fileDialog.selectedNameFilter() == "Portable Network Graphics (*.png)") + { + selectedFile.replace(".suffix", ".png"); + } + else + { + selectedFile.replace(".suffix", ".jpg"); + } + } + + if (QFile::exists(selectedFile)) + { + if (QMessageBox::Yes == QMessageBox::warning(parent, PictureDialog::tr("Export as Picture"), PictureDialog::tr("Overwrite %1 with current Snapmatic picture?").arg("\""+selectedFile+"\""), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)) + { + if (!QFile::remove(selectedFile)) + { + QMessageBox::warning(parent, PictureDialog::tr("Export as Picture"), PictureDialog::tr("Failed to overwrite %1 with current Snapmatic picture").arg("\""+selectedFile+"\"")); + goto fileDialogPreSave; //Work? + } + } + else + { + goto fileDialogPreSave; //Work? + } + } + + // Scale Picture + QImage exportPicture = picture->getImage(); + if (sizeMode == "Desktop") + { + QRect desktopResolution = QApplication::desktop()->screenGeometry(); + exportPicture = exportPicture.scaled(desktopResolution.width(), desktopResolution.height(), aspectRatio, Qt::SmoothTransformation); + } + else if (sizeMode == "Custom") + { + exportPicture = exportPicture.scaled(cusExportSize, aspectRatio, Qt::SmoothTransformation); + } + + bool isSaved; + if (useCustomQuality) + { + isSaved = exportPicture.save(selectedFile, saveFileFormat.toStdString().c_str(), customQuality); + } + else + { + isSaved = exportPicture.save(selectedFile, saveFileFormat.toStdString().c_str(), 100); + } + + if (!isSaved) + { + QMessageBox::warning(parent, PictureDialog::tr("Export as Picture"), PictureDialog::tr("Failed to export current Snapmatic picture")); + goto fileDialogPreSave; //Work? + } + } + else + { + QMessageBox::warning(parent, PictureDialog::tr("Export as Picture"), PictureDialog::tr("No valid file is selected")); + goto fileDialogPreSave; //Work? + } + } + + settings.setValue(parent->objectName() % "+Geometry", fileDialog.saveGeometry()); + settings.setValue("Directory", fileDialog.directory().absolutePath()); + settings.endGroup(); + settings.endGroup(); +} + +void PictureExport::exportAsSnapmatic(QWidget *parent, SnapmaticPicture *picture) +{ + QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); + settings.beginGroup("FileDialogs"); + settings.beginGroup("ExportAsSnapmatic"); + + QString adjustedPicPath = picture->getPictureFileName(); + if (adjustedPicPath.right(7) == ".hidden") // for the hidden file system + { + adjustedPicPath.remove(adjustedPicPath.length() - 7, 7); + } + +fileDialogPreSave: //Work? + QFileInfo sgdFileInfo(adjustedPicPath); + QFileDialog fileDialog(parent); + fileDialog.setFileMode(QFileDialog::AnyFile); + fileDialog.setViewMode(QFileDialog::Detail); + fileDialog.setAcceptMode(QFileDialog::AcceptSave); + fileDialog.setOption(QFileDialog::DontUseNativeDialog, false); + fileDialog.setOption(QFileDialog::DontConfirmOverwrite, true); + fileDialog.setDefaultSuffix(".rem"); + fileDialog.setWindowFlags(fileDialog.windowFlags()^Qt::WindowContextHelpButtonHint); + fileDialog.setWindowTitle(PictureDialog::tr("Export as Snapmatic...")); + fileDialog.setLabelText(QFileDialog::Accept, PictureDialog::tr("Export")); + + QStringList filters; + filters << PictureDialog::tr("GTA V Export (*.g5e)"); + filters << PictureDialog::tr("GTA V Raw Export (*.auto)"); + filters << PictureDialog::tr("Snapmatic pictures (PGTA*)"); + fileDialog.setNameFilters(filters); + + QList<QUrl> sidebarUrls = SidebarGenerator::generateSidebarUrls(fileDialog.sidebarUrls()); + + fileDialog.setSidebarUrls(sidebarUrls); + fileDialog.setDirectory(settings.value("Directory", StandardPaths::documentsLocation()).toString()); + fileDialog.selectFile(QString(picture->getExportPictureFileName() % ".g5e")); + fileDialog.restoreGeometry(settings.value(parent->objectName() % "+Geomtery", "").toByteArray()); + + + if (fileDialog.exec()) + { + QStringList selectedFiles = fileDialog.selectedFiles(); + if (selectedFiles.length() == 1) + { + QString selectedFile = selectedFiles.at(0); + bool isAutoExt = false; + if (selectedFile.right(5) == ".auto") + { + isAutoExt = true; + QString dirPath = QFileInfo(selectedFile).dir().path(); + QString stockFileName = sgdFileInfo.fileName(); + selectedFile = dirPath % "/" % stockFileName; + } + else if (selectedFile.right(4) == ".rem") + { + selectedFile.remove(selectedFile.length() - 4, 4); + } + + if (QFile::exists(selectedFile)) + { + if (QMessageBox::Yes == QMessageBox::warning(parent, PictureDialog::tr("Export as Snapmatic"), PictureDialog::tr("Overwrite %1 with current Snapmatic picture?").arg("\""+selectedFile+"\""), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)) + { + if (!QFile::remove(selectedFile)) + { + QMessageBox::warning(parent, PictureDialog::tr("Export as Snapmatic"), PictureDialog::tr("Failed to overwrite %1 with current Snapmatic picture").arg("\""+selectedFile+"\"")); + goto fileDialogPreSave; //Work? + } + } + else + { + goto fileDialogPreSave; //Work? + } + } + + if (selectedFile.right(4) == ".g5e") + { + bool isExported = picture->exportPicture(selectedFile, SnapmaticFormat::G5E_Format); + if (!isExported) + { + QMessageBox::warning(parent, PictureDialog::tr("Export as Snapmatic"), PictureDialog::tr("Failed to export current Snapmatic picture")); + goto fileDialogPreSave; //Work? + } + } + else + { + bool isCopied = picture->exportPicture(selectedFile, SnapmaticFormat::PGTA_Format); + if (!isCopied) + { + QMessageBox::warning(parent, PictureDialog::tr("Export as Snapmatic"), PictureDialog::tr("Failed to export current Snapmatic picture")); + goto fileDialogPreSave; //Work? + } + else + { + if (isAutoExt) QMessageBox::information(parent, PictureDialog::tr("Export as Snapmatic"), PictureDialog::tr("Exported Snapmatic to \"%1\" because of using the .auto extension.").arg(selectedFile)); + } + } + } + else + { + QMessageBox::warning(parent, PictureDialog::tr("Export as Snapmatic"), PictureDialog::tr("No valid file is selected")); + goto fileDialogPreSave; //Work? + } + } + + settings.setValue(parent->objectName() % "+Geometry", fileDialog.saveGeometry()); + settings.setValue("Directory", fileDialog.directory().absolutePath()); + settings.endGroup(); +} + +QString PictureExport::getPictureFileName(SnapmaticPicture *picture) +{ + return picture->getExportPictureFileName(); +} diff --git a/PictureExport.h b/PictureExport.h index f7aeee9..6ee84a0 100755 --- a/PictureExport.h +++ b/PictureExport.h @@ -1,35 +1,35 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef PICTUREEXPORT_H -#define PICTUREEXPORT_H - -#include "SnapmaticPicture.h" -#include <QWidget> -#include <QString> - -class PictureExport -{ -public: - PictureExport(); - static void exportAsPicture(QWidget *parent, SnapmaticPicture *picture); - static void exportAsSnapmatic(QWidget *parent, SnapmaticPicture *picture); - static QString getPictureFileName(SnapmaticPicture *picture); -}; - -#endif // PICTUREEXPORT_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef PICTUREEXPORT_H +#define PICTUREEXPORT_H + +#include "SnapmaticPicture.h" +#include <QWidget> +#include <QString> + +class PictureExport +{ +public: + PictureExport(); + static void exportAsPicture(QWidget *parent, SnapmaticPicture *picture); + static void exportAsSnapmatic(QWidget *parent, SnapmaticPicture *picture); + static QString getPictureFileName(SnapmaticPicture *picture); +}; + +#endif // PICTUREEXPORT_H diff --git a/ProfileDatabase.cpp b/ProfileDatabase.cpp index b7bc1c7..9d4e814 100755 --- a/ProfileDatabase.cpp +++ b/ProfileDatabase.cpp @@ -1,61 +1,76 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "ProfileDatabase.h" -#include "StandardPaths.h" -#include "config.h" -#include <QFile> -#include <QDir> - -ProfileDatabase::ProfileDatabase(QObject *parent) : QObject(parent) -{ - QDir dir; - dir.mkpath(StandardPaths::dataLocation()); - dir.setPath(StandardPaths::dataLocation()); - QString dirPath = dir.absolutePath(); - QString defaultConfPath = dirPath + QDir::separator() + "players.ini"; - - QSettings confPathSettings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); - confPathSettings.beginGroup("Database"); - QString confPathFile = confPathSettings.value("Players", defaultConfPath).toString(); - confPathSettings.endGroup(); - - profileDB = new QSettings(confPathFile, QSettings::IniFormat); - profileDB->beginGroup("Players"); -} - -ProfileDatabase::~ProfileDatabase() -{ - profileDB->endGroup(); - delete profileDB; -} - -QStringList ProfileDatabase::getPlayers() -{ - return profileDB->childKeys(); -} - -QString ProfileDatabase::getPlayerName(int playerID) -{ - return profileDB->value(QString::number(playerID), playerID).toString(); -} - -void ProfileDatabase::setPlayerName(int playerID, QString playerName) -{ - profileDB->setValue(QString::number(playerID), playerName); -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "ProfileDatabase.h" +#include "StandardPaths.h" +#include "config.h" +#include <QStringBuilder> +#include <QMutexLocker> +#include <QDebug> +#include <QFile> +#include <QDir> + +ProfileDatabase::ProfileDatabase(QObject *parent) : QObject(parent) +{ + QDir dir; + dir.mkpath(StandardPaths::dataLocation()); + dir.setPath(StandardPaths::dataLocation()); + QString dirPath = dir.absolutePath(); + QString defaultConfPath = dirPath % QDir::separator() % "players.ini"; + + QSettings confPathSettings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); + confPathSettings.beginGroup("Database"); + QString confPathFile = confPathSettings.value("Players", defaultConfPath).toString(); + confPathSettings.endGroup(); + + profileDB = new QSettings(confPathFile, QSettings::IniFormat); + profileDB->beginGroup("Players"); +} + +ProfileDatabase::~ProfileDatabase() +{ + profileDB->endGroup(); + delete profileDB; +} + +QStringList ProfileDatabase::getPlayers() +{ + QMutexLocker locker(&mutex); +#ifdef GTA5SYNC_DEBUG + qDebug() << "getPlayers"; +#endif + return profileDB->childKeys(); +} + +QString ProfileDatabase::getPlayerName(int playerID) +{ + QMutexLocker locker(&mutex); +#ifdef GTA5SYNC_DEBUG + qDebug() << "getPlayerName" << playerID; +#endif + return profileDB->value(QString::number(playerID), playerID).toString(); +} + +void ProfileDatabase::setPlayerName(int playerID, QString playerName) +{ + QMutexLocker locker(&mutex); +#ifdef GTA5SYNC_DEBUG + qDebug() << "setPlayerName" << playerID << playerName; +#endif + profileDB->setValue(QString::number(playerID), playerName); +} diff --git a/ProfileDatabase.h b/ProfileDatabase.h index b92fb4f..7a1fbd8 100755 --- a/ProfileDatabase.h +++ b/ProfileDatabase.h @@ -1,43 +1,45 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef PROFILEDATABASE_H -#define PROFILEDATABASE_H - -#include <QSettings> -#include <QObject> -#include <QMap> - -class ProfileDatabase : public QObject -{ - Q_OBJECT -public: - explicit ProfileDatabase(QObject *parent = 0); - QString getPlayerName(int playerID); - QStringList getPlayers(); - ~ProfileDatabase(); - -private: - QSettings *profileDB; - -public slots: - void setPlayerName(int playerID, QString playerName); - -}; - -#endif // PROFILEDATABASE_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef PROFILEDATABASE_H +#define PROFILEDATABASE_H + +#include <QSettings> +#include <QObject> +#include <QMutex> +#include <QMap> + +class ProfileDatabase : public QObject +{ + Q_OBJECT +public: + explicit ProfileDatabase(QObject *parent = 0); + QString getPlayerName(int playerID); + QStringList getPlayers(); + ~ProfileDatabase(); + +private: + mutable QMutex mutex; + QSettings *profileDB; + +public slots: + void setPlayerName(int playerID, QString playerName); + +}; + +#endif // PROFILEDATABASE_H diff --git a/ProfileInterface.cpp b/ProfileInterface.cpp index 51e8cc0..1507a90 100755 --- a/ProfileInterface.cpp +++ b/ProfileInterface.cpp @@ -38,6 +38,7 @@ #include <QPushButton> #include <QSpacerItem> #include <QMessageBox> +#include <QMouseEvent> #include <QFileDialog> #include <QEventLoop> #include <QScrollBar> @@ -64,13 +65,14 @@ ProfileInterface::ProfileInterface(ProfileDatabase *profileDB, CrewDatabase *cre enabledPicStr = tr("Enabled pictures: %1 of %2"); selectedWidgts = 0; profileFolder = ""; - profileLoader = 0; - saSpacerItem = 0; + contextMenuOpened = false; + isProfileLoaded = false; + previousWidget = nullptr; + profileLoader = nullptr; + saSpacerItem = nullptr; - QPalette palette; - QColor baseColor = palette.base().color(); - ui->labVersion->setText(ui->labVersion->text().arg(GTA5SYNC_APPSTR, GTA5SYNC_APPVER)); - ui->saProfile->setStyleSheet(QString("QWidget#saProfileContent{background-color: rgb(%1, %2, %3)}").arg(QString::number(baseColor.red()),QString::number(baseColor.green()),QString::number(baseColor.blue()))); + updatePalette(); + ui->labVersion->setText(QString("%1 %2").arg(GTA5SYNC_APPSTR, GTA5SYNC_APPVER)); ui->saProfileContent->setFilesMode(true); if (QIcon::hasThemeIcon("dialog-close")) @@ -87,6 +89,9 @@ ProfileInterface::ProfileInterface(ProfileDatabase *profileDB, CrewDatabase *cre ui->hlButtons->setSpacing(6 * screenRatio); ui->hlButtons->setContentsMargins(9 * screenRatio, 15 * screenRatio, 15 * screenRatio, 17 * screenRatio); #endif + + setMouseTracking(true); + installEventFilter(this); } ProfileInterface::~ProfileInterface() @@ -94,6 +99,8 @@ ProfileInterface::~ProfileInterface() foreach(ProfileWidget *widget, widgets.keys()) { widgets.remove(widget); + widget->removeEventFilter(this); + widget->disconnect(); delete widget; } foreach(SavegameData *savegame, savegames) @@ -138,6 +145,8 @@ void ProfileInterface::savegameLoaded(SavegameData *savegame, QString savegamePa SavegameWidget *sgdWidget = new SavegameWidget(this); sgdWidget->setSavegameData(savegame, savegamePath); sgdWidget->setContentMode(contentMode); + sgdWidget->setMouseTracking(true); + sgdWidget->installEventFilter(this); widgets[sgdWidget] = "SGD" % QFileInfo(savegamePath).fileName(); savegames += savegame; if (selectedWidgts != 0 || contentMode == 2) { sgdWidget->setSelectionMode(true); } @@ -160,6 +169,8 @@ void ProfileInterface::pictureLoaded(SnapmaticPicture *picture, bool inserted) SnapmaticWidget *picWidget = new SnapmaticWidget(profileDB, crewDB, threadDB, this); picWidget->setSnapmaticPicture(picture); picWidget->setContentMode(contentMode); + picWidget->setMouseTracking(true); + picWidget->installEventFilter(this); widgets[picWidget] = "PIC" % picture->getPictureSortStr(); pictures += picture; if (selectedWidgts != 0 || contentMode == 2) { picWidget->setSelectionMode(true); } @@ -183,7 +194,7 @@ void ProfileInterface::loadingProgress(int value, int maximum) void ProfileInterface::insertSnapmaticIPI(QWidget *widget) { - ProfileWidget *proWidget = (ProfileWidget*)widget; + ProfileWidget *proWidget = qobject_cast<ProfileWidget*>(widget); if (widgets.contains(proWidget)) { QString widgetKey = widgets[proWidget]; @@ -204,7 +215,7 @@ void ProfileInterface::insertSnapmaticIPI(QWidget *widget) void ProfileInterface::insertSavegameIPI(QWidget *widget) { - ProfileWidget *proWidget = (ProfileWidget*)widget; + ProfileWidget *proWidget = qobject_cast<ProfileWidget*>(widget); if (widgets.contains(proWidget)) { QString widgetKey = widgets[proWidget]; @@ -221,8 +232,8 @@ void ProfileInterface::insertSavegameIPI(QWidget *widget) void ProfileInterface::dialogNextPictureRequested(QWidget *dialog) { - PictureDialog *picDialog = (PictureDialog*)dialog; - ProfileWidget *proWidget = (ProfileWidget*)sender(); + PictureDialog *picDialog = qobject_cast<PictureDialog*>(dialog); + ProfileWidget *proWidget = qobject_cast<ProfileWidget*>(sender()); if (widgets.contains(proWidget)) { QString widgetKey = widgets[proWidget]; @@ -256,8 +267,8 @@ void ProfileInterface::dialogNextPictureRequested(QWidget *dialog) void ProfileInterface::dialogPreviousPictureRequested(QWidget *dialog) { - PictureDialog *picDialog = (PictureDialog*)dialog; - ProfileWidget *proWidget = (ProfileWidget*)sender(); + PictureDialog *picDialog = qobject_cast<PictureDialog*>(dialog); + ProfileWidget *proWidget = qobject_cast<ProfileWidget*>(sender()); if (widgets.contains(proWidget)) { QString widgetKey = widgets[proWidget]; @@ -324,12 +335,13 @@ void ProfileInterface::profileLoaded_p() ui->swProfile->setCurrentWidget(ui->pageProfile); ui->cmdCloseProfile->setEnabled(true); ui->cmdImport->setEnabled(true); + isProfileLoaded = true; emit profileLoaded(); } void ProfileInterface::savegameDeleted_event() { - savegameDeleted((SavegameWidget*)sender(), true); + savegameDeleted(qobject_cast<SavegameWidget*>(sender()), true); } void ProfileInterface::savegameDeleted(SavegameWidget *sgdWidget, bool isRemoteEmited) @@ -338,13 +350,21 @@ void ProfileInterface::savegameDeleted(SavegameWidget *sgdWidget, bool isRemoteE if (sgdWidget->isSelected()) { sgdWidget->setSelected(false); } widgets.remove(sgdWidget); + sgdWidget->removeEventFilter(this); + if (sgdWidget == previousWidget) + { + previousWidget = nullptr; + } + // Deleting when the widget did send a event cause a crash if (isRemoteEmited) { + sgdWidget->disconnect(); sgdWidget->deleteLater(); } else { + sgdWidget->disconnect(); delete sgdWidget; } @@ -354,7 +374,7 @@ void ProfileInterface::savegameDeleted(SavegameWidget *sgdWidget, bool isRemoteE void ProfileInterface::pictureDeleted_event() { - pictureDeleted((SnapmaticWidget*)sender(), true); + pictureDeleted(qobject_cast<SnapmaticWidget*>(sender()), true); } void ProfileInterface::pictureDeleted(SnapmaticWidget *picWidget, bool isRemoteEmited) @@ -363,13 +383,21 @@ void ProfileInterface::pictureDeleted(SnapmaticWidget *picWidget, bool isRemoteE if (picWidget->isSelected()) { picWidget->setSelected(false); } widgets.remove(picWidget); + picWidget->removeEventFilter(this); + if (picWidget == previousWidget) + { + previousWidget = nullptr; + } + // Deleting when the widget did send a event cause a crash if (isRemoteEmited) { + picWidget->disconnect(); picWidget->deleteLater(); } else { + picWidget->disconnect(); delete picWidget; } @@ -398,12 +426,24 @@ fileDialogPreOpen: //Work? fileDialog.setWindowTitle(tr("Import...")); fileDialog.setLabelText(QFileDialog::Accept, tr("Import")); + // Getting readable Image formats + QString imageFormatsStr = " "; + foreach(const QByteArray &imageFormat, QImageReader::supportedImageFormats()) + { + imageFormatsStr += QString("*.") % QString::fromUtf8(imageFormat).toLower() % " "; + } + QString importableFormatsStr = QString("*.g5e SGTA* PGTA*"); + if (!imageFormatsStr.trimmed().isEmpty()) + { + importableFormatsStr = QString("*.g5e%1SGTA* PGTA*").arg(imageFormatsStr); + } + QStringList filters; - filters << tr("Importable files (*.g5e *.jpg *.png SGTA* PGTA*)"); + filters << tr("Importable files (%1)").arg(importableFormatsStr); filters << tr("GTA V Export (*.g5e)"); filters << tr("Savegames files (SGTA*)"); filters << tr("Snapmatic pictures (PGTA*)"); - filters << tr("All image files (*.jpg *.png)"); + filters << tr("All image files (%1)").arg(imageFormatsStr.trimmed()); filters << tr("All files (**)"); fileDialog.setNameFilters(filters); @@ -520,7 +560,7 @@ bool ProfileInterface::importFile(QString selectedFile, bool notMultiple) return false; } } - else if(selectedFileName.right(4) == ".jpg" || selectedFileName.right(4) == ".png") + else if(isSupportedImageFile(selectedFileName)) { SnapmaticPicture *picture = new SnapmaticPicture(":/template/template.g5e"); if (picture->readingPicture(true, false, true, false)) @@ -631,6 +671,7 @@ bool ProfileInterface::importFile(QString selectedFile, bool notMultiple) snapmaticImageReader.setDevice(&snapmaticFile); if (!snapmaticImageReader.read(&snapmaticImage)) { + QMessageBox::warning(this, tr("Import"), tr("Can't import %1 because file can't be parsed properly").arg("\""+selectedFileName+"\"")); delete picture; return false; } @@ -640,7 +681,7 @@ bool ProfileInterface::importFile(QString selectedFile, bool notMultiple) importDialog->setModal(true); importDialog->show(); importDialog->exec(); - if (importDialog->isDoImport()) + if (importDialog->isImportAgreed()) { if (picture->setImage(importDialog->image())) { @@ -705,9 +746,13 @@ bool ProfileInterface::importFile(QString selectedFile, bool notMultiple) } else { - delete savegame; +#ifdef GTA5SYNC_DEBUG + qDebug() << "ImportError SnapmaticPicture" << picture->getLastStep(); + qDebug() << "ImportError SavegameData" << savegame->getLastStep(); +#endif delete picture; - if (notMultiple) QMessageBox::warning(this, tr("Import"), tr("Can't import %1 because of not valid file format").arg("\""+selectedFileName+"\"")); + delete savegame; + if (notMultiple) QMessageBox::warning(this, tr("Import"), tr("Can't import %1 because file format can't be detected").arg("\""+selectedFileName+"\"")); return false; } } @@ -738,7 +783,7 @@ bool ProfileInterface::importSnapmaticPicture(SnapmaticPicture *picture, bool wa if (warn) QMessageBox::warning(this, tr("Import"), tr("Failed to import the Snapmatic picture, the picture is already in the game")); return false; } - else if (picture->exportPicture(profileFolder % QDir::separator() % adjustedFileName, "PGTA")) + else if (picture->exportPicture(profileFolder % QDir::separator() % adjustedFileName, SnapmaticFormat::PGTA_Format)) { picture->setPicFilePath(profileFolder % QDir::separator() % adjustedFileName); pictureLoaded(picture, true); @@ -914,8 +959,10 @@ void ProfileInterface::exportSelected() } else { - pictureExportEnabled = true; - pictureCopyEnabled = true; + // Don't export anymore when any Cancel button got clicked + settings.endGroup(); + settings.endGroup(); + return; } } @@ -934,7 +981,7 @@ void ProfileInterface::exportSelected() QProgressDialog pbDialog(this); pbDialog.setWindowFlags(pbDialog.windowFlags()^Qt::WindowContextHelpButtonHint^Qt::WindowCloseButtonHint); pbDialog.setWindowTitle(tr("Export selected...")); - pbDialog.setLabelText(tr("Initializing export...")); + pbDialog.setLabelText(tr("Initialising export...")); pbDialog.setRange(0, exportCount); QList<QPushButton*> pbBtn = pbDialog.findChildren<QPushButton*>(); @@ -1003,7 +1050,7 @@ void ProfileInterface::deleteSelected() { if (widget->getWidgetType() == "SnapmaticWidget") { - SnapmaticWidget *picWidget = (SnapmaticWidget*)widget; + SnapmaticWidget *picWidget = qobject_cast<SnapmaticWidget*>(widget); if (picWidget->getPicture()->deletePicFile()) { pictureDeleted(picWidget); @@ -1011,7 +1058,7 @@ void ProfileInterface::deleteSelected() } else if (widget->getWidgetType() == "SavegameWidget") { - SavegameWidget *sgdWidget = (SavegameWidget*)widget; + SavegameWidget *sgdWidget = qobject_cast<SavegameWidget*>(widget); SavegameData *savegame = sgdWidget->getSavegame(); QString fileName = savegame->getSavegameFileName(); if (!QFile::exists(fileName) || QFile::remove(fileName)) @@ -1038,9 +1085,15 @@ void ProfileInterface::importFiles() on_cmdImport_clicked(); } -void ProfileInterface::settingsApplied(int _contentMode, QString language) +void ProfileInterface::settingsApplied(int _contentMode, QString _language) { - Q_UNUSED(language) + bool translationUpdated = false; + if (language != _language) + { + retranslateUi(); + language = _language; + translationUpdated = true; + } contentMode = _contentMode; if (contentMode == 2) @@ -1049,6 +1102,7 @@ void ProfileInterface::settingsApplied(int _contentMode, QString language) { widget->setSelectionMode(true); widget->setContentMode(contentMode); + if (translationUpdated) widget->retranslate(); } } else @@ -1060,6 +1114,7 @@ void ProfileInterface::settingsApplied(int _contentMode, QString language) widget->setSelectionMode(false); } widget->setContentMode(contentMode); + if (translationUpdated) widget->retranslate(); } } } @@ -1073,7 +1128,7 @@ void ProfileInterface::enableSelected() { if (widget->getWidgetType() == "SnapmaticWidget") { - SnapmaticWidget *snapmaticWidget = (SnapmaticWidget*)widget; + SnapmaticWidget *snapmaticWidget = qobject_cast<SnapmaticWidget*>(widget); if (!snapmaticWidget->makePictureVisible()) { fails++; @@ -1092,7 +1147,7 @@ void ProfileInterface::disableSelected() { if (widget->getWidgetType() == "SnapmaticWidget") { - SnapmaticWidget *snapmaticWidget = (SnapmaticWidget*)widget; + SnapmaticWidget *snapmaticWidget = qobject_cast<SnapmaticWidget*>(widget); if (!snapmaticWidget->makePictureHidden()) { fails++; @@ -1109,7 +1164,16 @@ int ProfileInterface::selectedWidgets() void ProfileInterface::contextMenuTriggeredPIC(QContextMenuEvent *ev) { - SnapmaticWidget *picWidget = (SnapmaticWidget*)sender(); + SnapmaticWidget *picWidget = qobject_cast<SnapmaticWidget*>(sender()); + if (picWidget != previousWidget) + { + if (previousWidget != nullptr) + { + previousWidget->setStyleSheet(QLatin1String("")); + } + picWidget->setStyleSheet(QString("QFrame#SnapmaticFrame{background-color: rgb(%1, %2, %3)}QLabel#labPicStr{color: rgb(%4, %5, %6)}").arg(QString::number(highlightBackColor.red()), QString::number(highlightBackColor.green()), QString::number(highlightBackColor.blue()), QString::number(highlightTextColor.red()), QString::number(highlightTextColor.green()), QString::number(highlightTextColor.blue()))); + previousWidget = picWidget; + } QMenu contextMenu(picWidget); QMenu editMenu(SnapmaticWidget::tr("Edi&t"), picWidget); if (picWidget->isHidden()) @@ -1122,8 +1186,8 @@ void ProfileInterface::contextMenuTriggeredPIC(QContextMenuEvent *ev) } editMenu.addAction(SnapmaticWidget::tr("&Edit Properties..."), picWidget, SLOT(editSnapmaticProperties())); QMenu exportMenu(SnapmaticWidget::tr("&Export"), this); - exportMenu.addAction(SnapmaticWidget::tr("Export as &JPG picture..."), picWidget, SLOT(on_cmdExport_clicked())); - exportMenu.addAction(SnapmaticWidget::tr("Export as >A Snapmatic..."), picWidget, SLOT(on_cmdCopy_clicked())); + exportMenu.addAction(SnapmaticWidget::tr("Export as &Picture..."), picWidget, SLOT(on_cmdExport_clicked())); + exportMenu.addAction(SnapmaticWidget::tr("Export as &Snapmatic..."), picWidget, SLOT(on_cmdCopy_clicked())); contextMenu.addAction(SnapmaticWidget::tr("&View"), picWidget, SLOT(on_cmdView_clicked())); contextMenu.addMenu(&editMenu); contextMenu.addMenu(&exportMenu); @@ -1139,12 +1203,24 @@ void ProfileInterface::contextMenuTriggeredPIC(QContextMenuEvent *ev) { contextMenu.addAction(SnapmaticWidget::tr("&Deselect All"), picWidget, SLOT(deselectAllWidgets()), QKeySequence::fromString("Ctrl+D")); } + contextMenuOpened = true; contextMenu.exec(ev->globalPos()); + contextMenuOpened = false; + hoverProfileWidgetCheck(); } void ProfileInterface::contextMenuTriggeredSGD(QContextMenuEvent *ev) { - SavegameWidget *sgdWidget = (SavegameWidget*)sender(); + SavegameWidget *sgdWidget = qobject_cast<SavegameWidget*>(sender()); + if (sgdWidget != previousWidget) + { + if (previousWidget != nullptr) + { + previousWidget->setStyleSheet(QLatin1String("")); + } + sgdWidget->setStyleSheet(QString("QFrame#SavegameFrame{background-color: rgb(%1, %2, %3)}QLabel#labSavegameStr{color: rgb(%4, %5, %6)}").arg(QString::number(highlightBackColor.red()), QString::number(highlightBackColor.green()), QString::number(highlightBackColor.blue()), QString::number(highlightTextColor.red()), QString::number(highlightTextColor.green()), QString::number(highlightTextColor.blue()))); + previousWidget = sgdWidget; + } QMenu contextMenu(sgdWidget); contextMenu.addAction(SavegameWidget::tr("&View"), sgdWidget, SLOT(on_cmdView_clicked())); contextMenu.addAction(SavegameWidget::tr("&Export"), sgdWidget, SLOT(on_cmdCopy_clicked())); @@ -1160,7 +1236,10 @@ void ProfileInterface::contextMenuTriggeredSGD(QContextMenuEvent *ev) { contextMenu.addAction(SavegameWidget::tr("&Deselect All"), sgdWidget, SLOT(deselectAllWidgets()), QKeySequence::fromString("Ctrl+D")); } + contextMenuOpened = true; contextMenu.exec(ev->globalPos()); + contextMenuOpened = false; + hoverProfileWidgetCheck(); } void ProfileInterface::on_saProfileContent_dropped(const QMimeData *mimeData) @@ -1187,3 +1266,200 @@ void ProfileInterface::on_saProfileContent_dropped(const QMimeData *mimeData) importFilesProgress(pathList); } } + +void ProfileInterface::retranslateUi() +{ + ui->retranslateUi(this); + ui->labVersion->setText(QString("%1 %2").arg(GTA5SYNC_APPSTR, GTA5SYNC_APPVER)); +} + +bool ProfileInterface::eventFilter(QObject *watched, QEvent *event) +{ + if (event->type() == QEvent::MouseMove) + { + if ((watched->objectName() == "SavegameWidget" || watched->objectName() == "SnapmaticWidget") && isProfileLoaded) + { + ProfileWidget *pWidget = qobject_cast<ProfileWidget*>(watched); + if (pWidget->underMouse()) + { + bool styleSheetChanged = false; + if (pWidget->getWidgetType() == "SnapmaticWidget") + { + if (pWidget != previousWidget) + { + pWidget->setStyleSheet(QString("QFrame#SnapmaticFrame{background-color: rgb(%1, %2, %3)}QLabel#labPicStr{color: rgb(%4, %5, %6)}").arg(QString::number(highlightBackColor.red()), QString::number(highlightBackColor.green()), QString::number(highlightBackColor.blue()), QString::number(highlightTextColor.red()), QString::number(highlightTextColor.green()), QString::number(highlightTextColor.blue()))); + styleSheetChanged = true; + } + } + else if (pWidget->getWidgetType() == "SavegameWidget") + { + if (pWidget != previousWidget) + { + pWidget->setStyleSheet(QString("QFrame#SavegameFrame{background-color: rgb(%1, %2, %3)}QLabel#labSavegameStr{color: rgb(%4, %5, %6)}").arg(QString::number(highlightBackColor.red()), QString::number(highlightBackColor.green()), QString::number(highlightBackColor.blue()), QString::number(highlightTextColor.red()), QString::number(highlightTextColor.green()), QString::number(highlightTextColor.blue()))); + styleSheetChanged = true; + } + } + if (styleSheetChanged) + { + if (previousWidget != nullptr) + { + previousWidget->setStyleSheet(QLatin1String("")); + } + previousWidget = pWidget; + } + } + return true; + } + } + else if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::WindowActivate) + { + if ((watched->objectName() == "SavegameWidget" || watched->objectName() == "SnapmaticWidget") && isProfileLoaded) + { + ProfileWidget *pWidget = nullptr; + foreach(ProfileWidget *widget, widgets.keys()) + { + QPoint mousePos = widget->mapFromGlobal(QCursor::pos()); + if (widget->rect().contains(mousePos)) + { + pWidget = widget; + break; + } + } + if (pWidget != nullptr) + { + bool styleSheetChanged = false; + if (pWidget->getWidgetType() == "SnapmaticWidget") + { + if (pWidget != previousWidget) + { + pWidget->setStyleSheet(QString("QFrame#SnapmaticFrame{background-color: rgb(%1, %2, %3)}QLabel#labPicStr{color: rgb(%4, %5, %6)}").arg(QString::number(highlightBackColor.red()), QString::number(highlightBackColor.green()), QString::number(highlightBackColor.blue()), QString::number(highlightTextColor.red()), QString::number(highlightTextColor.green()), QString::number(highlightTextColor.blue()))); + styleSheetChanged = true; + } + } + else if (pWidget->getWidgetType() == "SavegameWidget") + { + if (pWidget != previousWidget) + { + pWidget->setStyleSheet(QString("QFrame#SavegameFrame{background-color: rgb(%1, %2, %3)}QLabel#labSavegameStr{color: rgb(%4, %5, %6)}").arg(QString::number(highlightBackColor.red()), QString::number(highlightBackColor.green()), QString::number(highlightBackColor.blue()), QString::number(highlightTextColor.red()), QString::number(highlightTextColor.green()), QString::number(highlightTextColor.blue()))); + styleSheetChanged = true; + } + } + if (styleSheetChanged) + { + if (previousWidget != nullptr) + { + previousWidget->setStyleSheet(QLatin1String("")); + } + previousWidget = pWidget; + } + } + } + } + else if (event->type() == QEvent::WindowDeactivate && isProfileLoaded) + { + if (previousWidget != nullptr) + { + previousWidget->setStyleSheet(QLatin1String("")); + previousWidget = nullptr; + } + } + else if (event->type() == QEvent::Leave && isProfileLoaded && !contextMenuOpened) + { + if (watched->objectName() == "SavegameWidget" || watched->objectName() == "SnapmaticWidget") + { + ProfileWidget *pWidget = qobject_cast<ProfileWidget*>(watched); + QPoint mousePos = pWidget->mapFromGlobal(QCursor::pos()); + if (!pWidget->geometry().contains(mousePos)) + { + if (previousWidget != nullptr) + { + previousWidget->setStyleSheet(QLatin1String("")); + previousWidget = nullptr; + } + } + } + } + return false; +} + +void ProfileInterface::hoverProfileWidgetCheck() +{ + ProfileWidget *pWidget = nullptr; + foreach(ProfileWidget *widget, widgets.keys()) + { + if (widget->underMouse()) + { + pWidget = widget; + break; + } + } + if (pWidget != nullptr) + { + bool styleSheetChanged = false; + if (pWidget->getWidgetType() == "SnapmaticWidget") + { + if (pWidget != previousWidget) + { + pWidget->setStyleSheet(QString("QFrame#SnapmaticFrame{background-color: rgb(%1, %2, %3)}QLabel#labPicStr{color: rgb(%4, %5, %6)}").arg(QString::number(highlightBackColor.red()), QString::number(highlightBackColor.green()), QString::number(highlightBackColor.blue()), QString::number(highlightTextColor.red()), QString::number(highlightTextColor.green()), QString::number(highlightTextColor.blue()))); + styleSheetChanged = true; + } + } + else if (pWidget->getWidgetType() == "SavegameWidget") + { + if (pWidget != previousWidget) + { + pWidget->setStyleSheet(QString("QFrame#SavegameFrame{background-color: rgb(%1, %2, %3)}QLabel#labSavegameStr{color: rgb(%4, %5, %6)}").arg(QString::number(highlightBackColor.red()), QString::number(highlightBackColor.green()), QString::number(highlightBackColor.blue()), QString::number(highlightTextColor.red()), QString::number(highlightTextColor.green()), QString::number(highlightTextColor.blue()))); + styleSheetChanged = true; + } + } + if (styleSheetChanged) + { + if (previousWidget != nullptr) + { + previousWidget->setStyleSheet(QLatin1String("")); + } + previousWidget = pWidget; + } + } + else + { + if (previousWidget != nullptr) + { + previousWidget->setStyleSheet(QLatin1String("")); + previousWidget = nullptr; + } + } +} + +void ProfileInterface::updatePalette() +{ + QPalette palette; + QColor baseColor = palette.base().color(); + highlightBackColor = palette.highlight().color(); + highlightTextColor = palette.highlightedText().color(); + ui->saProfile->setStyleSheet(QString("QWidget#saProfileContent{background-color: rgb(%1, %2, %3)}").arg(QString::number(baseColor.red()), QString::number(baseColor.green()), QString::number(baseColor.blue()))); + if (previousWidget != nullptr) + { + if (previousWidget->getWidgetType() == "SnapmaticWidget") + { + previousWidget->setStyleSheet(QString("QFrame#SnapmaticFrame{background-color: rgb(%1, %2, %3)}QLabel#labPicStr{color: rgb(%4, %5, %6)}").arg(QString::number(highlightBackColor.red()), QString::number(highlightBackColor.green()), QString::number(highlightBackColor.blue()), QString::number(highlightTextColor.red()), QString::number(highlightTextColor.green()), QString::number(highlightTextColor.blue()))); + } + else if (previousWidget->getWidgetType() == "SavegameWidget") + { + previousWidget->setStyleSheet(QString("QFrame#SavegameFrame{background-color: rgb(%1, %2, %3)}QLabel#labSavegameStr{color: rgb(%4, %5, %6)}").arg(QString::number(highlightBackColor.red()), QString::number(highlightBackColor.green()), QString::number(highlightBackColor.blue()), QString::number(highlightTextColor.red()), QString::number(highlightTextColor.green()), QString::number(highlightTextColor.blue()))); + } + } +} + +bool ProfileInterface::isSupportedImageFile(QString selectedFileName) +{ + foreach(const QByteArray &imageFormat, QImageReader::supportedImageFormats()) + { + QString imageFormatStr = QString(".") % QString::fromUtf8(imageFormat).toLower(); + if (selectedFileName.length() >= imageFormatStr.length() && selectedFileName.toLower().right(imageFormatStr.length()) == imageFormatStr) + { + return true; + } + } + return false; +} diff --git a/ProfileInterface.h b/ProfileInterface.h index 9d769e8..a45ed9e 100755 --- a/ProfileInterface.h +++ b/ProfileInterface.h @@ -1,114 +1,127 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef PROFILEINTERFACE_H -#define PROFILEINTERFACE_H - -#include "SnapmaticPicture.h" -#include "SnapmaticWidget.h" -#include "ProfileDatabase.h" -#include "DatabaseThread.h" -#include "SavegameWidget.h" -#include "ProfileLoader.h" -#include "ProfileWidget.h" -#include "ExportThread.h" -#include "SavegameData.h" -#include "CrewDatabase.h" -#include <QProgressDialog> -#include <QSpacerItem> -#include <QWidget> -#include <QList> -#include <QMap> - -namespace Ui { -class ProfileInterface; -} - -class ProfileInterface : public QWidget -{ - Q_OBJECT -public: - explicit ProfileInterface(ProfileDatabase *profileDB, CrewDatabase *crewDB, DatabaseThread *threadDB, QWidget *parent = 0); - void setProfileFolder(QString folder, QString profile); - void settingsApplied(int contentMode, QString language); - void setupProfileInterface(); - void disableSelected(); - void enableSelected(); - int selectedWidgets(); - ~ProfileInterface(); - -public slots: - void contextMenuTriggeredPIC(QContextMenuEvent* ev); - void contextMenuTriggeredSGD(QContextMenuEvent* ev); - void selectAllWidgets(); - void deselectAllWidgets(); - void exportSelected(); - void deleteSelected(); - void importFiles(); - -private slots: - void on_cmdCloseProfile_clicked(); - void on_cmdImport_clicked(); - void pictureLoaded_event(SnapmaticPicture *picture); - void savegameLoaded_event(SavegameData *savegame, QString savegamePath); - void loadingProgress(int value, int maximum); - void pictureDeleted_event(); - void savegameDeleted_event(); - void profileLoaded_p(); - void profileWidgetSelected(); - void profileWidgetDeselected(); - void dialogNextPictureRequested(QWidget *dialog); - void dialogPreviousPictureRequested(QWidget *dialog); - void on_saProfileContent_dropped(const QMimeData *mimeData); - -private: - ProfileDatabase *profileDB; - CrewDatabase *crewDB; - DatabaseThread *threadDB; - Ui::ProfileInterface *ui; - - ProfileLoader *profileLoader; - QList<SavegameData*> savegames; - QList<SnapmaticPicture*> pictures; - QMap<ProfileWidget*,QString> widgets; - QSpacerItem *saSpacerItem; - QString enabledPicStr; - QString profileFolder; - QString profileName; - QString loadingStr; - int selectedWidgts; - int contentMode; - - bool importFile(QString selectedFile, bool notMultiple); - void importFilesProgress(QStringList selectedFiles); - bool importSnapmaticPicture(SnapmaticPicture *picture, bool warn = true); - bool importSavegameData(SavegameData *savegame, QString sgdPath, bool warn = true); - void pictureLoaded(SnapmaticPicture *picture, bool inserted); - void savegameLoaded(SavegameData *savegame, QString savegamePath, bool inserted); - void savegameDeleted(SavegameWidget *sgdWidget, bool isRemoteEmited = false); - void pictureDeleted(SnapmaticWidget *picWidget, bool isRemoteEmited = false); - void insertSnapmaticIPI(QWidget *widget); - void insertSavegameIPI(QWidget *widget); - void sortingProfileInterface(); - -signals: - void profileLoaded(); - void profileClosed(); -}; - -#endif // PROFILEINTERFACE_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef PROFILEINTERFACE_H +#define PROFILEINTERFACE_H + +#include "SnapmaticPicture.h" +#include "SnapmaticWidget.h" +#include "ProfileDatabase.h" +#include "DatabaseThread.h" +#include "SavegameWidget.h" +#include "ProfileLoader.h" +#include "ProfileWidget.h" +#include "ExportThread.h" +#include "SavegameData.h" +#include "CrewDatabase.h" +#include <QProgressDialog> +#include <QSpacerItem> +#include <QWidget> +#include <QList> +#include <QMap> + +namespace Ui { +class ProfileInterface; +} + +class ProfileInterface : public QWidget +{ + Q_OBJECT +public: + explicit ProfileInterface(ProfileDatabase *profileDB, CrewDatabase *crewDB, DatabaseThread *threadDB, QWidget *parent = 0); + void setProfileFolder(QString folder, QString profile); + void settingsApplied(int contentMode, QString language); + void setupProfileInterface(); + void disableSelected(); + void enableSelected(); + int selectedWidgets(); + void retranslateUi(); + ~ProfileInterface(); + +public slots: + void contextMenuTriggeredPIC(QContextMenuEvent* ev); + void contextMenuTriggeredSGD(QContextMenuEvent* ev); + void hoverProfileWidgetCheck(); + void selectAllWidgets(); + void deselectAllWidgets(); + void exportSelected(); + void deleteSelected(); + void updatePalette(); + void importFiles(); + +private slots: + void on_cmdCloseProfile_clicked(); + void on_cmdImport_clicked(); + void pictureLoaded_event(SnapmaticPicture *picture); + void savegameLoaded_event(SavegameData *savegame, QString savegamePath); + void loadingProgress(int value, int maximum); + void pictureDeleted_event(); + void savegameDeleted_event(); + void profileLoaded_p(); + void profileWidgetSelected(); + void profileWidgetDeselected(); + void dialogNextPictureRequested(QWidget *dialog); + void dialogPreviousPictureRequested(QWidget *dialog); + void on_saProfileContent_dropped(const QMimeData *mimeData); + +protected: + bool eventFilter(QObject *watched, QEvent *event); + +private: + ProfileDatabase *profileDB; + CrewDatabase *crewDB; + DatabaseThread *threadDB; + Ui::ProfileInterface *ui; + + ProfileLoader *profileLoader; + ProfileWidget *previousWidget; + QList<SavegameData*> savegames; + QList<SnapmaticPicture*> pictures; + QMap<ProfileWidget*,QString> widgets; + QSpacerItem *saSpacerItem; + QColor highlightBackColor; + QColor highlightTextColor; + QString enabledPicStr; + QString profileFolder; + QString profileName; + QString loadingStr; + QString language; + bool contextMenuOpened; + bool isProfileLoaded; + int selectedWidgts; + int contentMode; + + bool isSupportedImageFile(QString selectedFileName); + bool importFile(QString selectedFile, bool notMultiple); + void importFilesProgress(QStringList selectedFiles); + bool importSnapmaticPicture(SnapmaticPicture *picture, bool warn = true); + bool importSavegameData(SavegameData *savegame, QString sgdPath, bool warn = true); + void pictureLoaded(SnapmaticPicture *picture, bool inserted); + void savegameLoaded(SavegameData *savegame, QString savegamePath, bool inserted); + void savegameDeleted(SavegameWidget *sgdWidget, bool isRemoteEmited = false); + void pictureDeleted(SnapmaticWidget *picWidget, bool isRemoteEmited = false); + void insertSnapmaticIPI(QWidget *widget); + void insertSavegameIPI(QWidget *widget); + void sortingProfileInterface(); + +signals: + void profileLoaded(); + void profileClosed(); +}; + +#endif // PROFILEINTERFACE_H diff --git a/ProfileInterface.ui b/ProfileInterface.ui index de37b79..066e636 100755 --- a/ProfileInterface.ui +++ b/ProfileInterface.ui @@ -1,244 +1,244 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>ProfileInterface</class> - <widget class="QWidget" name="ProfileInterface"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>400</width> - <height>300</height> - </rect> - </property> - <property name="windowTitle"> - <string>Profile Interface</string> - </property> - <layout class="QVBoxLayout" name="vlProfileInterface"> - <property name="spacing"> - <number>0</number> - </property> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QStackedWidget" name="swProfile"> - <property name="currentIndex"> - <number>0</number> - </property> - <widget class="QWidget" name="pageLoading"> - <layout class="QVBoxLayout" name="vlLoadingPage"> - <item> - <spacer name="vsLoading1"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="labProfileLoading"> - <property name="text"> - <string>Loading file %1 of %2 files</string> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - </widget> - </item> - <item> - <widget class="QProgressBar" name="pbPictureLoading"> - <property name="value"> - <number>0</number> - </property> - <property name="textVisible"> - <bool>false</bool> - </property> - </widget> - </item> - <item> - <spacer name="vsLoading2"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - <widget class="QWidget" name="pageProfile"> - <layout class="QVBoxLayout" name="vlProfilePage"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QScrollArea" name="saProfile"> - <property name="widgetResizable"> - <bool>true</bool> - </property> - <widget class="UiModWidget" name="saProfileContent"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>398</width> - <height>257</height> - </rect> - </property> - <property name="acceptDrops"> - <bool>true</bool> - </property> - <layout class="QVBoxLayout" name="vlProfile"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <layout class="QVBoxLayout" name="vlContent"> - <property name="spacing"> - <number>0</number> - </property> - <item> - <layout class="QVBoxLayout" name="vlSavegame"/> - </item> - <item> - <layout class="QVBoxLayout" name="vlSnapmatic"/> - </item> - </layout> - </item> - </layout> - </widget> - </widget> - </item> - </layout> - </widget> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="hlButtons"> - <property name="spacing"> - <number>6</number> - </property> - <property name="leftMargin"> - <number>9</number> - </property> - <property name="topMargin"> - <number>9</number> - </property> - <property name="rightMargin"> - <number>9</number> - </property> - <property name="bottomMargin"> - <number>9</number> - </property> - <item> - <widget class="QLabel" name="labVersion"> - <property name="text"> - <string>%1 %2</string> - </property> - </widget> - </item> - <item> - <spacer name="hsProfile"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="cmdImport"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Import exported file</string> - </property> - <property name="text"> - <string>&Import...</string> - </property> - <property name="autoDefault"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="cmdCloseProfile"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Close profile</string> - </property> - <property name="text"> - <string>&Close</string> - </property> - <property name="autoDefault"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - <customwidgets> - <customwidget> - <class>UiModWidget</class> - <extends>QWidget</extends> - <header>UiModWidget.h</header> - <container>1</container> - <slots> - <signal>dropped(QMimeData*)</signal> - </slots> - </customwidget> - </customwidgets> - <resources/> - <connections/> -</ui> +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ProfileInterface</class> + <widget class="QWidget" name="ProfileInterface"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string>Profile Interface</string> + </property> + <layout class="QVBoxLayout" name="vlProfileInterface"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QStackedWidget" name="swProfile"> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="pageLoading"> + <layout class="QVBoxLayout" name="vlLoadingPage"> + <item> + <spacer name="vsLoading1"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="labProfileLoading"> + <property name="text"> + <string>Loading file %1 of %2 files</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QProgressBar" name="pbPictureLoading"> + <property name="value"> + <number>0</number> + </property> + <property name="textVisible"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <spacer name="vsLoading2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="pageProfile"> + <layout class="QVBoxLayout" name="vlProfilePage"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QScrollArea" name="saProfile"> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="UiModWidget" name="saProfileContent"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>398</width> + <height>257</height> + </rect> + </property> + <property name="acceptDrops"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="vlProfile"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <layout class="QVBoxLayout" name="vlContent"> + <property name="spacing"> + <number>0</number> + </property> + <item> + <layout class="QVBoxLayout" name="vlSavegame"/> + </item> + <item> + <layout class="QVBoxLayout" name="vlSnapmatic"/> + </item> + </layout> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="hlButtons"> + <property name="spacing"> + <number>6</number> + </property> + <property name="leftMargin"> + <number>9</number> + </property> + <property name="topMargin"> + <number>9</number> + </property> + <property name="rightMargin"> + <number>9</number> + </property> + <property name="bottomMargin"> + <number>9</number> + </property> + <item> + <widget class="QLabel" name="labVersion"> + <property name="text"> + <string>%1 %2</string> + </property> + </widget> + </item> + <item> + <spacer name="hsProfile"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="cmdImport"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Import file</string> + </property> + <property name="text"> + <string>&Import...</string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="cmdCloseProfile"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Close profile</string> + </property> + <property name="text"> + <string>&Close</string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>UiModWidget</class> + <extends>QWidget</extends> + <header>UiModWidget.h</header> + <container>1</container> + <slots> + <signal>dropped(QMimeData*)</signal> + </slots> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/ProfileLoader.cpp b/ProfileLoader.cpp index 73e3941..243721e 100755 --- a/ProfileLoader.cpp +++ b/ProfileLoader.cpp @@ -1,103 +1,106 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "ProfileLoader.h" -#include "SnapmaticPicture.h" -#include "SavegameData.h" -#include "CrewDatabase.h" -#include <QStringList> -#include <QString> -#include <QFile> -#include <QDir> - -ProfileLoader::ProfileLoader(QString profileFolder, CrewDatabase *crewDB, QObject *parent) : QThread(parent), profileFolder(profileFolder), crewDB(crewDB) -{ - -} - -void ProfileLoader::run() -{ - int curFile = 1; - QDir profileDir; - QList<int> crewList; - profileDir.setPath(profileFolder); - - // Seek pictures and savegames - profileDir.setNameFilters(QStringList("SGTA*")); - QStringList SavegameFiles = profileDir.entryList(QDir::Files | QDir::NoDot, QDir::NoSort); - QStringList BackupFiles = SavegameFiles.filter(".bak", Qt::CaseInsensitive); - profileDir.setNameFilters(QStringList("PGTA*")); - QStringList SnapmaticPics = profileDir.entryList(QDir::Files | QDir::NoDot, QDir::NoSort); - BackupFiles.append(SnapmaticPics.filter(".bak", Qt::CaseInsensitive)); - - SavegameFiles.removeDuplicates(); - SnapmaticPics.removeDuplicates(); - foreach(const QString &BackupFile, BackupFiles) - { - SavegameFiles.removeAll(BackupFile); - SnapmaticPics.removeAll(BackupFile); - } - - int maximumV = SavegameFiles.length() + SnapmaticPics.length(); - - // Loading pictures and savegames - emit loadingProgress(curFile, maximumV); - foreach(const QString &SavegameFile, SavegameFiles) - { - emit loadingProgress(curFile, maximumV); - QString sgdPath = profileFolder + QDir::separator() + SavegameFile; - SavegameData *savegame = new SavegameData(sgdPath); - if (savegame->readingSavegame()) - { - emit savegameLoaded(savegame, sgdPath); - } - curFile++; - } - foreach(const QString &SnapmaticPic, SnapmaticPics) - { - emit loadingProgress(curFile, maximumV); - QString picturePath = profileFolder + QDir::separator() + SnapmaticPic; - SnapmaticPicture *picture = new SnapmaticPicture(picturePath); - if (picture->readingPicture(true, true, true)) - { - emit pictureLoaded(picture); - int crewNumber = picture->getSnapmaticProperties().crewID; - if (!crewList.contains(crewNumber)) - { - crewList.append(crewNumber); - } - } - curFile++; - } - - // adding found crews - foreach(int crewID, crewList) - { - crewDB->addCrew(crewID); - } -} - -void ProfileLoader::preloaded() -{ - -} - -void ProfileLoader::loaded() -{ - -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "ProfileLoader.h" +#include "SnapmaticPicture.h" +#include "SavegameData.h" +#include "CrewDatabase.h" +#include <QStringBuilder> +#include <QStringList> +#include <QString> +#include <QFile> +#include <QDir> + +ProfileLoader::ProfileLoader(QString profileFolder, CrewDatabase *crewDB, QObject *parent) : QThread(parent), profileFolder(profileFolder), crewDB(crewDB) +{ + +} + +void ProfileLoader::run() +{ + int curFile = 1; + QDir profileDir; + QList<int> crewList; + profileDir.setPath(profileFolder); + + // Seek pictures and savegames + profileDir.setNameFilters(QStringList("SGTA*")); + QStringList SavegameFiles = profileDir.entryList(QDir::Files | QDir::NoDot, QDir::NoSort); + QStringList BackupFiles = SavegameFiles.filter(".bak", Qt::CaseInsensitive); + profileDir.setNameFilters(QStringList("PGTA*")); + QStringList SnapmaticPics = profileDir.entryList(QDir::Files | QDir::NoDot, QDir::NoSort); + BackupFiles += SnapmaticPics.filter(".bak", Qt::CaseInsensitive); + + SavegameFiles.removeDuplicates(); + SnapmaticPics.removeDuplicates(); + foreach(const QString &BackupFile, BackupFiles) + { + SavegameFiles.removeAll(BackupFile); + SnapmaticPics.removeAll(BackupFile); + } + + int maximumV = SavegameFiles.length() + SnapmaticPics.length(); + + // Loading pictures and savegames + emit loadingProgress(curFile, maximumV); + foreach(const QString &SavegameFile, SavegameFiles) + { + emit loadingProgress(curFile, maximumV); + QString sgdPath = profileFolder % QDir::separator() % SavegameFile; + SavegameData *savegame = new SavegameData(sgdPath); + if (savegame->readingSavegame()) + { + emit savegameLoaded(savegame, sgdPath); + } + curFile++; + } + foreach(const QString &SnapmaticPic, SnapmaticPics) + { + emit loadingProgress(curFile, maximumV); + QString picturePath = profileFolder % QDir::separator() % SnapmaticPic; + SnapmaticPicture *picture = new SnapmaticPicture(picturePath); + if (picture->readingPicture(true, true, true)) + { + emit pictureLoaded(picture); + int crewNumber = picture->getSnapmaticProperties().crewID; + if (!crewList.contains(crewNumber)) + { + crewList += crewNumber; + } + } + curFile++; + } + + // adding found crews + crewDB->setAddingCrews(true); + foreach(int crewID, crewList) + { + crewDB->addCrew(crewID); + } + crewDB->setAddingCrews(false); +} + +void ProfileLoader::preloaded() +{ + +} + +void ProfileLoader::loaded() +{ + +} diff --git a/ProfileLoader.h b/ProfileLoader.h index 23c4d77..4de52fe 100755 --- a/ProfileLoader.h +++ b/ProfileLoader.h @@ -1,52 +1,52 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef PROFILELOADER_H -#define PROFILELOADER_H - -#include "SnapmaticPicture.h" -#include "SavegameData.h" -#include "CrewDatabase.h" -#include <QThread> -#include <QDir> - -class ProfileLoader : public QThread -{ - Q_OBJECT -public: - explicit ProfileLoader(QString profileFolder, CrewDatabase *crewDB, QObject *parent = 0); - -protected: - void run(); - -private: - QString profileFolder; - CrewDatabase *crewDB; - ProfileLoader *profileLoader; - -private slots: - void preloaded(); - void loaded(); - -signals: - void pictureLoaded(SnapmaticPicture *picture); - void savegameLoaded(SavegameData *savegame, QString savegamePath); - void loadingProgress(int value, int maximum); -}; - -#endif // PROFILELOADER_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef PROFILELOADER_H +#define PROFILELOADER_H + +#include "SnapmaticPicture.h" +#include "SavegameData.h" +#include "CrewDatabase.h" +#include <QThread> +#include <QDir> + +class ProfileLoader : public QThread +{ + Q_OBJECT +public: + explicit ProfileLoader(QString profileFolder, CrewDatabase *crewDB, QObject *parent = 0); + +protected: + void run(); + +private: + QString profileFolder; + CrewDatabase *crewDB; + ProfileLoader *profileLoader; + +private slots: + void preloaded(); + void loaded(); + +signals: + void pictureLoaded(SnapmaticPicture *picture); + void savegameLoaded(SavegameData *savegame, QString savegamePath); + void loadingProgress(int value, int maximum); +}; + +#endif // PROFILELOADER_H diff --git a/ProfileWidget.cpp b/ProfileWidget.cpp index 58828ef..09b7a0f 100755 --- a/ProfileWidget.cpp +++ b/ProfileWidget.cpp @@ -1,61 +1,66 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "ProfileWidget.h" -#include <QDebug> - -ProfileWidget::ProfileWidget(QWidget *parent) : QWidget(parent) -{ - contentMode = 0; -} - -ProfileWidget::~ProfileWidget() -{ -} - -bool ProfileWidget::isSelected() -{ - qDebug() << "ProfileWidget::isSelected got used without overwrite"; - return false; -} - -void ProfileWidget::setSelected(bool isSelected) -{ - qDebug() << "ProfileWidget::setSelected got used without overwrite, result" << isSelected; -} - -void ProfileWidget::setSelectionMode(bool selectionMode) -{ - qDebug() << "ProfileWidget::setSelectionMode got used without overwrite, result:" << selectionMode; -} - -QString ProfileWidget::getWidgetType() -{ - qDebug() << "ProfileWidget::getWidgetType got used without overwrite"; - return "ProfileWidget"; -} - -int ProfileWidget::getContentMode() -{ - return contentMode; -} - -void ProfileWidget::setContentMode(int _contentMode) -{ - contentMode = _contentMode; -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "ProfileWidget.h" +#include <QDebug> + +ProfileWidget::ProfileWidget(QWidget *parent) : QWidget(parent) +{ + contentMode = 0; +} + +ProfileWidget::~ProfileWidget() +{ +} + +void ProfileWidget::retranslate() +{ + qDebug() << "ProfileWidget::retranslate got used without overwrite"; +} + +bool ProfileWidget::isSelected() +{ + qDebug() << "ProfileWidget::isSelected got used without overwrite"; + return false; +} + +void ProfileWidget::setSelected(bool isSelected) +{ + qDebug() << "ProfileWidget::setSelected got used without overwrite, result" << isSelected; +} + +void ProfileWidget::setSelectionMode(bool selectionMode) +{ + qDebug() << "ProfileWidget::setSelectionMode got used without overwrite, result:" << selectionMode; +} + +QString ProfileWidget::getWidgetType() +{ + qDebug() << "ProfileWidget::getWidgetType got used without overwrite"; + return "ProfileWidget"; +} + +int ProfileWidget::getContentMode() +{ + return contentMode; +} + +void ProfileWidget::setContentMode(int _contentMode) +{ + contentMode = _contentMode; +} diff --git a/ProfileWidget.h b/ProfileWidget.h index 6fab255..8de7cda 100755 --- a/ProfileWidget.h +++ b/ProfileWidget.h @@ -1,45 +1,46 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef PROFILEWIDGET_H -#define PROFILEWIDGET_H - -#include <QWidget> - -class ProfileWidget : public QWidget -{ - Q_OBJECT -public: - explicit ProfileWidget(QWidget *parent = 0); - virtual void setSelectionMode(bool selectionMode); - virtual void setContentMode(int contentMode); - virtual void setSelected(bool isSelected); - virtual bool isSelected(); - virtual QString getWidgetType(); - virtual int getContentMode(); - ~ProfileWidget(); - -private: - int contentMode; - -signals: - -public slots: -}; - -#endif // PROFILEWIDGET_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef PROFILEWIDGET_H +#define PROFILEWIDGET_H + +#include <QWidget> + +class ProfileWidget : public QWidget +{ + Q_OBJECT +public: + explicit ProfileWidget(QWidget *parent = 0); + virtual void setSelectionMode(bool selectionMode); + virtual void setContentMode(int contentMode); + virtual void setSelected(bool isSelected); + virtual bool isSelected(); + virtual QString getWidgetType(); + virtual int getContentMode(); + virtual void retranslate(); + ~ProfileWidget(); + +private: + int contentMode; + +signals: + +public slots: +}; + +#endif // PROFILEWIDGET_H diff --git a/SavegameCopy.cpp b/SavegameCopy.cpp index fc0e3e0..2bcad1f 100755 --- a/SavegameCopy.cpp +++ b/SavegameCopy.cpp @@ -1,100 +1,100 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "SidebarGenerator.h" -#include "SavegameWidget.h" -#include "SavegameCopy.h" -#include "config.h" -#include <QMessageBox> -#include <QFileDialog> -#include <QSettings> - -SavegameCopy::SavegameCopy() -{ - -} - -void SavegameCopy::copySavegame(QWidget *parent, QString sgdPath) -{ - QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); - settings.beginGroup("FileDialogs"); - -fileDialogPreSave: //Work? - QFileInfo sgdFileInfo(sgdPath); - QFileDialog fileDialog(parent); - fileDialog.setFileMode(QFileDialog::AnyFile); - fileDialog.setViewMode(QFileDialog::Detail); - fileDialog.setAcceptMode(QFileDialog::AcceptSave); - fileDialog.setOption(QFileDialog::DontUseNativeDialog, false); - fileDialog.setOption(QFileDialog::DontConfirmOverwrite, true); - fileDialog.setDefaultSuffix(""); - fileDialog.setWindowFlags(fileDialog.windowFlags()^Qt::WindowContextHelpButtonHint); - fileDialog.setWindowTitle(SavegameWidget::tr(("Export Savegame..."))); - fileDialog.setLabelText(QFileDialog::Accept, SavegameWidget::tr("Export")); - - QStringList filters; - filters << SavegameWidget::tr("Savegame files (SGTA*)"); - filters << SavegameWidget::tr("All files (**)"); - fileDialog.setNameFilters(filters); - - QList<QUrl> sidebarUrls = SidebarGenerator::generateSidebarUrls(fileDialog.sidebarUrls()); - - fileDialog.setSidebarUrls(sidebarUrls); - fileDialog.restoreState(settings.value("CopySavegame","").toByteArray()); - fileDialog.selectFile(sgdFileInfo.fileName()); - - if (fileDialog.exec()) - { - QStringList selectedFiles = fileDialog.selectedFiles(); - if (selectedFiles.length() == 1) - { - QString selectedFile = selectedFiles.at(0); - - if (QFile::exists(selectedFile)) - { - if (QMessageBox::Yes == QMessageBox::warning(parent, SavegameWidget::tr("Export Savegame"), SavegameWidget::tr("Overwrite %1 with current Savegame?").arg("\""+selectedFile+"\""), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)) - { - if (!QFile::remove(selectedFile)) - { - QMessageBox::warning(parent, SavegameWidget::tr("Export Savegame"), SavegameWidget::tr("Failed to overwrite %1 with current Savegame").arg("\""+selectedFile+"\"")); - goto fileDialogPreSave; //Work? - } - } - else - { - goto fileDialogPreSave; //Work? - } - } - - bool isCopied = QFile::copy(sgdPath, selectedFile); - if (!isCopied) - { - QMessageBox::warning(parent, SavegameWidget::tr("Export Savegame"), SavegameWidget::tr("Failed to export current Savegame")); - goto fileDialogPreSave; //Work? - } - } - else - { - QMessageBox::warning(parent, SavegameWidget::tr("Export Savegame"), SavegameWidget::tr("No valid file is selected")); - goto fileDialogPreSave; //Work? - } - } - - settings.setValue("CopySavegame", fileDialog.saveState()); - settings.endGroup(); -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "SidebarGenerator.h" +#include "SavegameWidget.h" +#include "SavegameCopy.h" +#include "config.h" +#include <QMessageBox> +#include <QFileDialog> +#include <QSettings> + +SavegameCopy::SavegameCopy() +{ + +} + +void SavegameCopy::copySavegame(QWidget *parent, QString sgdPath) +{ + QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); + settings.beginGroup("FileDialogs"); + +fileDialogPreSave: //Work? + QFileInfo sgdFileInfo(sgdPath); + QFileDialog fileDialog(parent); + fileDialog.setFileMode(QFileDialog::AnyFile); + fileDialog.setViewMode(QFileDialog::Detail); + fileDialog.setAcceptMode(QFileDialog::AcceptSave); + fileDialog.setOption(QFileDialog::DontUseNativeDialog, false); + fileDialog.setOption(QFileDialog::DontConfirmOverwrite, true); + fileDialog.setDefaultSuffix(""); + fileDialog.setWindowFlags(fileDialog.windowFlags()^Qt::WindowContextHelpButtonHint); + fileDialog.setWindowTitle(SavegameWidget::tr(("Export Savegame..."))); + fileDialog.setLabelText(QFileDialog::Accept, SavegameWidget::tr("Export")); + + QStringList filters; + filters << SavegameWidget::tr("Savegame files (SGTA*)"); + filters << SavegameWidget::tr("All files (**)"); + fileDialog.setNameFilters(filters); + + QList<QUrl> sidebarUrls = SidebarGenerator::generateSidebarUrls(fileDialog.sidebarUrls()); + + fileDialog.setSidebarUrls(sidebarUrls); + fileDialog.restoreState(settings.value("CopySavegame","").toByteArray()); + fileDialog.selectFile(sgdFileInfo.fileName()); + + if (fileDialog.exec()) + { + QStringList selectedFiles = fileDialog.selectedFiles(); + if (selectedFiles.length() == 1) + { + QString selectedFile = selectedFiles.at(0); + + if (QFile::exists(selectedFile)) + { + if (QMessageBox::Yes == QMessageBox::warning(parent, SavegameWidget::tr("Export Savegame"), SavegameWidget::tr("Overwrite %1 with current Savegame?").arg("\""+selectedFile+"\""), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)) + { + if (!QFile::remove(selectedFile)) + { + QMessageBox::warning(parent, SavegameWidget::tr("Export Savegame"), SavegameWidget::tr("Failed to overwrite %1 with current Savegame").arg("\""+selectedFile+"\"")); + goto fileDialogPreSave; //Work? + } + } + else + { + goto fileDialogPreSave; //Work? + } + } + + bool isCopied = QFile::copy(sgdPath, selectedFile); + if (!isCopied) + { + QMessageBox::warning(parent, SavegameWidget::tr("Export Savegame"), SavegameWidget::tr("Failed to export current Savegame")); + goto fileDialogPreSave; //Work? + } + } + else + { + QMessageBox::warning(parent, SavegameWidget::tr("Export Savegame"), SavegameWidget::tr("No valid file is selected")); + goto fileDialogPreSave; //Work? + } + } + + settings.setValue("CopySavegame", fileDialog.saveState()); + settings.endGroup(); +} diff --git a/SavegameCopy.h b/SavegameCopy.h index 1ea5cf6..6447497 100755 --- a/SavegameCopy.h +++ b/SavegameCopy.h @@ -1,32 +1,32 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef SAVEGAMECOPY_H -#define SAVEGAMECOPY_H - -#include <QWidget> -#include <QString> - -class SavegameCopy -{ -public: - SavegameCopy(); - static void copySavegame(QWidget *parent, QString sgdPath); -}; - -#endif // SAVEGAMECOPY_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef SAVEGAMECOPY_H +#define SAVEGAMECOPY_H + +#include <QWidget> +#include <QString> + +class SavegameCopy +{ +public: + SavegameCopy(); + static void copySavegame(QWidget *parent, QString sgdPath); +}; + +#endif // SAVEGAMECOPY_H diff --git a/SavegameData.cpp b/SavegameData.cpp index b679325..826746a 100755 --- a/SavegameData.cpp +++ b/SavegameData.cpp @@ -1,119 +1,120 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "StringParser.h" -#include "SavegameData.h" -#include <QTextCodec> -#include <QByteArray> -#include <QDebug> -#include <QFile> - -#define savegameHeaderLength 260 -#define verificationValue QByteArray::fromHex("00000001") - -SavegameData::SavegameData(const QString &fileName, QObject *parent) : QObject(parent), savegameFileName(fileName) -{ - // INIT SAVEGAME - savegameStr = ""; - savegameOk = 0; -} - -bool SavegameData::readingSavegame() -{ - // Start opening file - // lastStep is like currentStep - - QFile *saveFile = new QFile(savegameFileName); - if (!saveFile->open(QFile::ReadOnly)) - { - lastStep = "1;/1,OpenFile," + StringParser::convertDrawStringForLog(savegameFileName); - saveFile->deleteLater(); - delete saveFile; - return false; - } - - // Reading Savegame Header - if (!saveFile->isReadable()) - { - lastStep = "2;/3,ReadingFile," + StringParser::convertDrawStringForLog(savegameFileName) + ",1,NOHEADER"; - saveFile->close(); - saveFile->deleteLater(); - delete saveFile; - return false; - } - QByteArray savegameHeaderLine = saveFile->read(savegameHeaderLength); - if (savegameHeaderLine.left(4) == verificationValue) - { - savegameStr = getSavegameDataString(savegameHeaderLine); - if (savegameStr.length() >= 1) - { - savegameOk = true; - } - } - saveFile->close(); - saveFile->deleteLater(); - delete saveFile; - return savegameOk; -} - -QString SavegameData::getSavegameDataString(const QByteArray &savegameHeader) -{ - QByteArray savegameBytes = savegameHeader.left(savegameHeaderLength); - QList<QByteArray> savegameBytesList = savegameBytes.split(char(0x01)); - savegameBytes = savegameBytesList.at(1); - savegameBytesList.clear(); - return StringParser::parseTitleString(savegameBytes, savegameBytes.length()); -} - -bool SavegameData::readingSavegameFromFile(const QString &fileName) -{ - if (fileName != "") - { - savegameFileName = fileName; - return readingSavegame(); - } - else - { - return false; - } -} - -bool SavegameData::isSavegameOk() -{ - return savegameOk; -} - -QString SavegameData::getSavegameFileName() -{ - return savegameFileName; -} - -QString SavegameData::getSavegameStr() -{ - return savegameStr; -} - -QString SavegameData::getLastStep() -{ - return lastStep; -} - -void SavegameData::setSavegameFileName(QString savegameFileName_) -{ - savegameFileName = savegameFileName_; -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "StringParser.h" +#include "SavegameData.h" +#include <QStringBuilder> +#include <QTextCodec> +#include <QByteArray> +#include <QDebug> +#include <QFile> + +#define savegameHeaderLength 260 +#define verificationValue QByteArray::fromHex("00000001") + +SavegameData::SavegameData(const QString &fileName, QObject *parent) : QObject(parent), savegameFileName(fileName) +{ + // INIT SAVEGAME + savegameStr = ""; + savegameOk = 0; +} + +bool SavegameData::readingSavegame() +{ + // Start opening file + // lastStep is like currentStep + + QFile *saveFile = new QFile(savegameFileName); + if (!saveFile->open(QFile::ReadOnly)) + { + lastStep = "1;/1,OpenFile," % StringParser::convertDrawStringForLog(savegameFileName); + saveFile->deleteLater(); + delete saveFile; + return false; + } + + // Reading Savegame Header + if (!saveFile->isReadable()) + { + lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(savegameFileName) % ",1,NOHEADER"; + saveFile->close(); + saveFile->deleteLater(); + delete saveFile; + return false; + } + QByteArray savegameHeaderLine = saveFile->read(savegameHeaderLength); + if (savegameHeaderLine.left(4) == verificationValue) + { + savegameStr = getSavegameDataString(savegameHeaderLine); + if (savegameStr.length() >= 1) + { + savegameOk = true; + } + } + saveFile->close(); + saveFile->deleteLater(); + delete saveFile; + return savegameOk; +} + +QString SavegameData::getSavegameDataString(const QByteArray &savegameHeader) +{ + QByteArray savegameBytes = savegameHeader.left(savegameHeaderLength); + QList<QByteArray> savegameBytesList = savegameBytes.split(char(0x01)); + savegameBytes = savegameBytesList.at(1); + savegameBytesList.clear(); + return StringParser::parseTitleString(savegameBytes, savegameBytes.length()); +} + +bool SavegameData::readingSavegameFromFile(const QString &fileName) +{ + if (fileName != "") + { + savegameFileName = fileName; + return readingSavegame(); + } + else + { + return false; + } +} + +bool SavegameData::isSavegameOk() +{ + return savegameOk; +} + +QString SavegameData::getSavegameFileName() +{ + return savegameFileName; +} + +QString SavegameData::getSavegameStr() +{ + return savegameStr; +} + +QString SavegameData::getLastStep() +{ + return lastStep; +} + +void SavegameData::setSavegameFileName(QString savegameFileName_) +{ + savegameFileName = savegameFileName_; +} diff --git a/SavegameData.h b/SavegameData.h index 20f87b3..bc5cf2f 100755 --- a/SavegameData.h +++ b/SavegameData.h @@ -1,45 +1,45 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef SAVEGAMEDATA_H -#define SAVEGAMEDATA_H - -#include <QObject> - -class SavegameData : public QObject -{ - Q_OBJECT -public: - explicit SavegameData(const QString &fileName = "", QObject *parent = 0); - bool readingSavegameFromFile(const QString &fileName); - bool readingSavegame(); - bool isSavegameOk(); - QString getLastStep(); - QString getSavegameStr(); - QString getSavegameFileName(); - void setSavegameFileName(QString savegameFileName); - -private: - QString getSavegameDataString(const QByteArray &savegameHeader); - QString savegameFileName; - QString savegameStr; - QString lastStep; - bool savegameOk; -}; - -#endif // SAVEGAMEDATA_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef SAVEGAMEDATA_H +#define SAVEGAMEDATA_H + +#include <QObject> + +class SavegameData : public QObject +{ + Q_OBJECT +public: + explicit SavegameData(const QString &fileName = "", QObject *parent = 0); + bool readingSavegameFromFile(const QString &fileName); + bool readingSavegame(); + bool isSavegameOk(); + QString getLastStep(); + QString getSavegameStr(); + QString getSavegameFileName(); + void setSavegameFileName(QString savegameFileName); + +private: + QString getSavegameDataString(const QByteArray &savegameHeader); + QString savegameFileName; + QString savegameStr; + QString lastStep; + bool savegameOk; +}; + +#endif // SAVEGAMEDATA_H diff --git a/SavegameDialog.cpp b/SavegameDialog.cpp index 99447ce..a3e52d3 100755 --- a/SavegameDialog.cpp +++ b/SavegameDialog.cpp @@ -1,53 +1,53 @@ -#include "SavegameDialog.h" -#include "ui_SavegameDialog.h" -#include "SavegameCopy.h" -#include "AppEnv.h" -#include <QMessageBox> - -SavegameDialog::SavegameDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::SavegameDialog) -{ - // Set Window Flags - setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint); - - // Setup User Interface - ui->setupUi(this); - savegameLabStr = ui->labSavegameText->text(); - - if (QIcon::hasThemeIcon("dialog-close")) - { - ui->cmdClose->setIcon(QIcon::fromTheme("dialog-close")); - } - - // DPI calculation - qreal screenRatio = AppEnv::screenRatio(); - resize(400 * screenRatio, 105 * screenRatio); -} - -SavegameDialog::~SavegameDialog() -{ - delete ui; -} - -void SavegameDialog::setSavegameData(SavegameData *savegame, QString savegamePath, bool readOk) -{ - // Showing error if reading error - if (!readOk) - { - QMessageBox::warning(this,tr("Savegame Viewer"),tr("Failed at %1").arg(savegame->getLastStep())); - return; - } - sgdPath = savegamePath; - ui->labSavegameText->setText(savegameLabStr.arg(savegame->getSavegameStr())); -} - -void SavegameDialog::on_cmdClose_clicked() -{ - this->close(); -} - -void SavegameDialog::on_cmdCopy_clicked() -{ - SavegameCopy::copySavegame(this, sgdPath); -} +#include "SavegameDialog.h" +#include "ui_SavegameDialog.h" +#include "SavegameCopy.h" +#include "AppEnv.h" +#include <QMessageBox> + +SavegameDialog::SavegameDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::SavegameDialog) +{ + // Set Window Flags + setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint); + + // Setup User Interface + ui->setupUi(this); + savegameLabStr = ui->labSavegameText->text(); + + if (QIcon::hasThemeIcon("dialog-close")) + { + ui->cmdClose->setIcon(QIcon::fromTheme("dialog-close")); + } + + // DPI calculation + qreal screenRatio = AppEnv::screenRatio(); + resize(400 * screenRatio, 105 * screenRatio); +} + +SavegameDialog::~SavegameDialog() +{ + delete ui; +} + +void SavegameDialog::setSavegameData(SavegameData *savegame, QString savegamePath, bool readOk) +{ + // Showing error if reading error + if (!readOk) + { + QMessageBox::warning(this,tr("Savegame Viewer"),tr("Failed at %1").arg(savegame->getLastStep())); + return; + } + sgdPath = savegamePath; + ui->labSavegameText->setText(savegameLabStr.arg(savegame->getSavegameStr())); +} + +void SavegameDialog::on_cmdClose_clicked() +{ + this->close(); +} + +void SavegameDialog::on_cmdCopy_clicked() +{ + SavegameCopy::copySavegame(this, sgdPath); +} diff --git a/SavegameDialog.h b/SavegameDialog.h index 0b3a900..9fe8f35 100755 --- a/SavegameDialog.h +++ b/SavegameDialog.h @@ -1,29 +1,29 @@ -#ifndef SAVEGAMEDIALOG_H -#define SAVEGAMEDIALOG_H - -#include "SavegameData.h" -#include <QDialog> - -namespace Ui { -class SavegameDialog; -} - -class SavegameDialog : public QDialog -{ - Q_OBJECT -public: - explicit SavegameDialog(QWidget *parent = 0); - void setSavegameData(SavegameData *savegame, QString sgdPath, bool readOk); - ~SavegameDialog(); - -private slots: - void on_cmdClose_clicked(); - void on_cmdCopy_clicked(); - -private: - Ui::SavegameDialog *ui; - QString savegameLabStr; - QString sgdPath; -}; - -#endif // SAVEGAMEDIALOG_H +#ifndef SAVEGAMEDIALOG_H +#define SAVEGAMEDIALOG_H + +#include "SavegameData.h" +#include <QDialog> + +namespace Ui { +class SavegameDialog; +} + +class SavegameDialog : public QDialog +{ + Q_OBJECT +public: + explicit SavegameDialog(QWidget *parent = 0); + void setSavegameData(SavegameData *savegame, QString sgdPath, bool readOk); + ~SavegameDialog(); + +private slots: + void on_cmdClose_clicked(); + void on_cmdCopy_clicked(); + +private: + Ui::SavegameDialog *ui; + QString savegameLabStr; + QString sgdPath; +}; + +#endif // SAVEGAMEDIALOG_H diff --git a/SavegameDialog.ui b/SavegameDialog.ui index a0a5e52..36b3b9b 100755 --- a/SavegameDialog.ui +++ b/SavegameDialog.ui @@ -1,86 +1,93 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>SavegameDialog</class> - <widget class="QDialog" name="SavegameDialog"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>400</width> - <height>105</height> - </rect> - </property> - <property name="windowTitle"> - <string>Savegame Viewer</string> - </property> - <property name="modal"> - <bool>true</bool> - </property> - <layout class="QVBoxLayout" name="vlSavegameDialog"> - <item> - <widget class="QLabel" name="labSavegameText"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string><span style=" font-weight:600;">Savegame</span><br><br>%1</string> - </property> - <property name="alignment"> - <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="hlButtons"> - <item> - <spacer name="hsButtons"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="cmdCopy"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>&Export</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="cmdClose"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>&Close</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>SavegameDialog</class> + <widget class="QDialog" name="SavegameDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>105</height> + </rect> + </property> + <property name="windowTitle"> + <string>Savegame Viewer</string> + </property> + <property name="modal"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="vlSavegameDialog"> + <item> + <widget class="QLabel" name="labSavegameText"> + <property name="text"> + <string><span style=" font-weight:600;">Savegame</span><br><br>%1</string> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <spacer name="vsSavegame"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QHBoxLayout" name="hlButtons"> + <item> + <spacer name="hsButtons"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="cmdCopy"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Export</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="cmdClose"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Close</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/SavegameWidget.cpp b/SavegameWidget.cpp index 6783bf9..ce21f46 100755 --- a/SavegameWidget.cpp +++ b/SavegameWidget.cpp @@ -1,261 +1,264 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "SavegameWidget.h" -#include "ui_SavegameWidget.h" -#include "SidebarGenerator.h" -#include "SavegameDialog.h" -#include "StandardPaths.h" -#include "SavegameData.h" -#include "SavegameCopy.h" -#include "AppEnv.h" -#include <QFileDialog> -#include <QMessageBox> -#include <QSettings> -#include <QFileInfo> -#include <QPalette> -#include <QColor> -#include <QBrush> -#include <QTimer> -#include <QDebug> -#include <QFile> -#include <QMenu> -#include <QUrl> - -SavegameWidget::SavegameWidget(QWidget *parent) : - ProfileWidget(parent), - ui(new Ui::SavegameWidget) -{ - ui->setupUi(this); - ui->cmdCopy->setVisible(false); - ui->cmdView->setVisible(false); - ui->cmdDelete->setVisible(false); - ui->cbSelected->setVisible(false); - - qreal screenRatio = AppEnv::screenRatio(); - ui->labSavegamePic->setFixedSize(48 * screenRatio, 27 * screenRatio); - - QPixmap savegamePixmap(":/img/savegame.png"); - if (screenRatio != 1) savegamePixmap = savegamePixmap.scaledToHeight(ui->labSavegamePic->height(), Qt::SmoothTransformation); - ui->labSavegamePic->setPixmap(savegamePixmap); - - QString exportSavegameStr = tr("Export Savegame..."); - Q_UNUSED(exportSavegameStr) - - QPalette palette; - highlightBackColor = palette.highlight().color(); - highlightTextColor = palette.highlightedText().color(); - - labelAutosaveStr = tr("AUTOSAVE - %1\n%2"); - labelSaveStr = tr("SAVE %3 - %1\n%2"); - snwgt = parent; - sgdPath = ""; - sgdStr = ""; - sgdata = 0; - - installEventFilter(this); -} - -SavegameWidget::~SavegameWidget() -{ - delete ui; -} - -bool SavegameWidget::eventFilter(QObject *obj, QEvent *ev) -{ - if (obj == this) - { - if (ev->type() == QEvent::Enter) - { - setStyleSheet(QString("QFrame#SavegameFrame{background-color: rgb(%1, %2, %3)}QLabel#labSavegameStr{color: rgb(%4, %5, %6)}").arg(QString::number(highlightBackColor.red()), QString::number(highlightBackColor.green()), QString::number(highlightBackColor.blue()), QString::number(highlightTextColor.red()), QString::number(highlightTextColor.green()), QString::number(highlightTextColor.blue()))); - return true; - } - else if(ev->type() == QEvent::Leave) - { - setStyleSheet(""); - return true; - } - } - return false; -} - -void SavegameWidget::setSavegameData(SavegameData *savegame, QString savegamePath) -{ - // BETA CODE - bool validNumber; - QString savegameName = tr("WRONG FORMAT"); - QString savegameDate = tr("WRONG FORMAT"); - QString savegameString = savegame->getSavegameStr(); - QString fileName = QFileInfo(savegame->getSavegameFileName()).fileName(); - QStringList savegameNDL = QString(savegameString).split(" - "); - if (savegameNDL.length() >= 2) - { - savegameDate = savegameNDL.at(savegameNDL.length() - 1); - savegameName = QString(savegameString).remove(savegameString.length() - savegameDate.length() - 3, savegameDate.length() + 3); - } - int savegameNumber = QString(fileName).remove(0,5).toInt(&validNumber) + 1; - if (validNumber) - { - if (savegameNumber == 16) - { - ui->labSavegameStr->setText(labelAutosaveStr.arg(savegameDate, savegameName)); - } - else - { - ui->labSavegameStr->setText(labelSaveStr.arg(savegameDate, savegameName, QString::number(savegameNumber))); - } - } - else - { - ui->labSavegameStr->setText(labelSaveStr.arg(savegameDate, savegameName, tr("UNKNOWN"))); - } - sgdStr = savegameString; - sgdPath = savegamePath; - sgdata = savegame; -} - -void SavegameWidget::on_cmdCopy_clicked() -{ - SavegameCopy::copySavegame(this, sgdPath); -} - -void SavegameWidget::on_cmdDelete_clicked() -{ - int uchoice = QMessageBox::question(this, tr("Delete savegame"), tr("Are you sure to delete %1 from your savegames?").arg("\""+sgdStr+"\""), QMessageBox::No | QMessageBox::Yes, QMessageBox::No); - if (uchoice == QMessageBox::Yes) - { - if (!QFile::exists(sgdPath)) - { - emit savegameDeleted(); - } - else if(QFile::remove(sgdPath)) - { - emit savegameDeleted(); - } - else - { - QMessageBox::warning(this, tr("Delete savegame"), tr("Failed at deleting %1 from your savegames").arg("\""+sgdStr+"\"")); - } - } -} - -void SavegameWidget::on_cmdView_clicked() -{ - SavegameDialog *savegameDialog = new SavegameDialog(this); - savegameDialog->setSavegameData(sgdata, sgdPath, true); - savegameDialog->setModal(true); -#ifdef Q_OS_ANDROID - // Android ... - savegameDialog->showMaximized(); -#else - savegameDialog->show(); -#endif - savegameDialog->exec(); - delete savegameDialog; -} - -void SavegameWidget::mousePressEvent(QMouseEvent *ev) -{ - ProfileWidget::mousePressEvent(ev); -} - -void SavegameWidget::mouseReleaseEvent(QMouseEvent *ev) -{ - ProfileWidget::mouseReleaseEvent(ev); - if (ui->cbSelected->isVisible()) - { - if (rect().contains(ev->pos()) && ev->button() == Qt::LeftButton) - { - ui->cbSelected->setChecked(!ui->cbSelected->isChecked()); - } - } - else - { - if (getContentMode() == 0 && rect().contains(ev->pos()) && ev->button() == Qt::LeftButton) - { - on_cmdView_clicked(); - } - } -} - -void SavegameWidget::mouseDoubleClickEvent(QMouseEvent *ev) -{ - ProfileWidget::mouseDoubleClickEvent(ev); - - if (!ui->cbSelected->isVisible() && getContentMode() == 1 && ev->button() == Qt::LeftButton) - { - on_cmdView_clicked(); - } -} - -void SavegameWidget::setSelected(bool isSelected) -{ - ui->cbSelected->setChecked(isSelected); -} - -void SavegameWidget::savegameSelected() -{ - setSelected(!ui->cbSelected->isChecked()); -} - -void SavegameWidget::contextMenuEvent(QContextMenuEvent *ev) -{ - emit contextMenuTriggered(ev); -} - -void SavegameWidget::on_cbSelected_stateChanged(int arg1) -{ - if (arg1 == Qt::Checked) - { - emit widgetSelected(); - } - else if (arg1 == Qt::Unchecked) - { - emit widgetDeselected(); - } -} - -bool SavegameWidget::isSelected() -{ - return ui->cbSelected->isChecked(); -} - -void SavegameWidget::setSelectionMode(bool selectionMode) -{ - ui->cbSelected->setVisible(selectionMode); -} - -void SavegameWidget::selectAllWidgets() -{ - emit allWidgetsSelected(); -} - -void SavegameWidget::deselectAllWidgets() -{ - emit allWidgetsDeselected(); -} - -SavegameData* SavegameWidget::getSavegame() -{ - return sgdata; -} - -QString SavegameWidget::getWidgetType() -{ - return "SavegameWidget"; -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "SavegameWidget.h" +#include "ui_SavegameWidget.h" +#include "SidebarGenerator.h" +#include "SavegameDialog.h" +#include "StandardPaths.h" +#include "SavegameData.h" +#include "SavegameCopy.h" +#include "AppEnv.h" +#include <QFileDialog> +#include <QMessageBox> +#include <QSettings> +#include <QFileInfo> +#include <QPalette> +#include <QColor> +#include <QBrush> +#include <QTimer> +#include <QDebug> +#include <QFile> +#include <QMenu> +#include <QUrl> + +SavegameWidget::SavegameWidget(QWidget *parent) : + ProfileWidget(parent), + ui(new Ui::SavegameWidget) +{ + ui->setupUi(this); + ui->cmdCopy->setVisible(false); + ui->cmdView->setVisible(false); + ui->cmdDelete->setVisible(false); + ui->cbSelected->setVisible(false); + + qreal screenRatio = AppEnv::screenRatio(); + ui->labSavegamePic->setFixedSize(48 * screenRatio, 27 * screenRatio); + + QPixmap savegamePixmap(":/img/savegame.png"); + if (screenRatio != 1) savegamePixmap = savegamePixmap.scaledToHeight(ui->labSavegamePic->height(), Qt::SmoothTransformation); + ui->labSavegamePic->setPixmap(savegamePixmap); + + QString exportSavegameStr = tr("Export Savegame..."); + Q_UNUSED(exportSavegameStr) + + labelAutosaveStr = tr("AUTOSAVE - %1\n%2"); + labelSaveStr = tr("SAVE %3 - %1\n%2"); + + ui->SavegameFrame->setMouseTracking(true); + ui->labSavegamePic->setMouseTracking(true); + ui->labSavegameStr->setMouseTracking(true); + ui->cbSelected->setMouseTracking(true); + sgdata = nullptr; +} + +SavegameWidget::~SavegameWidget() +{ + delete ui; +} + +void SavegameWidget::setSavegameData(SavegameData *savegame, QString savegamePath) +{ + // BETA CODE + QString savegameString = savegame->getSavegameStr(); + QString fileName = QFileInfo(savegame->getSavegameFileName()).fileName(); + renderString(savegameString, fileName); + sgdStr = savegameString; + sgdPath = savegamePath; + sgdata = savegame; +} + +void SavegameWidget::renderString(const QString &savegameString, const QString &fileName) +{ + bool validNumber; + QString savegameName = tr("WRONG FORMAT"); + QString savegameDate = tr("WRONG FORMAT"); + QStringList savegameNDL = QString(savegameString).split(" - "); + if (savegameNDL.length() >= 2) + { + savegameDate = savegameNDL.at(savegameNDL.length() - 1); + savegameName = QString(savegameString).remove(savegameString.length() - savegameDate.length() - 3, savegameDate.length() + 3); + } + int savegameNumber = QString(fileName).remove(0,5).toInt(&validNumber) + 1; + if (validNumber) + { + if (savegameNumber == 16) + { + ui->labSavegameStr->setText(labelAutosaveStr.arg(savegameDate, savegameName)); + } + else + { + ui->labSavegameStr->setText(labelSaveStr.arg(savegameDate, savegameName, QString::number(savegameNumber))); + } + } + else + { + ui->labSavegameStr->setText(labelSaveStr.arg(savegameDate, savegameName, tr("UNKNOWN"))); + } +} + +void SavegameWidget::retranslate() +{ + labelAutosaveStr = tr("AUTOSAVE - %1\n%2"); + labelSaveStr = tr("SAVE %3 - %1\n%2"); + + QString fileName = QFileInfo(sgdata->getSavegameFileName()).fileName(); + renderString(sgdStr, fileName); +} + +void SavegameWidget::on_cmdCopy_clicked() +{ + SavegameCopy::copySavegame(this, sgdPath); +} + +void SavegameWidget::on_cmdDelete_clicked() +{ + int uchoice = QMessageBox::question(this, tr("Delete savegame"), tr("Are you sure to delete %1 from your savegames?").arg("\""+sgdStr+"\""), QMessageBox::No | QMessageBox::Yes, QMessageBox::No); + if (uchoice == QMessageBox::Yes) + { + if (!QFile::exists(sgdPath)) + { + emit savegameDeleted(); + } + else if(QFile::remove(sgdPath)) + { + emit savegameDeleted(); + } + else + { + QMessageBox::warning(this, tr("Delete savegame"), tr("Failed at deleting %1 from your savegames").arg("\""+sgdStr+"\"")); + } + } +} + +void SavegameWidget::on_cmdView_clicked() +{ + SavegameDialog *savegameDialog = new SavegameDialog(this); + savegameDialog->setSavegameData(sgdata, sgdPath, true); + savegameDialog->setModal(true); +#ifdef Q_OS_ANDROID + // Android ... + savegameDialog->showMaximized(); +#else + savegameDialog->show(); +#endif + savegameDialog->exec(); + delete savegameDialog; +} + +void SavegameWidget::mousePressEvent(QMouseEvent *ev) +{ + ProfileWidget::mousePressEvent(ev); +} + +void SavegameWidget::mouseReleaseEvent(QMouseEvent *ev) +{ + ProfileWidget::mouseReleaseEvent(ev); + if (ui->cbSelected->isVisible()) + { + if (rect().contains(ev->pos()) && ev->button() == Qt::LeftButton) + { + ui->cbSelected->setChecked(!ui->cbSelected->isChecked()); + } + } + else + { + if (getContentMode() == 0 && rect().contains(ev->pos()) && ev->button() == Qt::LeftButton) + { + if (ev->modifiers().testFlag(Qt::ShiftModifier)) + { + ui->cbSelected->setChecked(!ui->cbSelected->isChecked()); + } + else + { + on_cmdView_clicked(); + } + } + else if (!ui->cbSelected->isVisible() && getContentMode() == 1 && ev->button() == Qt::LeftButton && ev->modifiers().testFlag(Qt::ShiftModifier)) + { + ui->cbSelected->setChecked(!ui->cbSelected->isChecked()); + } + } +} + +void SavegameWidget::mouseDoubleClickEvent(QMouseEvent *ev) +{ + ProfileWidget::mouseDoubleClickEvent(ev); + + if (!ui->cbSelected->isVisible() && getContentMode() == 1 && ev->button() == Qt::LeftButton) + { + on_cmdView_clicked(); + } +} + +void SavegameWidget::setSelected(bool isSelected) +{ + ui->cbSelected->setChecked(isSelected); +} + +void SavegameWidget::savegameSelected() +{ + setSelected(!ui->cbSelected->isChecked()); +} + +void SavegameWidget::contextMenuEvent(QContextMenuEvent *ev) +{ + emit contextMenuTriggered(ev); +} + +void SavegameWidget::on_cbSelected_stateChanged(int arg1) +{ + if (arg1 == Qt::Checked) + { + emit widgetSelected(); + } + else if (arg1 == Qt::Unchecked) + { + emit widgetDeselected(); + } +} + +bool SavegameWidget::isSelected() +{ + return ui->cbSelected->isChecked(); +} + +void SavegameWidget::setSelectionMode(bool selectionMode) +{ + ui->cbSelected->setVisible(selectionMode); +} + +void SavegameWidget::selectAllWidgets() +{ + emit allWidgetsSelected(); +} + +void SavegameWidget::deselectAllWidgets() +{ + emit allWidgetsDeselected(); +} + +SavegameData* SavegameWidget::getSavegame() +{ + return sgdata; +} + +QString SavegameWidget::getWidgetType() +{ + return "SavegameWidget"; +} diff --git a/SavegameWidget.h b/SavegameWidget.h index f0f62c4..0db69af 100755 --- a/SavegameWidget.h +++ b/SavegameWidget.h @@ -1,82 +1,80 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef SAVEGAMEWIDGET_H -#define SAVEGAMEWIDGET_H -#include "ProfileWidget.h" -#include "SavegameData.h" -#include <QContextMenuEvent> -#include <QMouseEvent> -#include <QWidget> -#include <QColor> - -namespace Ui { -class SavegameWidget; -} - -class SavegameWidget : public ProfileWidget -{ - Q_OBJECT - -public: - SavegameWidget(QWidget *parent = 0); - void setSavegameData(SavegameData *savegame, QString savegamePath); - void setSelectionMode(bool selectionMode); - void setSelected(bool isSelected); - SavegameData* getSavegame(); - QString getWidgetType(); - bool isSelected(); - ~SavegameWidget(); - -private slots: - void on_cmdView_clicked(); - void on_cmdCopy_clicked(); - void on_cmdDelete_clicked(); - void on_cbSelected_stateChanged(int arg1); - void savegameSelected(); - void selectAllWidgets(); - void deselectAllWidgets(); - -protected: - bool eventFilter(QObject *obj, QEvent *ev); - void mouseDoubleClickEvent(QMouseEvent *ev); - void mouseReleaseEvent(QMouseEvent *ev); - void mousePressEvent(QMouseEvent *ev); - void contextMenuEvent(QContextMenuEvent *ev); - -private: - Ui::SavegameWidget *ui; - SavegameData *sgdata; - QColor highlightBackColor; - QColor highlightTextColor; - QString labelAutosaveStr; - QString labelSaveStr; - QString sgdPath; - QString sgdStr; - QWidget *snwgt; - -signals: - void savegameDeleted(); - void widgetSelected(); - void widgetDeselected(); - void allWidgetsSelected(); - void allWidgetsDeselected(); - void contextMenuTriggered(QContextMenuEvent *ev); -}; - -#endif // SAVEGAMEWIDGET_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef SAVEGAMEWIDGET_H +#define SAVEGAMEWIDGET_H +#include "ProfileWidget.h" +#include "SavegameData.h" +#include <QContextMenuEvent> +#include <QMouseEvent> +#include <QWidget> +#include <QColor> + +namespace Ui { +class SavegameWidget; +} + +class SavegameWidget : public ProfileWidget +{ + Q_OBJECT + +public: + SavegameWidget(QWidget *parent = 0); + void setSavegameData(SavegameData *savegame, QString savegamePath); + void setSelectionMode(bool selectionMode); + void setSelected(bool isSelected); + SavegameData* getSavegame(); + QString getWidgetType(); + bool isSelected(); + void retranslate(); + ~SavegameWidget(); + +private slots: + void on_cmdView_clicked(); + void on_cmdCopy_clicked(); + void on_cmdDelete_clicked(); + void on_cbSelected_stateChanged(int arg1); + void savegameSelected(); + void selectAllWidgets(); + void deselectAllWidgets(); + +protected: + void mouseDoubleClickEvent(QMouseEvent *ev); + void mouseReleaseEvent(QMouseEvent *ev); + void mousePressEvent(QMouseEvent *ev); + void contextMenuEvent(QContextMenuEvent *ev); + +private: + Ui::SavegameWidget *ui; + SavegameData *sgdata; + QString labelAutosaveStr; + QString labelSaveStr; + QString sgdPath; + QString sgdStr; + void renderString(const QString &savegameString, const QString &fileName); + +signals: + void savegameDeleted(); + void widgetSelected(); + void widgetDeselected(); + void allWidgetsSelected(); + void allWidgetsDeselected(); + void contextMenuTriggered(QContextMenuEvent *ev); +}; + +#endif // SAVEGAMEWIDGET_H diff --git a/SavegameWidget.ui b/SavegameWidget.ui index 2f857c7..ea5e3c6 100755 --- a/SavegameWidget.ui +++ b/SavegameWidget.ui @@ -1,135 +1,135 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>SavegameWidget</class> - <widget class="QWidget" name="SavegameWidget"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>405</width> - <height>46</height> - </rect> - </property> - <property name="windowTitle"> - <string>Savegame Widget</string> - </property> - <layout class="QHBoxLayout" name="hlSavegameContent"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QFrame" name="SavegameFrame"> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Plain</enum> - </property> - <property name="lineWidth"> - <number>0</number> - </property> - <layout class="QHBoxLayout" name="hlSavegame"> - <item> - <widget class="QCheckBox" name="cbSelected"> - <property name="focusPolicy"> - <enum>Qt::NoFocus</enum> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="labSavegamePic"> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="labSavegameStr"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>SAVE %3 - %1<br>%2</string> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="cmdView"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>View savegame</string> - </property> - <property name="text"> - <string>View</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="cmdCopy"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Copy savegame</string> - </property> - <property name="text"> - <string>Export</string> - </property> - <property name="autoDefault"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="cmdDelete"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Delete savegame</string> - </property> - <property name="text"> - <string>Delete</string> - </property> - <property name="autoDefault"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>SavegameWidget</class> + <widget class="QWidget" name="SavegameWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>405</width> + <height>46</height> + </rect> + </property> + <property name="windowTitle"> + <string>Savegame Widget</string> + </property> + <layout class="QHBoxLayout" name="hlSavegameContent"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QFrame" name="SavegameFrame"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <layout class="QHBoxLayout" name="hlSavegame"> + <item> + <widget class="QCheckBox" name="cbSelected"> + <property name="focusPolicy"> + <enum>Qt::NoFocus</enum> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="labSavegamePic"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="labSavegameStr"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>SAVE %3 - %1<br>%2</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="cmdView"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>View savegame</string> + </property> + <property name="text"> + <string>View</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="cmdCopy"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Copy savegame</string> + </property> + <property name="text"> + <string>Export</string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="cmdDelete"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Delete savegame</string> + </property> + <property name="text"> + <string>Delete</string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/SidebarGenerator.cpp b/SidebarGenerator.cpp index 2675dae..1d57e5d 100755 --- a/SidebarGenerator.cpp +++ b/SidebarGenerator.cpp @@ -1,61 +1,61 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "SidebarGenerator.h" -#include "StandardPaths.h" -#include "AppEnv.h" -#include <QList> -#include <QUrl> -#include <QDir> - -SidebarGenerator::SidebarGenerator() -{ - -} - -QList<QUrl> SidebarGenerator::generateSidebarUrls(QList<QUrl> sidebarUrls) -{ - QDir dir; - - dir.setPath(StandardPaths::picturesLocation()); - if (dir.exists()) - { - sidebarUrls << QUrl::fromLocalFile(dir.absolutePath()); - } - - dir.setPath(StandardPaths::documentsLocation()); - if (dir.exists()) - { - sidebarUrls << QUrl::fromLocalFile(dir.absolutePath()); - } - - bool gameFolderExists; - QString gameFolder = AppEnv::getGameFolder(&gameFolderExists); - if (gameFolderExists) - { - sidebarUrls << QUrl::fromLocalFile(gameFolder); - } - - dir.setPath(StandardPaths::desktopLocation()); - if (dir.exists()) - { - sidebarUrls << QUrl::fromLocalFile(dir.absolutePath()); - } - - return sidebarUrls; -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "SidebarGenerator.h" +#include "StandardPaths.h" +#include "AppEnv.h" +#include <QList> +#include <QUrl> +#include <QDir> + +SidebarGenerator::SidebarGenerator() +{ + +} + +QList<QUrl> SidebarGenerator::generateSidebarUrls(QList<QUrl> sidebarUrls) +{ + QDir dir; + + dir.setPath(StandardPaths::picturesLocation()); + if (dir.exists()) + { + sidebarUrls += QUrl::fromLocalFile(dir.absolutePath()); + } + + dir.setPath(StandardPaths::documentsLocation()); + if (dir.exists()) + { + sidebarUrls += QUrl::fromLocalFile(dir.absolutePath()); + } + + bool gameFolderExists; + QString gameFolder = AppEnv::getGameFolder(&gameFolderExists); + if (gameFolderExists) + { + sidebarUrls += QUrl::fromLocalFile(gameFolder); + } + + dir.setPath(StandardPaths::desktopLocation()); + if (dir.exists()) + { + sidebarUrls += QUrl::fromLocalFile(dir.absolutePath()); + } + + return sidebarUrls; +} diff --git a/SidebarGenerator.h b/SidebarGenerator.h index 35716c0..5e906a3 100755 --- a/SidebarGenerator.h +++ b/SidebarGenerator.h @@ -1,32 +1,32 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef SIDEBARGENERATOR_H -#define SIDEBARGENERATOR_H - -#include <QList> -#include <QUrl> - -class SidebarGenerator -{ -public: - SidebarGenerator(); - static QList<QUrl> generateSidebarUrls(QList<QUrl> sidebarUrls); -}; - -#endif // SIDEBARGENERATOR_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef SIDEBARGENERATOR_H +#define SIDEBARGENERATOR_H + +#include <QList> +#include <QUrl> + +class SidebarGenerator +{ +public: + SidebarGenerator(); + static QList<QUrl> generateSidebarUrls(QList<QUrl> sidebarUrls); +}; + +#endif // SIDEBARGENERATOR_H diff --git a/SnapmaticEditor.cpp b/SnapmaticEditor.cpp index c4ce38f..10239a3 100644 --- a/SnapmaticEditor.cpp +++ b/SnapmaticEditor.cpp @@ -1,340 +1,340 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "SnapmaticEditor.h" -#include "ui_SnapmaticEditor.h" -#include "SnapmaticPicture.h" -#include "StringParser.h" -#include "AppEnv.h" -#include <QStringBuilder> -#include <QTextDocument> -#include <QInputDialog> -#include <QMessageBox> -#include <QDebug> -#include <QFile> - -SnapmaticEditor::SnapmaticEditor(CrewDatabase *crewDB, QWidget *parent) : - QDialog(parent), crewDB(crewDB), - ui(new Ui::SnapmaticEditor) -{ - ui->setupUi(this); - ui->cmdApply->setDefault(true); - - if (QIcon::hasThemeIcon("dialog-apply")) - { - ui->cmdApply->setIcon(QIcon::fromTheme("dialog-apply")); - } - if (QIcon::hasThemeIcon("dialog-cancel")) - { - ui->cmdCancel->setIcon(QIcon::fromTheme("dialog-cancel")); - } - - snapmaticTitle = ""; - smpic = 0; - - // DPI calculation - qreal screenRatio = AppEnv::screenRatio(); - resize(400 * screenRatio, 360 * screenRatio); -} - -SnapmaticEditor::~SnapmaticEditor() -{ - delete ui; -} - -void SnapmaticEditor::selfie_toggled(bool checked) -{ - if (checked) - { - isSelfie = true; - } - else - { - isSelfie = false; - } -} - - -void SnapmaticEditor::mugshot_toggled(bool checked) -{ - if (checked) - { - isMugshot = true; - ui->cbDirector->setEnabled(false); - ui->cbDirector->setChecked(false); - } - else - { - isMugshot = false; - ui->cbDirector->setEnabled(true); - } -} - -void SnapmaticEditor::editor_toggled(bool checked) -{ - if (checked) - { - isEditor = true; - ui->cbDirector->setEnabled(false); - ui->cbDirector->setChecked(false); - } - else - { - isEditor = false; - ui->cbDirector->setEnabled(true); - } -} - -void SnapmaticEditor::on_rbSelfie_toggled(bool checked) -{ - if (checked) - { - mugshot_toggled(false); - editor_toggled(false); - selfie_toggled(true); - } -} - -void SnapmaticEditor::on_rbMugshot_toggled(bool checked) -{ - if (checked) - { - selfie_toggled(false); - editor_toggled(false); - mugshot_toggled(true); - } -} - -void SnapmaticEditor::on_rbEditor_toggled(bool checked) -{ - if (checked) - { - selfie_toggled(false); - mugshot_toggled(false); - editor_toggled(true); - } -} - -void SnapmaticEditor::on_rbCustom_toggled(bool checked) -{ - if (checked) - { - selfie_toggled(false); - mugshot_toggled(false); - editor_toggled(false); - } -} - -void SnapmaticEditor::setSnapmaticPicture(SnapmaticPicture *picture) -{ - smpic = picture; - localSpJson = smpic->getSnapmaticProperties(); - ui->rbCustom->setChecked(true); - crewID = localSpJson.crewID; - isSelfie = localSpJson.isSelfie; - isMugshot = localSpJson.isMug; - isEditor = localSpJson.isFromRSEditor; - ui->cbDirector->setChecked(localSpJson.isFromDirector); - ui->cbMeme->setChecked(localSpJson.isMeme); - if (isSelfie) - { - ui->rbSelfie->setChecked(true); - } - else if (isMugshot) - { - ui->rbMugshot->setChecked(true); - } - else if (isEditor) - { - ui->rbEditor->setChecked(true); - } - else - { - ui->rbCustom->setChecked(true); - } - setSnapmaticCrew(returnCrewName(crewID)); - setSnapmaticTitle(picture->getPictureTitle()); -} - -void SnapmaticEditor::setSnapmaticTitle(const QString &title) -{ - if (title.length() > 39) - { - snapmaticTitle = title.left(39); - } - else - { - snapmaticTitle = title; - } - QString editStr = QString("<a href=\"g5e://edittitle\" style=\"text-decoration: none;\">%1</a>").arg(tr("Edit")); - QString titleStr = tr("Title: %1 (%2)").arg(StringParser::escapeString(snapmaticTitle), editStr); - ui->labTitle->setText(titleStr); - if (SnapmaticPicture::verifyTitle(snapmaticTitle)) - { - ui->labAppropriate->setText(tr("Appropriate: %1").arg(QString("<span style=\"color: green\">%1</a>").arg(tr("Yes", "Yes, should work fine")))); - } - else - { - ui->labAppropriate->setText(tr("Appropriate: %1").arg(QString("<span style=\"color: red\">%1</a>").arg(tr("No", "No, could lead to issues")))); - } -} - -void SnapmaticEditor::setSnapmaticCrew(const QString &crew) -{ - QString editStr = QString("<a href=\"g5e://editcrew\" style=\"text-decoration: none;\">%1</a>").arg(tr("Edit")); - QString crewStr = tr("Crew: %1 (%2)").arg(StringParser::escapeString(crew), editStr); - ui->labCrew->setText(crewStr); -} - -QString SnapmaticEditor::returnCrewName(int crewID_) -{ - return crewDB->getCrewName(crewID_); -} - -void SnapmaticEditor::on_cmdCancel_clicked() -{ - close(); -} - -void SnapmaticEditor::on_cmdApply_clicked() -{ - if (ui->cbQualify->isChecked()) - { - qualifyAvatar(); - } - localSpJson.crewID = crewID; - localSpJson.isSelfie = isSelfie; - localSpJson.isMug = isMugshot; - localSpJson.isFromRSEditor = isEditor; - localSpJson.isFromDirector = ui->cbDirector->isChecked(); - localSpJson.isMeme = ui->cbMeme->isChecked(); - if (smpic) - { - QString originalFileName = smpic->getPictureFilePath(); - QString adjustedFileName = originalFileName; - if (adjustedFileName.right(7) == ".hidden") // for the hidden file system - { - adjustedFileName.remove(adjustedFileName.length() - 7, 7); - } - QString backupFileName = adjustedFileName % ".bak"; - if (!QFile::exists(backupFileName)) - { - QFile::copy(adjustedFileName, backupFileName); - } - SnapmaticProperties fallbackProperties = smpic->getSnapmaticProperties(); - QString fallbackTitle = smpic->getPictureTitle(); - smpic->setSnapmaticProperties(localSpJson); - smpic->setPictureTitle(snapmaticTitle); - if (!smpic->exportPicture(originalFileName)) - { - QMessageBox::warning(this, tr("Snapmatic Properties"), tr("Patching of Snapmatic Properties failed because of I/O Error")); - smpic->setSnapmaticProperties(fallbackProperties); - smpic->setPictureTitle(fallbackTitle); - } - else - { - smpic->emitUpdate(); - } - } - close(); -} - -void SnapmaticEditor::qualifyAvatar() -{ - ui->rbSelfie->setChecked(true); - ui->cbDirector->setChecked(false); - ui->cbMeme->setChecked(false); - ui->cmdApply->setDefault(true); -} - -void SnapmaticEditor::on_cbQualify_toggled(bool checked) -{ - if (checked) - { - ui->cbMeme->setEnabled(false); - ui->cbDirector->setEnabled(false); - ui->rbCustom->setEnabled(false); - ui->rbSelfie->setEnabled(false); - ui->rbEditor->setEnabled(false); - ui->rbMugshot->setEnabled(false); - } - else - { - ui->cbMeme->setEnabled(true); - ui->rbCustom->setEnabled(true); - ui->rbSelfie->setEnabled(true); - ui->rbEditor->setEnabled(true); - ui->rbMugshot->setEnabled(true); - if (ui->rbSelfie->isChecked() || ui->rbCustom->isChecked()) - { - ui->cbDirector->setEnabled(true); - } - } -} - -void SnapmaticEditor::on_labTitle_linkActivated(const QString &link) -{ - if (link == "g5e://edittitle") - { - bool ok; - QString newTitle = QInputDialog::getText(this, tr("Snapmatic Title"), tr("New Snapmatic title:"), QLineEdit::Normal, snapmaticTitle, &ok, windowFlags()); - if (ok && !newTitle.isEmpty()) - { - setSnapmaticTitle(newTitle); - } - } -} - -void SnapmaticEditor::on_labCrew_linkActivated(const QString &link) -{ - if (link == "g5e://editcrew") - { - bool ok; - int indexNum = 0; - QStringList itemList; - QStringList crewList = crewDB->getCrews(); - if (!crewList.contains(QLatin1String("0"))) - { - crewList.append(QLatin1String("0")); - } - crewList.sort(); - foreach(const QString &crew, crewList) - { - itemList.append(QString("%1 (%2)").arg(crew, returnCrewName(crew.toInt()))); - } - if (crewList.contains(QString::number(crewID))) - { - indexNum = crewList.indexOf(QRegExp(QString::number(crewID))); - } - QString newCrew = QInputDialog::getItem(this, tr("Snapmatic Crew"), tr("New Snapmatic crew:"), itemList, indexNum, true, &ok, windowFlags()); - if (ok && !newCrew.isEmpty()) - { - if (newCrew.contains(" ")) newCrew = newCrew.split(" ").at(0); - if (newCrew.length() > 10) return; - foreach (const QChar &crewChar, newCrew) - { - if (!crewChar.isNumber()) - { - return; - } - } - crewID = newCrew.toInt(); - setSnapmaticCrew(returnCrewName(crewID)); - } - } -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "SnapmaticEditor.h" +#include "ui_SnapmaticEditor.h" +#include "SnapmaticPicture.h" +#include "StringParser.h" +#include "AppEnv.h" +#include <QStringBuilder> +#include <QTextDocument> +#include <QInputDialog> +#include <QMessageBox> +#include <QDebug> +#include <QFile> + +SnapmaticEditor::SnapmaticEditor(CrewDatabase *crewDB, QWidget *parent) : + QDialog(parent), crewDB(crewDB), + ui(new Ui::SnapmaticEditor) +{ + ui->setupUi(this); + ui->cmdApply->setDefault(true); + + if (QIcon::hasThemeIcon("dialog-apply")) + { + ui->cmdApply->setIcon(QIcon::fromTheme("dialog-apply")); + } + if (QIcon::hasThemeIcon("dialog-cancel")) + { + ui->cmdCancel->setIcon(QIcon::fromTheme("dialog-cancel")); + } + + snapmaticTitle = ""; + smpic = 0; + + // DPI calculation + qreal screenRatio = AppEnv::screenRatio(); + resize(400 * screenRatio, 360 * screenRatio); +} + +SnapmaticEditor::~SnapmaticEditor() +{ + delete ui; +} + +void SnapmaticEditor::selfie_toggled(bool checked) +{ + if (checked) + { + isSelfie = true; + } + else + { + isSelfie = false; + } +} + + +void SnapmaticEditor::mugshot_toggled(bool checked) +{ + if (checked) + { + isMugshot = true; + ui->cbDirector->setEnabled(false); + ui->cbDirector->setChecked(false); + } + else + { + isMugshot = false; + ui->cbDirector->setEnabled(true); + } +} + +void SnapmaticEditor::editor_toggled(bool checked) +{ + if (checked) + { + isEditor = true; + ui->cbDirector->setEnabled(false); + ui->cbDirector->setChecked(false); + } + else + { + isEditor = false; + ui->cbDirector->setEnabled(true); + } +} + +void SnapmaticEditor::on_rbSelfie_toggled(bool checked) +{ + if (checked) + { + mugshot_toggled(false); + editor_toggled(false); + selfie_toggled(true); + } +} + +void SnapmaticEditor::on_rbMugshot_toggled(bool checked) +{ + if (checked) + { + selfie_toggled(false); + editor_toggled(false); + mugshot_toggled(true); + } +} + +void SnapmaticEditor::on_rbEditor_toggled(bool checked) +{ + if (checked) + { + selfie_toggled(false); + mugshot_toggled(false); + editor_toggled(true); + } +} + +void SnapmaticEditor::on_rbCustom_toggled(bool checked) +{ + if (checked) + { + selfie_toggled(false); + mugshot_toggled(false); + editor_toggled(false); + } +} + +void SnapmaticEditor::setSnapmaticPicture(SnapmaticPicture *picture) +{ + smpic = picture; + localSpJson = smpic->getSnapmaticProperties(); + ui->rbCustom->setChecked(true); + crewID = localSpJson.crewID; + isSelfie = localSpJson.isSelfie; + isMugshot = localSpJson.isMug; + isEditor = localSpJson.isFromRSEditor; + ui->cbDirector->setChecked(localSpJson.isFromDirector); + ui->cbMeme->setChecked(localSpJson.isMeme); + if (isSelfie) + { + ui->rbSelfie->setChecked(true); + } + else if (isMugshot) + { + ui->rbMugshot->setChecked(true); + } + else if (isEditor) + { + ui->rbEditor->setChecked(true); + } + else + { + ui->rbCustom->setChecked(true); + } + setSnapmaticCrew(returnCrewName(crewID)); + setSnapmaticTitle(picture->getPictureTitle()); +} + +void SnapmaticEditor::setSnapmaticTitle(const QString &title) +{ + if (title.length() > 39) + { + snapmaticTitle = title.left(39); + } + else + { + snapmaticTitle = title; + } + QString editStr = QString("<a href=\"g5e://edittitle\" style=\"text-decoration: none;\">%1</a>").arg(tr("Edit")); + QString titleStr = tr("Title: %1 (%2)").arg(StringParser::escapeString(snapmaticTitle), editStr); + ui->labTitle->setText(titleStr); + if (SnapmaticPicture::verifyTitle(snapmaticTitle)) + { + ui->labAppropriate->setText(tr("Appropriate: %1").arg(QString("<span style=\"color: green\">%1</a>").arg(tr("Yes", "Yes, should work fine")))); + } + else + { + ui->labAppropriate->setText(tr("Appropriate: %1").arg(QString("<span style=\"color: red\">%1</a>").arg(tr("No", "No, could lead to issues")))); + } +} + +void SnapmaticEditor::setSnapmaticCrew(const QString &crew) +{ + QString editStr = QString("<a href=\"g5e://editcrew\" style=\"text-decoration: none;\">%1</a>").arg(tr("Edit")); + QString crewStr = tr("Crew: %1 (%2)").arg(StringParser::escapeString(crew), editStr); + ui->labCrew->setText(crewStr); +} + +QString SnapmaticEditor::returnCrewName(int crewID_) +{ + return crewDB->getCrewName(crewID_); +} + +void SnapmaticEditor::on_cmdCancel_clicked() +{ + close(); +} + +void SnapmaticEditor::on_cmdApply_clicked() +{ + if (ui->cbQualify->isChecked()) + { + qualifyAvatar(); + } + localSpJson.crewID = crewID; + localSpJson.isSelfie = isSelfie; + localSpJson.isMug = isMugshot; + localSpJson.isFromRSEditor = isEditor; + localSpJson.isFromDirector = ui->cbDirector->isChecked(); + localSpJson.isMeme = ui->cbMeme->isChecked(); + if (smpic) + { + QString originalFileName = smpic->getPictureFilePath(); + QString adjustedFileName = originalFileName; + if (adjustedFileName.right(7) == ".hidden") // for the hidden file system + { + adjustedFileName.remove(adjustedFileName.length() - 7, 7); + } + QString backupFileName = adjustedFileName % ".bak"; + if (!QFile::exists(backupFileName)) + { + QFile::copy(adjustedFileName, backupFileName); + } + SnapmaticProperties fallbackProperties = smpic->getSnapmaticProperties(); + QString fallbackTitle = smpic->getPictureTitle(); + smpic->setSnapmaticProperties(localSpJson); + smpic->setPictureTitle(snapmaticTitle); + if (!smpic->exportPicture(originalFileName)) + { + QMessageBox::warning(this, tr("Snapmatic Properties"), tr("Patching of Snapmatic Properties failed because of I/O Error")); + smpic->setSnapmaticProperties(fallbackProperties); + smpic->setPictureTitle(fallbackTitle); + } + else + { + smpic->emitUpdate(); + } + } + close(); +} + +void SnapmaticEditor::qualifyAvatar() +{ + ui->rbSelfie->setChecked(true); + ui->cbDirector->setChecked(false); + ui->cbMeme->setChecked(false); + ui->cmdApply->setDefault(true); +} + +void SnapmaticEditor::on_cbQualify_toggled(bool checked) +{ + if (checked) + { + ui->cbMeme->setEnabled(false); + ui->cbDirector->setEnabled(false); + ui->rbCustom->setEnabled(false); + ui->rbSelfie->setEnabled(false); + ui->rbEditor->setEnabled(false); + ui->rbMugshot->setEnabled(false); + } + else + { + ui->cbMeme->setEnabled(true); + ui->rbCustom->setEnabled(true); + ui->rbSelfie->setEnabled(true); + ui->rbEditor->setEnabled(true); + ui->rbMugshot->setEnabled(true); + if (ui->rbSelfie->isChecked() || ui->rbCustom->isChecked()) + { + ui->cbDirector->setEnabled(true); + } + } +} + +void SnapmaticEditor::on_labTitle_linkActivated(const QString &link) +{ + if (link == "g5e://edittitle") + { + bool ok; + QString newTitle = QInputDialog::getText(this, tr("Snapmatic Title"), tr("New Snapmatic title:"), QLineEdit::Normal, snapmaticTitle, &ok, windowFlags()); + if (ok && !newTitle.isEmpty()) + { + setSnapmaticTitle(newTitle); + } + } +} + +void SnapmaticEditor::on_labCrew_linkActivated(const QString &link) +{ + if (link == "g5e://editcrew") + { + bool ok; + int indexNum = 0; + QStringList itemList; + QStringList crewList = crewDB->getCrews(); + if (!crewList.contains(QLatin1String("0"))) + { + crewList += QLatin1String("0"); + } + crewList.sort(); + foreach(const QString &crew, crewList) + { + itemList += QString("%1 (%2)").arg(crew, returnCrewName(crew.toInt())); + } + if (crewList.contains(QString::number(crewID))) + { + indexNum = crewList.indexOf(QRegExp(QString::number(crewID))); + } + QString newCrew = QInputDialog::getItem(this, tr("Snapmatic Crew"), tr("New Snapmatic crew:"), itemList, indexNum, true, &ok, windowFlags()); + if (ok && !newCrew.isEmpty()) + { + if (newCrew.contains(" ")) newCrew = newCrew.split(" ").at(0); + if (newCrew.length() > 10) return; + foreach (const QChar &crewChar, newCrew) + { + if (!crewChar.isNumber()) + { + return; + } + } + crewID = newCrew.toInt(); + setSnapmaticCrew(returnCrewName(crewID)); + } + } +} diff --git a/SnapmaticEditor.h b/SnapmaticEditor.h index d2f41ee..243d85a 100644 --- a/SnapmaticEditor.h +++ b/SnapmaticEditor.h @@ -1,69 +1,69 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef SNAPMATICEDITOR_H -#define SNAPMATICEDITOR_H - -#include <QDialog> -#include "CrewDatabase.h" -#include "SnapmaticPicture.h" - -namespace Ui { -class SnapmaticEditor; -} - -class SnapmaticEditor : public QDialog -{ - Q_OBJECT - -public: - explicit SnapmaticEditor(CrewDatabase *crewDB, QWidget *parent = 0); - void setSnapmaticPicture(SnapmaticPicture *picture); - void setSnapmaticTitle(const QString &title); - void setSnapmaticCrew(const QString &crew = ""); - QString returnCrewName(int crewID); - ~SnapmaticEditor(); - -private slots: - void on_rbSelfie_toggled(bool checked); - void on_rbMugshot_toggled(bool checked); - void on_rbEditor_toggled(bool checked); - void on_rbCustom_toggled(bool checked); - void on_cmdCancel_clicked(); - void on_cmdApply_clicked(); - void on_cbQualify_toggled(bool checked); - void on_labTitle_linkActivated(const QString &link); - void on_labCrew_linkActivated(const QString &link); - -private: - CrewDatabase *crewDB; - Ui::SnapmaticEditor *ui; - SnapmaticProperties localSpJson; - SnapmaticPicture *smpic; - QString snapmaticTitle; - int crewID; - bool isSelfie; - bool isMugshot; - bool isEditor; - void selfie_toggled(bool checked); - void mugshot_toggled(bool checked); - void editor_toggled(bool checked); - void qualifyAvatar(); -}; - -#endif // SNAPMATICEDITOR_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef SNAPMATICEDITOR_H +#define SNAPMATICEDITOR_H + +#include <QDialog> +#include "CrewDatabase.h" +#include "SnapmaticPicture.h" + +namespace Ui { +class SnapmaticEditor; +} + +class SnapmaticEditor : public QDialog +{ + Q_OBJECT + +public: + explicit SnapmaticEditor(CrewDatabase *crewDB, QWidget *parent = 0); + void setSnapmaticPicture(SnapmaticPicture *picture); + void setSnapmaticTitle(const QString &title); + void setSnapmaticCrew(const QString &crew = ""); + QString returnCrewName(int crewID); + ~SnapmaticEditor(); + +private slots: + void on_rbSelfie_toggled(bool checked); + void on_rbMugshot_toggled(bool checked); + void on_rbEditor_toggled(bool checked); + void on_rbCustom_toggled(bool checked); + void on_cmdCancel_clicked(); + void on_cmdApply_clicked(); + void on_cbQualify_toggled(bool checked); + void on_labTitle_linkActivated(const QString &link); + void on_labCrew_linkActivated(const QString &link); + +private: + CrewDatabase *crewDB; + Ui::SnapmaticEditor *ui; + SnapmaticProperties localSpJson; + SnapmaticPicture *smpic; + QString snapmaticTitle; + int crewID; + bool isSelfie; + bool isMugshot; + bool isEditor; + void selfie_toggled(bool checked); + void mugshot_toggled(bool checked); + void editor_toggled(bool checked); + void qualifyAvatar(); +}; + +#endif // SNAPMATICEDITOR_H diff --git a/SnapmaticEditor.ui b/SnapmaticEditor.ui index 46ffa60..6a8a538 100644 --- a/SnapmaticEditor.ui +++ b/SnapmaticEditor.ui @@ -1,248 +1,248 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>SnapmaticEditor</class> - <widget class="QDialog" name="SnapmaticEditor"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>400</width> - <height>362</height> - </rect> - </property> - <property name="windowTitle"> - <string>Snapmatic Properties</string> - </property> - <property name="modal"> - <bool>true</bool> - </property> - <layout class="QVBoxLayout" name="vlEditor"> - <item> - <widget class="QWidget" name="frameWidget" native="true"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <layout class="QVBoxLayout" name="vlFrame"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QGroupBox" name="gbMode"> - <property name="title"> - <string>Snapmatic Type</string> - </property> - <layout class="QGridLayout" name="gdType"> - <item row="2" column="1"> - <widget class="QRadioButton" name="rbEditor"> - <property name="text"> - <string>Editor</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QRadioButton" name="rbSelfie"> - <property name="text"> - <string>Selfie</string> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QRadioButton" name="rbCustom"> - <property name="text"> - <string>Regular</string> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QRadioButton" name="rbMugshot"> - <property name="text"> - <string>Mugshot</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="gbProperties"> - <property name="title"> - <string>Snapmatic Properties</string> - </property> - <layout class="QGridLayout" name="gdProperties"> - <item row="0" column="1"> - <widget class="QCheckBox" name="cbMeme"> - <property name="text"> - <string>Meme</string> - </property> - </widget> - </item> - <item row="0" column="2"> - <widget class="QCheckBox" name="cbDirector"> - <property name="text"> - <string>Director</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="gbValues"> - <property name="title"> - <string>Snapmatic Values</string> - </property> - <layout class="QVBoxLayout" name="vlTitle"> - <item> - <widget class="UiModLabel" name="labCrew"> - <property name="contextMenuPolicy"> - <enum>Qt::NoContextMenu</enum> - </property> - <property name="text"> - <string>Crew: %1 (%2)</string> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="UiModLabel" name="labTitle"> - <property name="contextMenuPolicy"> - <enum>Qt::NoContextMenu</enum> - </property> - <property name="text"> - <string>Title: %1 (%2)</string> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="UiModLabel" name="labAppropriate"> - <property name="text"> - <string>Appropriate: %1</string> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="gbExtras"> - <property name="title"> - <string>Extras</string> - </property> - <layout class="QVBoxLayout" name="vlExtras"> - <item> - <widget class="QCheckBox" name="cbQualify"> - <property name="text"> - <string>Qualify as Avatar automatically at apply</string> - </property> - </widget> - </item> - <item> - <widget class="UiModLabel" name="labQualify"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Qualify as Avatar allows you to use this Snapmatic as a Social Club profile picture</string> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <spacer name="vsEditor"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <layout class="QHBoxLayout" name="hlButtons"> - <item> - <spacer name="hsButtons"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="cmdApply"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>&Apply</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="cmdCancel"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>&Cancel</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - <customwidgets> - <customwidget> - <class>UiModLabel</class> - <extends>QLabel</extends> - <header>UiModLabel.h</header> - </customwidget> - </customwidgets> - <resources/> - <connections/> -</ui> +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>SnapmaticEditor</class> + <widget class="QDialog" name="SnapmaticEditor"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>362</height> + </rect> + </property> + <property name="windowTitle"> + <string>Snapmatic Properties</string> + </property> + <property name="modal"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="vlEditor"> + <item> + <widget class="QWidget" name="frameWidget" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QVBoxLayout" name="vlFrame"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QGroupBox" name="gbMode"> + <property name="title"> + <string>Snapmatic Type</string> + </property> + <layout class="QGridLayout" name="gdType"> + <item row="2" column="1"> + <widget class="QRadioButton" name="rbEditor"> + <property name="text"> + <string>Editor</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QRadioButton" name="rbSelfie"> + <property name="text"> + <string>Selfie</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QRadioButton" name="rbCustom"> + <property name="text"> + <string>Regular</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QRadioButton" name="rbMugshot"> + <property name="text"> + <string>Mugshot</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="gbProperties"> + <property name="title"> + <string>Snapmatic Properties</string> + </property> + <layout class="QGridLayout" name="gdProperties"> + <item row="0" column="1"> + <widget class="QCheckBox" name="cbMeme"> + <property name="text"> + <string>Meme</string> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QCheckBox" name="cbDirector"> + <property name="text"> + <string>Director</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="gbValues"> + <property name="title"> + <string>Snapmatic Values</string> + </property> + <layout class="QVBoxLayout" name="vlTitle"> + <item> + <widget class="UiModLabel" name="labCrew"> + <property name="contextMenuPolicy"> + <enum>Qt::NoContextMenu</enum> + </property> + <property name="text"> + <string>Crew: %1 (%2)</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="UiModLabel" name="labTitle"> + <property name="contextMenuPolicy"> + <enum>Qt::NoContextMenu</enum> + </property> + <property name="text"> + <string>Title: %1 (%2)</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="UiModLabel" name="labAppropriate"> + <property name="text"> + <string>Appropriate: %1</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="gbExtras"> + <property name="title"> + <string>Extras</string> + </property> + <layout class="QVBoxLayout" name="vlExtras"> + <item> + <widget class="QCheckBox" name="cbQualify"> + <property name="text"> + <string>Qualify as Avatar automatically at apply</string> + </property> + </widget> + </item> + <item> + <widget class="UiModLabel" name="labQualify"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Qualify as Avatar allows you to use this Snapmatic as a Social Club profile picture</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="vsEditor"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QHBoxLayout" name="hlButtons"> + <item> + <spacer name="hsButtons"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="cmdApply"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Apply</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="cmdCancel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Cancel</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>UiModLabel</class> + <extends>QLabel</extends> + <header>UiModLabel.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/SnapmaticPicture.cpp b/SnapmaticPicture.cpp index 1ded9ad..3a209bd 100755 --- a/SnapmaticPicture.cpp +++ b/SnapmaticPicture.cpp @@ -1,972 +1,1078 @@ -/***************************************************************************** -* gta5sync-spv Grand Theft Auto Snapmatic Picture Viewer -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "SnapmaticPicture.h" -#include "StringParser.h" -#include <QStringBuilder> -#include <QJsonDocument> -#include <QJsonObject> -#include <QStringList> -#include <QVariantMap> -#include <QJsonArray> -#include <QFileInfo> -#include <QPainter> -#include <QString> -#include <QBuffer> -#include <QDebug> -#include <QImage> -#include <QSize> -#include <QFile> - -// PARSER ALLOCATIONS -#define snapmaticHeaderLength 278 -#define snapmaticUsefulLength 260 -#define snapmaticFileMaxSize 528192 -#define jpegHeaderLineDifStr 2 -#define jpegPreHeaderLength 14 -#define jpegPicStreamLength 524288 -#define jsonStreamLength 3076 -#define tideStreamLength 260 - -// EDITOR ALLOCATIONS -#define jpegStreamEditorBegin 292 -#define jsonStreamEditorBegin 524588 -#define jsonStreamEditorLength 3072 -#define titlStreamEditorBegin 527668 -#define titlStreamEditorLength 256 -#define titlStreamCharacterMax 39 - -// IMAGES VALUES -#define snapmaticResolutionW 960 -#define snapmaticResolutionH 536 -#define snapmaticResolution QSize(snapmaticResolutionW, snapmaticResolutionH) - -SnapmaticPicture::SnapmaticPicture(const QString &fileName, QObject *parent) : QObject(parent), picFilePath(fileName) -{ - reset(); -} - -SnapmaticPicture::~SnapmaticPicture() -{ -} - -void SnapmaticPicture::reset() -{ - // INIT PIC - rawPicContent = ""; - cachePicture = QImage(); - jpegRawContentSizeE = 0; - jpegRawContentSize = 0; - picExportFileName = ""; - isCustomFormat = 0; - isLoadedInRAM = 0; - pictureHead = ""; - pictureStr = ""; - lowRamMode = 0; - lastStep = ""; - sortStr = ""; - titlStr = ""; - descStr = ""; - picOk = 0; - - // INIT JSON - jsonOk = 0; - jsonStr = ""; - - // SNAPMATIC PROPERTIES - localSpJson = {}; -} - -bool SnapmaticPicture::preloadFile() -{ - QFile *picFile = new QFile(picFilePath); - picFileName = QFileInfo(picFilePath).fileName(); - - if (!picFile->open(QFile::ReadOnly)) - { - lastStep = "1;/1,OpenFile," % StringParser::convertDrawStringForLog(picFilePath); - delete picFile; - return false; - } - if (picFilePath.right(4) != QLatin1String(".g5e")) - { - rawPicContent = picFile->read(snapmaticFileMaxSize); - picFile->close(); - delete picFile; - - // Setting is values - isCustomFormat = false; - isLoadedInRAM = true; - } - else - { - QByteArray g5eContent = picFile->read(snapmaticFileMaxSize + 1024); - picFile->close(); - delete picFile; - - // Set Custom Format - isCustomFormat = true; - - // Reading g5e Content - g5eContent.remove(0, 1); - if (g5eContent.left(3) == QByteArray("G5E")) - { - g5eContent.remove(0, 3); - if (g5eContent.left(2).toHex() == QByteArray("1000")) - { - g5eContent.remove(0, 2); - if (g5eContent.left(3) == QByteArray("LEN")) - { - g5eContent.remove(0, 3); - int fileNameLength = g5eContent.left(1).toHex().toInt(); - g5eContent.remove(0, 1); - if (g5eContent.left(3) == QByteArray("FIL")) - { - g5eContent.remove(0, 3); - picFileName = g5eContent.left(fileNameLength); - g5eContent.remove(0, fileNameLength); - if (g5eContent.left(3) == QByteArray("COM")) - { - g5eContent.remove(0, 3); - rawPicContent = qUncompress(g5eContent); - - // Setting is values - isLoadedInRAM = true; - } - else - { - lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",4,G5E_FORMATERROR"; - return false; - } - } - else - { - lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",3,G5E_FORMATERROR"; - return false; - } - } - else - { - lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",2,G5E_FORMATERROR"; - return false; - } - } - else - { - lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",1,G5E_NOTCOMPATIBLE"; - return false; - } - } - else - { - lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",1,G5E_FORMATERROR"; - return false; - } - } - emit preloaded(); - return true; -} - -bool SnapmaticPicture::readingPicture(bool writeEnabled_, bool cacheEnabled_, bool fastLoad, bool lowRamMode_) -{ - // Start opening file - // lastStep is like currentStep - - // Set boolean values - writeEnabled = writeEnabled_; - cacheEnabled = cacheEnabled_; - lowRamMode = lowRamMode_; - if (!writeEnabled) { lowRamMode = false; } // Low RAM Mode only works when writeEnabled is true - - QIODevice *picStream; - - if (!isLoadedInRAM) { preloadFile(); } - - picStream = new QBuffer(&rawPicContent); - picStream->open(QIODevice::ReadWrite); - - // Reading Snapmatic Header - if (!picStream->isReadable()) - { - lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",1,NOHEADER"; - picStream->close(); - delete picStream; - return false; - } - QByteArray snapmaticHeaderLine = picStream->read(snapmaticHeaderLength); - pictureHead = getSnapmaticHeaderString(snapmaticHeaderLine); - - // Reading JPEG Header Line - if (!picStream->isReadable()) - { - lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",2,NOHEADER"; - picStream->close(); - delete picStream; - return false; - } - QByteArray jpegHeaderLine = picStream->read(jpegPreHeaderLength); - - // Checking for JPEG - jpegHeaderLine.remove(0, jpegHeaderLineDifStr); - if (jpegHeaderLine.left(4) != QByteArray("JPEG")) - { - lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",2,NOJPEG"; - picStream->close(); - delete picStream; - return false; - } - - // Read JPEG Stream - if (!picStream->isReadable()) - { - lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",2,NOPIC"; - picStream->close(); - delete picStream; - return false; - } - QByteArray jpegRawContent = picStream->read(jpegPicStreamLength); - if (jpegRawContent.contains("\xFF\xD9")) - { - int jpegRawContentSizeT = jpegRawContent.indexOf("\xFF\xD9") + 2; - jpegRawContentSizeE = jpegRawContentSizeT; - jpegRawContentSize = jpegRawContentSizeT; - if (jpegRawContent.contains("\xFF\x45\x4F\x49")) - { - jpegRawContentSizeT = jpegRawContent.indexOf("\xFF\x45\x4F\x49"); - } - jpegRawContent = jpegRawContent.left(jpegRawContentSize); - jpegRawContentSize = jpegRawContentSizeT; - } - if (cacheEnabled) picOk = cachePicture.loadFromData(jpegRawContent, "JPEG"); - if (!cacheEnabled) - { - QImage tempPicture; - picOk = tempPicture.loadFromData(jpegRawContent, "JPEG"); - } - else if (!fastLoad) - { - QImage tempPicture = QImage(snapmaticResolution, QImage::Format_RGB888); - QPainter tempPainter(&tempPicture); - if (cachePicture.size() == snapmaticResolution) - { - tempPainter.drawImage(0, 0, cachePicture); - } - else - { - tempPainter.drawImage(0, 0, cachePicture.scaled(snapmaticResolution, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); - } - tempPainter.end(); - cachePicture = tempPicture; - } - - // Read JSON Stream - if (!picStream->isReadable()) - { - lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",3,NOJSON"; - picStream->close(); - delete picStream; - return false; - } - else if (picStream->read(4) != QByteArray("JSON")) - { - lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",3,CTJSON"; - picStream->close(); - delete picStream; - return false; - } - QByteArray jsonRawContent = picStream->read(jsonStreamLength); - jsonStr = getSnapmaticJSONString(jsonRawContent); - parseJsonContent(); // JSON parsing is own function - - if (!picStream->isReadable()) - { - lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",4,NOTITL"; - picStream->close(); - delete picStream; - return false; - } - else if (picStream->read(4) != QByteArray("TITL")) - { - lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",4,CTTITL"; - picStream->close(); - delete picStream; - return false; - } - QByteArray titlRawContent = picStream->read(tideStreamLength); - titlStr = getSnapmaticTIDEString(titlRawContent); - - if (!picStream->isReadable()) - { - lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",5,NODESC"; - picStream->close(); - delete picStream; - return picOk; - } - else if (picStream->read(4) != QByteArray("DESC")) - { - lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",5,CTDESC"; - picStream->close(); - delete picStream; - return false; - } - QByteArray descRawContent = picStream->read(tideStreamLength); - descStr = getSnapmaticTIDEString(descRawContent); - - updateStrings(); - - picStream->close(); - delete picStream; - - if (!writeEnabled) { rawPicContent.clear(); } - else if (lowRamMode) { rawPicContent = qCompress(rawPicContent, 9); } - - emit loaded(); - return picOk; -} - -QString SnapmaticPicture::getSnapmaticHeaderString(const QByteArray &snapmaticHeader) -{ - QByteArray snapmaticBytes = snapmaticHeader.left(snapmaticUsefulLength); - QList<QByteArray> snapmaticBytesList = snapmaticBytes.split('\x01'); - snapmaticBytes = snapmaticBytesList.at(1); - snapmaticBytesList.clear(); - return StringParser::parseTitleString(snapmaticBytes, snapmaticBytes.length()); -} - -QString SnapmaticPicture::getSnapmaticJSONString(const QByteArray &jsonBytes) -{ - QByteArray jsonUsefulBytes = jsonBytes; - jsonUsefulBytes.replace('\x00', ""); - jsonUsefulBytes.replace('\x0c', ""); - return QString::fromUtf8(jsonUsefulBytes).trimmed(); -} - -QString SnapmaticPicture::getSnapmaticTIDEString(const QByteArray &tideBytes) -{ - QByteArray tideUsefulBytes = tideBytes; - tideUsefulBytes.remove(0,4); - QList<QByteArray> tideUsefulBytesList = tideUsefulBytes.split('\x00'); - return QString::fromUtf8(tideUsefulBytesList.at(0)).trimmed(); -} - -void SnapmaticPicture::updateStrings() -{ - QString cmpPicTitl = titlStr; - cmpPicTitl.replace('\"', "''"); - cmpPicTitl.replace(' ', '_'); - cmpPicTitl.replace(':', '-'); - cmpPicTitl.remove('\\'); - cmpPicTitl.remove('{'); - cmpPicTitl.remove('}'); - cmpPicTitl.remove('/'); - cmpPicTitl.remove('<'); - cmpPicTitl.remove('>'); - cmpPicTitl.remove('*'); - cmpPicTitl.remove('?'); - cmpPicTitl.remove('.'); - pictureStr = tr("PHOTO - %1").arg(localSpJson.createdDateTime.toString("MM/dd/yy HH:mm:ss")); - sortStr = localSpJson.createdDateTime.toString("yyMMddHHmmss") % QString::number(localSpJson.uid); - picExportFileName = sortStr % "_" % cmpPicTitl; -} - -bool SnapmaticPicture::readingPictureFromFile(const QString &fileName, bool writeEnabled_, bool cacheEnabled_, bool fastLoad, bool lowRamMode_) -{ - if (!fileName.isEmpty()) - { - picFilePath = fileName; - return readingPicture(writeEnabled_, cacheEnabled_, fastLoad, lowRamMode_); - } - else - { - return false; - } -} - -bool SnapmaticPicture::setImage(const QImage &picture) // dirty method -{ - if (writeEnabled) - { - QByteArray picByteArray; - int comLvl = 100; - bool saveSuccess = false; - while (comLvl != 0 && !saveSuccess) - { - QByteArray picByteArrayT; - QBuffer picStreamT(&picByteArrayT); - picStreamT.open(QIODevice::WriteOnly); - saveSuccess = picture.save(&picStreamT, "JPEG", comLvl); - picStreamT.close(); - if (saveSuccess) - { - if (picByteArrayT.length() > jpegRawContentSize) - { - comLvl--; - saveSuccess = false; - } - else - { - picByteArray = picByteArrayT; - } - } - } - if (saveSuccess) return setPictureStream(picByteArray); - } - return false; -} - -bool SnapmaticPicture::setPictureStream(const QByteArray &picByteArray_) // clean method -{ - if (writeEnabled) - { - bool customEOI = false; - QByteArray picByteArray = picByteArray_; - if (lowRamMode) { rawPicContent = qUncompress(rawPicContent); } - QBuffer snapmaticStream(&rawPicContent); - snapmaticStream.open(QIODevice::ReadWrite); - if (!snapmaticStream.seek(jpegStreamEditorBegin)) return false; - if (picByteArray.length() > jpegPicStreamLength) return false; - if (picByteArray.length() < jpegRawContentSize && jpegRawContentSize + 4 < jpegPicStreamLength) - { - customEOI = true; - } - while (picByteArray.length() != jpegPicStreamLength) - { - picByteArray += '\x00'; - } - if (customEOI) - { - picByteArray.replace(jpegRawContentSize, 4, "\xFF\x45\x4F\x49"); - } - int result = snapmaticStream.write(picByteArray); - snapmaticStream.close(); - if (result != 0) - { - if (cacheEnabled) - { - QImage replacedPicture; - replacedPicture.loadFromData(picByteArray); - cachePicture = replacedPicture; - } - if (lowRamMode) { rawPicContent = qCompress(rawPicContent, 9); } - return true; - } - if (lowRamMode) { rawPicContent = qCompress(rawPicContent, 9); } - return false; - } - return false; -} - -bool SnapmaticPicture::setPictureTitl(const QString &newTitle_) -{ - if (writeEnabled) - { - QString newTitle = newTitle_; - if (lowRamMode) { rawPicContent = qUncompress(rawPicContent); } - QBuffer snapmaticStream(&rawPicContent); - snapmaticStream.open(QIODevice::ReadWrite); - if (!snapmaticStream.seek(titlStreamEditorBegin)) return false; - if (newTitle.length() > titlStreamCharacterMax) - { - newTitle = newTitle.left(titlStreamCharacterMax); - } - QByteArray newTitleArray = newTitle.toUtf8(); - while (newTitleArray.length() != titlStreamEditorLength) - { - newTitleArray += '\x00'; - } - int result = snapmaticStream.write(newTitleArray); - snapmaticStream.close(); - if (result != 0) - { - titlStr = newTitle; - if (lowRamMode) { rawPicContent = qCompress(rawPicContent, 9); } - return true; - } - if (lowRamMode) { rawPicContent = qCompress(rawPicContent, 9); } - return false; - } - return false; -} - -QString SnapmaticPicture::getExportPictureFileName() -{ - return picExportFileName; -} - -QString SnapmaticPicture::getPictureFileName() -{ - return picFileName; -} - -QString SnapmaticPicture::getPictureFilePath() -{ - return picFilePath; -} - -QString SnapmaticPicture::getPictureSortStr() -{ - return sortStr; -} - -QString SnapmaticPicture::getPictureDesc() -{ - return descStr; -} - -QString SnapmaticPicture::getPictureTitl() -{ - return titlStr; -} - -QString SnapmaticPicture::getPictureHead() -{ - return pictureHead; -} - -QString SnapmaticPicture::getPictureStr() -{ - return pictureStr; -} - -QString SnapmaticPicture::getLastStep() -{ - return lastStep; -} - -QImage SnapmaticPicture::getImage() -{ - if (cacheEnabled) - { - return cachePicture; - } - else if (writeEnabled) - { - bool returnOk = 0; - QImage tempPicture; - QImage returnPicture(snapmaticResolution, QImage::Format_RGB888); - - if (lowRamMode) { rawPicContent = qUncompress(rawPicContent); } - QBuffer snapmaticStream(&rawPicContent); - snapmaticStream.open(QIODevice::ReadOnly); - if (snapmaticStream.seek(jpegStreamEditorBegin)) - { - QByteArray jpegRawContent = snapmaticStream.read(jpegPicStreamLength); - returnOk = tempPicture.loadFromData(jpegRawContent, "JPEG"); - } - snapmaticStream.close(); - if (lowRamMode) { rawPicContent = qCompress(rawPicContent, 9); } - - if (returnOk) - { - QPainter returnPainter(&returnPicture); - if (tempPicture.size() == snapmaticResolution) - { - returnPainter.drawImage(0, 0, tempPicture); - } - else - { - returnPainter.drawImage(0, 0, tempPicture.scaled(snapmaticResolution, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); - } - returnPainter.end(); - return returnPicture; - } - } - else - { - bool returnOk = 0; - QImage returnPicture; - QIODevice *picStream; - - QFile *picFile = new QFile(picFilePath); - if (!picFile->open(QFile::ReadOnly)) - { - lastStep = "1;/1,OpenFile," % StringParser::convertDrawStringForLog(picFilePath); - delete picFile; - return QImage(0, 0, QImage::Format_RGB888); - } - rawPicContent = picFile->read(snapmaticFileMaxSize); - picFile->close(); - delete picFile; - - picStream = new QBuffer(&rawPicContent); - picStream->open(QIODevice::ReadWrite); - if (picStream->seek(jpegStreamEditorBegin)) - { - QByteArray jpegRawContent = picStream->read(jpegPicStreamLength); - returnOk = returnPicture.loadFromData(jpegRawContent, "JPEG"); - } - picStream->close(); - delete picStream; - - if (returnOk) - { - return returnPicture; - } - } - return QImage(0, 0, QImage::Format_RGB888); -} - -int SnapmaticPicture::getContentMaxLength() -{ - return jpegRawContentSize; -} - -bool SnapmaticPicture::isPicOk() -{ - return picOk; -} - -void SnapmaticPicture::clearCache() -{ - cacheEnabled = false; - cachePicture = QImage(); -} - -void SnapmaticPicture::emitUpdate() -{ - emit updated(); -} - -// JSON part - -bool SnapmaticPicture::isJsonOk() -{ - return jsonOk; -} - -QString SnapmaticPicture::getJsonStr() -{ - return jsonStr; -} - -SnapmaticProperties SnapmaticPicture::getSnapmaticProperties() -{ - return localSpJson; -} - -void SnapmaticPicture::parseJsonContent() -{ - QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonStr.toUtf8()); - QJsonObject jsonObject = jsonDocument.object(); - QVariantMap jsonMap = jsonObject.toVariantMap(); // backward compatibility - - if (jsonObject.contains("loc")) - { - QJsonObject locObject = jsonObject["loc"].toObject(); - if (locObject.contains("x")) { localSpJson.location.x = locObject["x"].toDouble(); } - if (locObject.contains("y")) { localSpJson.location.y = locObject["y"].toDouble(); } - if (locObject.contains("z")) { localSpJson.location.z = locObject["z"].toDouble(); } - } - if (jsonObject.contains("uid")) - { - localSpJson.uid = jsonObject["uid"].toInt(); - } - if (jsonObject.contains("area")) - { - localSpJson.location.area = jsonObject["area"].toString(); - } - if (jsonObject.contains("crewid")) - { - localSpJson.crewID = jsonObject["crewid"].toInt(); - } - if (jsonObject.contains("creat")) - { - QDateTime createdTimestamp; - localSpJson.createdTimestamp = jsonMap["creat"].toUInt(); - createdTimestamp.setTime_t(localSpJson.createdTimestamp); - localSpJson.createdDateTime = createdTimestamp; - } - if (jsonObject.contains("plyrs")) - { - localSpJson.playersList = jsonMap["plyrs"].toStringList(); - } - if (jsonObject.contains("meme")) - { - localSpJson.isMeme = jsonObject["meme"].toBool(); - } - if (jsonObject.contains("mug")) - { - localSpJson.isMug = jsonObject["mug"].toBool(); - } - if (jsonObject.contains("slf")) - { - localSpJson.isSelfie = jsonObject["slf"].toBool(); - } - if (jsonObject.contains("drctr")) - { - localSpJson.isFromDirector = jsonObject["drctr"].toBool(); - } - if (jsonObject.contains("rsedtr")) - { - localSpJson.isFromRSEditor = jsonObject["rsedtr"].toBool(); - } - - jsonOk = true; -} - -bool SnapmaticPicture::setSnapmaticProperties(SnapmaticProperties newSpJson) -{ - QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonStr.toUtf8()); - QJsonObject jsonObject = jsonDocument.object(); - - QJsonObject locObject; - locObject["x"] = newSpJson.location.x; - locObject["y"] = newSpJson.location.y; - locObject["z"] = newSpJson.location.z; - - jsonObject["loc"] = locObject; - jsonObject["uid"] = newSpJson.uid; - jsonObject["area"] = newSpJson.location.area; - jsonObject["crewid"] = newSpJson.crewID; - jsonObject["creat"] = QJsonValue::fromVariant(newSpJson.createdTimestamp); - jsonObject["plyrs"] = QJsonValue::fromVariant(newSpJson.playersList); - jsonObject["meme"] = newSpJson.isMeme; - jsonObject["mug"] = newSpJson.isMug; - jsonObject["slf"] = newSpJson.isSelfie; - jsonObject["drctr"] = newSpJson.isFromDirector; - jsonObject["rsedtr"] = newSpJson.isFromRSEditor; - - jsonDocument.setObject(jsonObject); - - QString newJsonStr = QString::fromUtf8(jsonDocument.toJson(QJsonDocument::Compact)); - if (newJsonStr.length() < jsonStreamEditorLength) - { - if (writeEnabled) - { - QByteArray jsonByteArray = newJsonStr.toUtf8(); - while (jsonByteArray.length() != jsonStreamEditorLength) - { - jsonByteArray += '\x00'; - } - if (lowRamMode) { rawPicContent = qUncompress(rawPicContent); } - QBuffer snapmaticStream(&rawPicContent); - snapmaticStream.open(QIODevice::ReadWrite); - if (!snapmaticStream.seek(jsonStreamEditorBegin)) - { - snapmaticStream.close(); - return false; - } - int result = snapmaticStream.write(jsonByteArray); - snapmaticStream.close(); - if (result != 0) - { - localSpJson = newSpJson; - jsonStr = newJsonStr; - if (lowRamMode) { rawPicContent = qCompress(rawPicContent, 9); } - return true; - } - else - { - if (lowRamMode) { rawPicContent = qCompress(rawPicContent, 9); } - return false; - } - } - else - { - return false; - } - } - else - { - return false; - } - - return true; -} - -// FILE MANAGEMENT - -bool SnapmaticPicture::exportPicture(const QString &fileName, const QString format) -{ - QFile *picFile = new QFile(fileName); - if (picFile->open(QIODevice::WriteOnly)) - { - if (format == QLatin1String("G5E")) - { - // Modern compressed export - QByteArray stockFileNameUTF8 = picFileName.toUtf8(); - QByteArray numberLength = QByteArray::number(stockFileNameUTF8.length()); - if (numberLength.length() == 1) - { - numberLength.insert(0, "0"); - } - else if (numberLength.length() != 2) - { - numberLength = "00"; - } - QByteArray g5eHeader; - g5eHeader.reserve(stockFileNameUTF8.length() + 16); - g5eHeader += '\x00'; // First Null Byte - g5eHeader += QByteArray("G5E"); // GTA 5 Export - g5eHeader += '\x10'; g5eHeader += '\x00'; // 2 byte GTA 5 Export Version - g5eHeader += QByteArray("LEN"); // Before Length - g5eHeader += QByteArray::fromHex(numberLength); // Length in HEX before Compressed - g5eHeader += QByteArray("FIL"); // Before File Name - g5eHeader += stockFileNameUTF8; // File Name - g5eHeader += QByteArray("COM"); // Before Compressed - picFile->write(g5eHeader); - if (!lowRamMode) - { - picFile->write(qCompress(rawPicContent, 9)); // Compressed Snapmatic - } - else - { - picFile->write(rawPicContent); - } - picFile->close(); - delete picFile; - } - else if (format == QLatin1String("JPG")) - { - // JPEG export - QBuffer snapmaticStream(&rawPicContent); - snapmaticStream.open(QIODevice::ReadOnly); - if (snapmaticStream.seek(jpegStreamEditorBegin)) - { - QByteArray jpegRawContent = snapmaticStream.read(jpegPicStreamLength); - if (jpegRawContentSizeE != 0) - { - jpegRawContent = jpegRawContent.left(jpegRawContentSizeE); - } - picFile->write(jpegRawContent); - } - picFile->close(); - delete picFile; - } - else - { - // Classic straight export - if (!lowRamMode) - { - picFile->write(rawPicContent); - } - else - { - picFile->write(qUncompress(rawPicContent)); - } - picFile->close(); - delete picFile; - } - return true; - } - else - { - delete picFile; - return false; - } -} - -void SnapmaticPicture::setPicFileName(const QString &picFileName_) -{ - picFileName = picFileName_; -} - -void SnapmaticPicture::setPicFilePath(const QString &picFilePath_) -{ - picFilePath = picFilePath_; -} - -bool SnapmaticPicture::deletePicFile() -{ - if (!QFile::exists(picFilePath)) return true; - if (QFile::remove(picFilePath)) return true; - return false; -} - -// VISIBILITY - -bool SnapmaticPicture::isHidden() -{ - if (picFilePath.right(7) == QLatin1String(".hidden")) - { - return true; - } - return false; -} - -bool SnapmaticPicture::setPictureHidden() -{ - if (isCustomFormat) - { - return false; - } - if (!isHidden()) - { - QString newPicFilePath = QString(picFilePath % ".hidden"); - if (QFile::rename(picFilePath, newPicFilePath)) - { - picFilePath = newPicFilePath; - return true; - } - return false; - } - return true; -} - -bool SnapmaticPicture::setPictureVisible() -{ - if (isCustomFormat) - { - return false; - } - if (isHidden()) - { - QString newPicFilePath = QString(picFilePath).remove(picFilePath.length() - 7, 7); - if (QFile::rename(picFilePath, newPicFilePath)) - { - picFilePath = newPicFilePath; - return true; - } - return false; - } - return true; -} - -// PREDEFINED PROPERTIES - -QSize SnapmaticPicture::getSnapmaticResolution() -{ - return snapmaticResolution; -} - -// VERIFY CONTENT - -bool SnapmaticPicture::verifyTitle(const QString &title) -{ - // VERIFY TITLE FOR BE A VALID SNAPMATIC TITLE - if (title.length() <= titlStreamCharacterMax) - { - foreach(const QChar &titleChar, title) - { - if (!verifyTitleChar(titleChar)) return false; - } - return true; - } - return false; -} - -bool SnapmaticPicture::verifyTitleChar(const QChar &titleChar) -{ - // VERIFY CHAR FOR BE A VALID SNAPMATIC CHARACTER - if (titleChar.isLetterOrNumber() || titleChar.isPrint()) - { - if (titleChar == '<' || titleChar == '>' || titleChar == '\\') return false; - return true; - } - return false; -} +/***************************************************************************** +* gta5sync-spv Grand Theft Auto Snapmatic Picture Viewer +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "SnapmaticPicture.h" +#include "StringParser.h" +#include <QStringBuilder> +#include <QJsonDocument> +#include <QJsonObject> +#include <QStringList> +#include <QVariantMap> +#include <QJsonArray> +#include <QFileInfo> +#include <QPainter> +#include <QString> +#include <QBuffer> +#include <QDebug> +#include <QImage> +#include <QSize> +#include <QFile> + +// PARSER ALLOCATIONS +#define snapmaticHeaderLength 278 +#define snapmaticUsefulLength 260 +#define snapmaticFileMaxSize 528192 +#define jpegHeaderLineDifStr 2 +#define jpegPreHeaderLength 14 +#define jpegPicStreamLength 524288 +#define jsonStreamLength 3076 +#define tideStreamLength 260 + +// EDITOR ALLOCATIONS +#define jpegStreamEditorBegin 292 +#define jsonStreamEditorBegin 524588 +#define jsonStreamEditorLength 3072 +#define titlStreamEditorBegin 527668 +#define titlStreamEditorLength 256 +#define titlStreamCharacterMax 39 + +// IMAGES VALUES +#define snapmaticResolutionW 960 +#define snapmaticResolutionH 536 +#define snapmaticResolution QSize(snapmaticResolutionW, snapmaticResolutionH) + +SnapmaticPicture::SnapmaticPicture(const QString &fileName, QObject *parent) : QObject(parent), picFilePath(fileName) +{ + reset(); +} + +SnapmaticPicture::~SnapmaticPicture() +{ +} + +void SnapmaticPicture::reset() +{ + // INIT PIC + rawPicContent.clear(); + rawPicContent.squeeze(); + cachePicture = QImage(); + picExportFileName = QString(); + pictureHead = QString(); + pictureStr = QString(); + lastStep = QString(); + sortStr = QString(); + titlStr = QString(); + descStr = QString(); + + // INIT PIC INTS + jpegRawContentSizeE = 0; + jpegRawContentSize = 0; + + // INIT PIC BOOLS + isCustomFormat = false; + isLoadedInRAM = false; + lowRamMode = false; + picOk = false; + + // INIT JSON + jsonOk = false; + jsonStr = QString(); + + // SNAPMATIC DEFAULTS +#ifdef GTA5SYNC_CSDF + careSnapDefault = false; +#else + careSnapDefault = true; +#endif + + // SNAPMATIC PROPERTIES + localSpJson = {}; +} + +bool SnapmaticPicture::preloadFile() +{ + QFile *picFile = new QFile(picFilePath); + picFileName = QFileInfo(picFilePath).fileName(); + + if (!picFile->open(QFile::ReadOnly)) + { + lastStep = "1;/1,OpenFile," % StringParser::convertDrawStringForLog(picFilePath); + delete picFile; + return false; + } + if (picFilePath.right(4) != QLatin1String(".g5e")) + { + rawPicContent = picFile->read(snapmaticFileMaxSize); + picFile->close(); + delete picFile; + + // Setting is values + isCustomFormat = false; + isLoadedInRAM = true; + } + else + { + QByteArray g5eContent = picFile->read(snapmaticFileMaxSize + 1024); + picFile->close(); + delete picFile; + + // Set Custom Format + isCustomFormat = true; + + // Reading g5e Content + g5eContent.remove(0, 1); + if (g5eContent.left(3) == QByteArray("G5E")) + { + g5eContent.remove(0, 3); + if (g5eContent.left(2).toHex() == QByteArray("1000")) + { + g5eContent.remove(0, 2); + if (g5eContent.left(3) == QByteArray("LEN")) + { + g5eContent.remove(0, 3); + int fileNameLength = g5eContent.left(1).toHex().toInt(); + g5eContent.remove(0, 1); + if (g5eContent.left(3) == QByteArray("FIL")) + { + g5eContent.remove(0, 3); + picFileName = g5eContent.left(fileNameLength); + g5eContent.remove(0, fileNameLength); + if (g5eContent.left(3) == QByteArray("COM")) + { + g5eContent.remove(0, 3); + rawPicContent = qUncompress(g5eContent); + + // Setting is values + isLoadedInRAM = true; + } + else + { + lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",4,G5E_FORMATERROR"; + return false; + } + } + else + { + lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",3,G5E_FORMATERROR"; + return false; + } + } + else + { + lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",2,G5E_FORMATERROR"; + return false; + } + } + else + { + lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",1,G5E_NOTCOMPATIBLE"; + return false; + } + } + else + { + lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",1,G5E_FORMATERROR"; + return false; + } + } + emit preloaded(); + return true; +} + +bool SnapmaticPicture::readingPicture(bool writeEnabled_, bool cacheEnabled_, bool fastLoad, bool lowRamMode_) +{ + // Start opening file + // lastStep is like currentStep + + // Set boolean values + writeEnabled = writeEnabled_; + cacheEnabled = cacheEnabled_; + lowRamMode = lowRamMode_; + if (!writeEnabled) { lowRamMode = false; } // Low RAM Mode only works when writeEnabled is true + + QIODevice *picStream; + + if (!isLoadedInRAM) { preloadFile(); } + + picStream = new QBuffer(&rawPicContent); + picStream->open(QIODevice::ReadWrite); + + // Reading Snapmatic Header + if (!picStream->isReadable()) + { + lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",1,NOHEADER"; + picStream->close(); + delete picStream; + return false; + } + QByteArray snapmaticHeaderLine = picStream->read(snapmaticHeaderLength); + pictureHead = getSnapmaticHeaderString(snapmaticHeaderLine); + if (pictureHead == QLatin1String("MALFORMED")) + { + lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",1,MALFORMEDHEADER"; + picStream->close(); + delete picStream; + return false; + } + + // Reading JPEG Header Line + if (!picStream->isReadable()) + { + lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",2,NOHEADER"; + picStream->close(); + delete picStream; + return false; + } + QByteArray jpegHeaderLine = picStream->read(jpegPreHeaderLength); + + // Checking for JPEG + jpegHeaderLine.remove(0, jpegHeaderLineDifStr); + if (jpegHeaderLine.left(4) != QByteArray("JPEG")) + { + lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",2,NOJPEG"; + picStream->close(); + delete picStream; + return false; + } + + // Read JPEG Stream + if (!picStream->isReadable()) + { + lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",2,NOPIC"; + picStream->close(); + delete picStream; + return false; + } + QByteArray jpegRawContent = picStream->read(jpegPicStreamLength); + if (jpegRawContent.contains("\xFF\xD9")) + { + int jpegRawContentSizeT = jpegRawContent.indexOf("\xFF\xD9") + 2; + jpegRawContentSizeE = jpegRawContentSizeT; + jpegRawContentSize = jpegRawContentSizeT; + if (jpegRawContent.contains("\xFF\x45\x4F\x49")) + { + jpegRawContentSizeT = jpegRawContent.indexOf("\xFF\x45\x4F\x49"); + } + jpegRawContent = jpegRawContent.left(jpegRawContentSize); + jpegRawContentSize = jpegRawContentSizeT; + } + if (cacheEnabled) picOk = cachePicture.loadFromData(jpegRawContent, "JPEG"); + if (!cacheEnabled) + { + QImage tempPicture; + picOk = tempPicture.loadFromData(jpegRawContent, "JPEG"); + } + else if (!fastLoad) + { + if (careSnapDefault) + { + QImage tempPicture = QImage(snapmaticResolution, QImage::Format_RGB888); + QPainter tempPainter(&tempPicture); + if (cachePicture.size() != snapmaticResolution) + { + tempPainter.drawImage(0, 0, cachePicture.scaled(snapmaticResolution, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + } + else + { + tempPainter.drawImage(0, 0, cachePicture); + } + tempPainter.end(); + cachePicture = tempPicture; + } + else + { + QImage tempPicture = QImage(cachePicture.size(), QImage::Format_RGB888); + QPainter tempPainter(&tempPicture); + tempPainter.drawImage(0, 0, cachePicture); + tempPainter.end(); + cachePicture = tempPicture; + } + } + + // Read JSON Stream + if (!picStream->isReadable()) + { + lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",3,NOJSON"; + picStream->close(); + delete picStream; + return false; + } + else if (picStream->read(4) != QByteArray("JSON")) + { + lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",3,CTJSON"; + picStream->close(); + delete picStream; + return false; + } + QByteArray jsonRawContent = picStream->read(jsonStreamLength); + jsonStr = getSnapmaticJSONString(jsonRawContent); + parseJsonContent(); // JSON parsing is own function + + if (!picStream->isReadable()) + { + lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",4,NOTITL"; + picStream->close(); + delete picStream; + return false; + } + else if (picStream->read(4) != QByteArray("TITL")) + { + lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",4,CTTITL"; + picStream->close(); + delete picStream; + return false; + } + QByteArray titlRawContent = picStream->read(tideStreamLength); + titlStr = getSnapmaticTIDEString(titlRawContent); + + if (!picStream->isReadable()) + { + lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",5,NODESC"; + picStream->close(); + delete picStream; + return picOk; + } + else if (picStream->read(4) != QByteArray("DESC")) + { + lastStep = "2;/3,ReadingFile," % StringParser::convertDrawStringForLog(picFilePath) % ",5,CTDESC"; + picStream->close(); + delete picStream; + return false; + } + QByteArray descRawContent = picStream->read(tideStreamLength); + descStr = getSnapmaticTIDEString(descRawContent); + + updateStrings(); + + picStream->close(); + delete picStream; + + if (!writeEnabled) { rawPicContent.clear(); } + else if (lowRamMode) { rawPicContent = qCompress(rawPicContent, 9); } + + emit loaded(); + return picOk; +} + +QString SnapmaticPicture::getSnapmaticHeaderString(const QByteArray &snapmaticHeader) +{ + QList<QByteArray> snapmaticBytesList = snapmaticHeader.left(snapmaticUsefulLength).split('\x01'); + if (snapmaticBytesList.length() < 2) { return QLatin1String("MALFORMED"); } + QByteArray snapmaticBytes = snapmaticBytesList.at(1); + return StringParser::parseTitleString(snapmaticBytes, snapmaticBytes.length()); +} + +QString SnapmaticPicture::getSnapmaticJSONString(const QByteArray &jsonBytes) +{ + QByteArray jsonUsefulBytes = jsonBytes; + jsonUsefulBytes.replace('\x00', QString()); + jsonUsefulBytes.replace('\x0c', QString()); + return QString::fromUtf8(jsonUsefulBytes.trimmed()); +} + +QString SnapmaticPicture::getSnapmaticTIDEString(const QByteArray &tideBytes) +{ + QByteArray tideUsefulBytes = tideBytes; + tideUsefulBytes.remove(0,4); + QList<QByteArray> tideUsefulBytesList = tideUsefulBytes.split('\x00'); + return QString::fromUtf8(tideUsefulBytesList.at(0).trimmed()); +} + +void SnapmaticPicture::updateStrings() +{ + QString cmpPicTitl = titlStr; + cmpPicTitl.replace('\"', "''"); + cmpPicTitl.replace(' ', '_'); + cmpPicTitl.replace(':', '-'); + cmpPicTitl.remove('\\'); + cmpPicTitl.remove('{'); + cmpPicTitl.remove('}'); + cmpPicTitl.remove('/'); + cmpPicTitl.remove('<'); + cmpPicTitl.remove('>'); + cmpPicTitl.remove('*'); + cmpPicTitl.remove('?'); + cmpPicTitl.remove('.'); + pictureStr = tr("PHOTO - %1").arg(localSpJson.createdDateTime.toString("MM/dd/yy HH:mm:ss")); + sortStr = localSpJson.createdDateTime.toString("yyMMddHHmmss") % QString::number(localSpJson.uid); + QString exportStr = localSpJson.createdDateTime.toString("yyyyMMdd") % "-" % QString::number(localSpJson.uid); + picExportFileName = exportStr % "_" % cmpPicTitl; +} + +bool SnapmaticPicture::readingPictureFromFile(const QString &fileName, bool writeEnabled_, bool cacheEnabled_, bool fastLoad, bool lowRamMode_) +{ + if (!fileName.isEmpty()) + { + picFilePath = fileName; + return readingPicture(writeEnabled_, cacheEnabled_, fastLoad, lowRamMode_); + } + else + { + return false; + } +} + +bool SnapmaticPicture::setImage(const QImage &picture) +{ + if (writeEnabled) + { + QImage altPicture; + bool useAltPicture = false; + if (picture.size() != snapmaticResolution && careSnapDefault) + { + altPicture = picture.scaled(snapmaticResolution, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + useAltPicture = true; + } + QByteArray picByteArray; + int comLvl = 100; + bool saveSuccess = false; + while (comLvl != 0 && !saveSuccess) + { + QByteArray picByteArrayT; + QBuffer picStreamT(&picByteArrayT); + picStreamT.open(QIODevice::WriteOnly); + if (useAltPicture) { saveSuccess = altPicture.save(&picStreamT, "JPEG", comLvl); } + else { saveSuccess = picture.save(&picStreamT, "JPEG", comLvl); } + picStreamT.close(); + if (saveSuccess) + { + if (picByteArrayT.length() > jpegRawContentSize) + { + comLvl--; + saveSuccess = false; + } + else + { + picByteArray = picByteArrayT; + } + } + } + if (saveSuccess) { return setPictureStream(picByteArray); } + } + return false; +} + +bool SnapmaticPicture::setPictureStream(const QByteArray &picByteArray_) // clean method +{ + if (writeEnabled) + { + bool customEOI = false; + QByteArray picByteArray = picByteArray_; + if (lowRamMode) { rawPicContent = qUncompress(rawPicContent); } + QBuffer snapmaticStream(&rawPicContent); + snapmaticStream.open(QIODevice::ReadWrite); + if (!snapmaticStream.seek(jpegStreamEditorBegin)) return false; + if (picByteArray.length() > jpegPicStreamLength) return false; + if (picByteArray.length() < jpegRawContentSize && jpegRawContentSize + 4 < jpegPicStreamLength) + { + customEOI = true; + } + while (picByteArray.length() != jpegPicStreamLength) + { + picByteArray += '\x00'; + } + if (customEOI) + { + picByteArray.replace(jpegRawContentSize, 4, "\xFF\x45\x4F\x49"); + } + int result = snapmaticStream.write(picByteArray); + snapmaticStream.close(); + if (result != 0) + { + if (cacheEnabled) + { + QImage replacedPicture; + replacedPicture.loadFromData(picByteArray); + cachePicture = replacedPicture; + } + if (lowRamMode) { rawPicContent = qCompress(rawPicContent, 9); } + return true; + } + if (lowRamMode) { rawPicContent = qCompress(rawPicContent, 9); } + return false; + } + return false; +} + +bool SnapmaticPicture::setPictureTitl(const QString &newTitle_) +{ + if (writeEnabled) + { + QString newTitle = newTitle_; + if (lowRamMode) { rawPicContent = qUncompress(rawPicContent); } + QBuffer snapmaticStream(&rawPicContent); + snapmaticStream.open(QIODevice::ReadWrite); + if (!snapmaticStream.seek(titlStreamEditorBegin)) return false; + if (newTitle.length() > titlStreamCharacterMax) + { + newTitle = newTitle.left(titlStreamCharacterMax); + } + QByteArray newTitleArray = newTitle.toUtf8(); + while (newTitleArray.length() != titlStreamEditorLength) + { + newTitleArray += '\x00'; + } + int result = snapmaticStream.write(newTitleArray); + snapmaticStream.close(); + if (result != 0) + { + titlStr = newTitle; + if (lowRamMode) { rawPicContent = qCompress(rawPicContent, 9); } + return true; + } + if (lowRamMode) { rawPicContent = qCompress(rawPicContent, 9); } + return false; + } + return false; +} + +QString SnapmaticPicture::getExportPictureFileName() +{ + return picExportFileName; +} + +QString SnapmaticPicture::getPictureFileName() +{ + return picFileName; +} + +QString SnapmaticPicture::getPictureFilePath() +{ + return picFilePath; +} + +QString SnapmaticPicture::getPictureSortStr() +{ + return sortStr; +} + +QString SnapmaticPicture::getPictureDesc() +{ + return descStr; +} + +QString SnapmaticPicture::getPictureTitl() +{ + return titlStr; +} + +QString SnapmaticPicture::getPictureHead() +{ + return pictureHead; +} + +QString SnapmaticPicture::getPictureStr() +{ + return pictureStr; +} + +QString SnapmaticPicture::getLastStep() +{ + return lastStep; +} + +QImage SnapmaticPicture::getImage(bool fastLoad) +{ + if (cacheEnabled) + { + return cachePicture; + } + else if (writeEnabled) + { + bool fastLoadU = fastLoad; + if (!careSnapDefault) { fastLoadU = true; } + + bool returnOk = false; + QImage tempPicture; + QImage returnPicture; + if (!fastLoadU) + { + returnPicture = QImage(snapmaticResolution, QImage::Format_RGB888); + } + + if (lowRamMode) { rawPicContent = qUncompress(rawPicContent); } + QBuffer snapmaticStream(&rawPicContent); + snapmaticStream.open(QIODevice::ReadOnly); + if (snapmaticStream.seek(jpegStreamEditorBegin)) + { + QByteArray jpegRawContent = snapmaticStream.read(jpegPicStreamLength); + returnOk = tempPicture.loadFromData(jpegRawContent, "JPEG"); + } + snapmaticStream.close(); + if (lowRamMode) { rawPicContent = qCompress(rawPicContent, 9); } + + if (returnOk) + { + if (!fastLoadU) + { + QPainter returnPainter(&returnPicture); + if (tempPicture.size() != snapmaticResolution) + { + returnPainter.drawImage(0, 0, tempPicture.scaled(snapmaticResolution, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + } + else + { + returnPainter.drawImage(0, 0, tempPicture); + } + returnPainter.end(); + return returnPicture; + } + else + { + return tempPicture; + } + } + } + else + { + bool fastLoadU = fastLoad; + if (!careSnapDefault) { fastLoadU = true; } + + bool returnOk = false; + QImage tempPicture; + QImage returnPicture; + if (!fastLoadU) + { + returnPicture = QImage(snapmaticResolution, QImage::Format_RGB888); + } + QIODevice *picStream; + + QFile *picFile = new QFile(picFilePath); + if (!picFile->open(QFile::ReadOnly)) + { + lastStep = "1;/1,OpenFile," % StringParser::convertDrawStringForLog(picFilePath); + delete picFile; + return QImage(); + } + rawPicContent = picFile->read(snapmaticFileMaxSize); + picFile->close(); + delete picFile; + + picStream = new QBuffer(&rawPicContent); + picStream->open(QIODevice::ReadWrite); + if (picStream->seek(jpegStreamEditorBegin)) + { + QByteArray jpegRawContent = picStream->read(jpegPicStreamLength); + returnOk = tempPicture.loadFromData(jpegRawContent, "JPEG"); + } + picStream->close(); + delete picStream; + + if (returnOk) + { + if (!fastLoadU) + { + QPainter returnPainter(&returnPicture); + if (tempPicture.size() != snapmaticResolution) + { + returnPainter.drawImage(0, 0, tempPicture.scaled(snapmaticResolution, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + } + else + { + returnPainter.drawImage(0, 0, tempPicture); + } + returnPainter.end(); + return returnPicture; + } + else + { + return tempPicture; + } + } + } + return QImage(); +} + +int SnapmaticPicture::getContentMaxLength() +{ + return jpegRawContentSize; +} + +bool SnapmaticPicture::isPicOk() +{ + return picOk; +} + +void SnapmaticPicture::clearCache() +{ + cacheEnabled = false; + cachePicture = QImage(); +} + +void SnapmaticPicture::emitUpdate() +{ + emit updated(); +} + +// JSON part + +bool SnapmaticPicture::isJsonOk() +{ + return jsonOk; +} + +QString SnapmaticPicture::getJsonStr() +{ + return jsonStr; +} + +SnapmaticProperties SnapmaticPicture::getSnapmaticProperties() +{ + return localSpJson; +} + +void SnapmaticPicture::parseJsonContent() +{ + QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonStr.toUtf8()); + QJsonObject jsonObject = jsonDocument.object(); + QVariantMap jsonMap = jsonObject.toVariantMap(); // backward compatibility + + if (jsonObject.contains("loc")) + { + QJsonObject locObject = jsonObject["loc"].toObject(); + if (locObject.contains("x")) { localSpJson.location.x = locObject["x"].toDouble(); } + if (locObject.contains("y")) { localSpJson.location.y = locObject["y"].toDouble(); } + if (locObject.contains("z")) { localSpJson.location.z = locObject["z"].toDouble(); } + } + if (jsonObject.contains("uid")) + { + localSpJson.uid = jsonObject["uid"].toInt(); + } + if (jsonObject.contains("area")) + { + localSpJson.location.area = jsonObject["area"].toString(); + } + if (jsonObject.contains("crewid")) + { + localSpJson.crewID = jsonObject["crewid"].toInt(); + } + if (jsonObject.contains("creat")) + { + QDateTime createdTimestamp; + localSpJson.createdTimestamp = jsonMap["creat"].toUInt(); + createdTimestamp.setTime_t(localSpJson.createdTimestamp); + localSpJson.createdDateTime = createdTimestamp; + } + if (jsonObject.contains("plyrs")) + { + localSpJson.playersList = jsonMap["plyrs"].toStringList(); + } + if (jsonObject.contains("meme")) + { + localSpJson.isMeme = jsonObject["meme"].toBool(); + } + if (jsonObject.contains("mug")) + { + localSpJson.isMug = jsonObject["mug"].toBool(); + } + if (jsonObject.contains("slf")) + { + localSpJson.isSelfie = jsonObject["slf"].toBool(); + } + if (jsonObject.contains("drctr")) + { + localSpJson.isFromDirector = jsonObject["drctr"].toBool(); + } + if (jsonObject.contains("rsedtr")) + { + localSpJson.isFromRSEditor = jsonObject["rsedtr"].toBool(); + } + + jsonOk = true; +} + +bool SnapmaticPicture::setSnapmaticProperties(SnapmaticProperties newSpJson) +{ + QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonStr.toUtf8()); + QJsonObject jsonObject = jsonDocument.object(); + + QJsonObject locObject; + locObject["x"] = newSpJson.location.x; + locObject["y"] = newSpJson.location.y; + locObject["z"] = newSpJson.location.z; + + jsonObject["loc"] = locObject; + jsonObject["uid"] = newSpJson.uid; + jsonObject["area"] = newSpJson.location.area; + jsonObject["crewid"] = newSpJson.crewID; + jsonObject["creat"] = QJsonValue::fromVariant(newSpJson.createdTimestamp); + jsonObject["plyrs"] = QJsonValue::fromVariant(newSpJson.playersList); + jsonObject["meme"] = newSpJson.isMeme; + jsonObject["mug"] = newSpJson.isMug; + jsonObject["slf"] = newSpJson.isSelfie; + jsonObject["drctr"] = newSpJson.isFromDirector; + jsonObject["rsedtr"] = newSpJson.isFromRSEditor; + + jsonDocument.setObject(jsonObject); + + if (setJsonStr(QString::fromUtf8(jsonDocument.toJson(QJsonDocument::Compact)))) + { + localSpJson = newSpJson; + return true; + } + return false; +} + +bool SnapmaticPicture::setJsonStr(const QString &newJsonStr) +{ + if (newJsonStr.length() < jsonStreamEditorLength) + { + if (writeEnabled) + { + QByteArray jsonByteArray = newJsonStr.toUtf8(); + while (jsonByteArray.length() != jsonStreamEditorLength) + { + jsonByteArray += '\x00'; + } + if (lowRamMode) { rawPicContent = qUncompress(rawPicContent); } + QBuffer snapmaticStream(&rawPicContent); + snapmaticStream.open(QIODevice::ReadWrite); + if (!snapmaticStream.seek(jsonStreamEditorBegin)) + { + snapmaticStream.close(); + return false; + } + int result = snapmaticStream.write(jsonByteArray); + snapmaticStream.close(); + if (result != 0) + { + jsonStr = newJsonStr; + if (lowRamMode) { rawPicContent = qCompress(rawPicContent, 9); } + return true; + } + else + { + if (lowRamMode) { rawPicContent = qCompress(rawPicContent, 9); } + return false; + } + } + else + { + return false; + } + } + return false; +} + +// FILE MANAGEMENT + +bool SnapmaticPicture::exportPicture(const QString &fileName, SnapmaticFormat format_) +{ + // Keep current format when Auto_Format is used + SnapmaticFormat format = format_; + if (format_ == SnapmaticFormat::Auto_Format) + { + if (isCustomFormat) + { + format = SnapmaticFormat::G5E_Format; + } + else + { + format = SnapmaticFormat::PGTA_Format; + } + } + + QFile *picFile = new QFile(fileName); + if (picFile->open(QIODevice::WriteOnly)) + { + if (format == SnapmaticFormat::G5E_Format) + { + // Modern compressed export + QByteArray stockFileNameUTF8 = picFileName.toUtf8(); + QByteArray numberLength = QByteArray::number(stockFileNameUTF8.length()); + if (numberLength.length() == 1) + { + numberLength.insert(0, '0'); + } + else if (numberLength.length() != 2) + { + numberLength = "00"; + } + QByteArray g5eHeader; + g5eHeader.reserve(stockFileNameUTF8.length() + 16); + g5eHeader += '\x00'; // First Null Byte + g5eHeader += QByteArray("G5E"); // GTA 5 Export + g5eHeader += '\x10'; g5eHeader += '\x00'; // 2 byte GTA 5 Export Version + g5eHeader += QByteArray("LEN"); // Before Length + g5eHeader += QByteArray::fromHex(numberLength); // Length in HEX before Compressed + g5eHeader += QByteArray("FIL"); // Before File Name + g5eHeader += stockFileNameUTF8; // File Name + g5eHeader += QByteArray("COM"); // Before Compressed + picFile->write(g5eHeader); + if (!lowRamMode) + { + picFile->write(qCompress(rawPicContent, 9)); // Compressed Snapmatic + } + else + { + picFile->write(rawPicContent); + } + picFile->close(); + delete picFile; + } + else if (format == SnapmaticFormat::JPEG_Format) + { + // JPEG export + QBuffer snapmaticStream(&rawPicContent); + snapmaticStream.open(QIODevice::ReadOnly); + if (snapmaticStream.seek(jpegStreamEditorBegin)) + { + QByteArray jpegRawContent = snapmaticStream.read(jpegPicStreamLength); + if (jpegRawContentSizeE != 0) + { + jpegRawContent = jpegRawContent.left(jpegRawContentSizeE); + } + picFile->write(jpegRawContent); + } + picFile->close(); + delete picFile; + } + else + { + // Classic straight export + if (!lowRamMode) + { + picFile->write(rawPicContent); + } + else + { + picFile->write(qUncompress(rawPicContent)); + } + picFile->close(); + delete picFile; + } + return true; + } + else + { + delete picFile; + return false; + } +} + +void SnapmaticPicture::setPicFileName(const QString &picFileName_) +{ + picFileName = picFileName_; +} + +void SnapmaticPicture::setPicFilePath(const QString &picFilePath_) +{ + picFilePath = picFilePath_; +} + +bool SnapmaticPicture::deletePicFile() +{ + if (!QFile::exists(picFilePath)) return true; + if (QFile::remove(picFilePath)) return true; + return false; +} + +// VISIBILITY + +bool SnapmaticPicture::isHidden() +{ + if (picFilePath.right(7) == QLatin1String(".hidden")) + { + return true; + } + return false; +} + +bool SnapmaticPicture::setPictureHidden() +{ + if (isCustomFormat) + { + return false; + } + if (!isHidden()) + { + QString newPicFilePath = QString(picFilePath % ".hidden"); + if (QFile::rename(picFilePath, newPicFilePath)) + { + picFilePath = newPicFilePath; + return true; + } + return false; + } + return true; +} + +bool SnapmaticPicture::setPictureVisible() +{ + if (isCustomFormat) + { + return false; + } + if (isHidden()) + { + QString newPicFilePath = QString(picFilePath).remove(picFilePath.length() - 7, 7); + if (QFile::rename(picFilePath, newPicFilePath)) + { + picFilePath = newPicFilePath; + return true; + } + return false; + } + return true; +} + +// PREDEFINED PROPERTIES + +QSize SnapmaticPicture::getSnapmaticResolution() +{ + return snapmaticResolution; +} + +// SNAPMATIC DEFAULTS + +bool SnapmaticPicture::isSnapmaticDefaultsEnforced() +{ + return careSnapDefault; +} + +void SnapmaticPicture::setSnapmaticDefaultsEnforced(bool enforced) +{ + careSnapDefault = enforced; +} + +// VERIFY CONTENT + +bool SnapmaticPicture::verifyTitle(const QString &title) +{ + // VERIFY TITLE FOR BE A VALID SNAPMATIC TITLE + if (title.length() <= titlStreamCharacterMax) + { + foreach(const QChar &titleChar, title) + { + if (!verifyTitleChar(titleChar)) return false; + } + return true; + } + return false; +} + +bool SnapmaticPicture::verifyTitleChar(const QChar &titleChar) +{ + // VERIFY CHAR FOR BE A VALID SNAPMATIC CHARACTER + if (titleChar.isLetterOrNumber() || titleChar.isPrint()) + { + if (titleChar == '<' || titleChar == '>' || titleChar == '\\') return false; + return true; + } + return false; +} diff --git a/SnapmaticPicture.h b/SnapmaticPicture.h index ab0ba00..706dc3b 100755 --- a/SnapmaticPicture.h +++ b/SnapmaticPicture.h @@ -1,150 +1,158 @@ -/***************************************************************************** -* gta5sync-spv Grand Theft Auto Snapmatic Picture Viewer -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef SNAPMATICPICTURE_H -#define SNAPMATICPICTURE_H - -#include <QStringList> -#include <QDateTime> -#include <QObject> -#include <QString> -#include <QImage> -#include <QFile> - -struct SnapmaticProperties { - struct SnapmaticLocation { - QString area; - double x; - double y; - double z; - }; - int uid; - int crewID; - QStringList playersList; - uint createdTimestamp; - QDateTime createdDateTime; - bool isMeme; - bool isMug; - bool isSelfie; - bool isFromDirector; - bool isFromRSEditor; - SnapmaticLocation location; -}; - -class SnapmaticPicture : public QObject -{ - Q_OBJECT -public: - explicit SnapmaticPicture(const QString &fileName = "", QObject *parent = 0); - ~SnapmaticPicture(); - void reset(); - bool preloadFile(); - bool readingPictureFromFile(const QString &fileName, bool writeEnabled = true, bool cacheEnabled = false, bool fastLoad = true, bool lowRamMode = false); - bool readingPicture(bool writeEnabled = true, bool cacheEnabled = false, bool fastLoad = true, bool lowRamMode = false); - bool isPicOk(); - void clearCache(); - QImage getImage(); - QString getLastStep(); - QString getPictureStr(); - QString getPictureHead(); - QString getPictureTitl(); - QString getPictureDesc(); - QString getPictureSortStr(); - QString getPictureFileName(); - QString getPictureFilePath(); - QString getExportPictureFileName(); - int getContentMaxLength(); - bool setImage(const QImage &picture); - bool setPictureTitl(const QString &newTitle); - bool setPictureStream(const QByteArray &picByteArray); - void updateStrings(); - void emitUpdate(); - - // FILE MANAGEMENT - bool exportPicture(const QString &fileName, const QString format = "PGTA"); - void setPicFileName(const QString &picFileName); - void setPicFilePath(const QString &picFilePath); - bool deletePicFile(); - - // ALTERNATIVES - QString getPictureTitle() { return getPictureTitl(); } - QString getPictureString() { return getPictureStr(); } - QString getPictureDescription() { return getPictureDesc(); } - bool setPictureTitle(const QString &newTitle) { return setPictureTitl(newTitle); } - - // JSON - bool isJsonOk(); - QString getJsonStr(); - SnapmaticProperties getSnapmaticProperties(); - bool setSnapmaticProperties(SnapmaticProperties newSpJson); - - // VISIBILITY - bool isHidden(); - bool setPictureHidden(); - bool setPictureVisible(); - - // PREDEFINED PROPERTIES - QSize getSnapmaticResolution(); - - // VERIFY CONTENT - static bool verifyTitle(const QString &title); - -private: - QString getSnapmaticHeaderString(const QByteArray &snapmaticHeader); - QString getSnapmaticJSONString(const QByteArray &jsonBytes); - QString getSnapmaticTIDEString(const QByteArray &tideBytes); - QImage cachePicture; - QString picExportFileName; - QString picFileName; - QString picFilePath; - QString pictureHead; - QString pictureStr; - QString lastStep; - QString sortStr; - QString titlStr; - QString descStr; - bool picOk; - bool lowRamMode; - bool writeEnabled; - bool cacheEnabled; - bool isLoadedInRAM; - bool isCustomFormat; - int jpegRawContentSize; - int jpegRawContentSizeE; - - // PICTURE STREAM - QByteArray rawPicContent; - - // JSON - void parseJsonContent(); - bool jsonOk; - QString jsonStr; - SnapmaticProperties localSpJson; - - // VERIFY CONTENT - static bool verifyTitleChar(const QChar &titleChar); - -signals: - void preloaded(); - void updated(); - void loaded(); - -public slots: -}; - -#endif // SNAPMATICPICTURE_H +/***************************************************************************** +* gta5sync-spv Grand Theft Auto Snapmatic Picture Viewer +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef SNAPMATICPICTURE_H +#define SNAPMATICPICTURE_H + +#include <QStringList> +#include <QDateTime> +#include <QObject> +#include <QString> +#include <QImage> +#include <QFile> + +enum class SnapmaticFormat : int { Auto_Format = 0, PGTA_Format = 1, JPEG_Format = 2, G5E_Format = 3 }; + +struct SnapmaticProperties { + struct SnapmaticLocation { + QString area; + double x; + double y; + double z; + }; + int uid; + int crewID; + QStringList playersList; + uint createdTimestamp; + QDateTime createdDateTime; + bool isMeme; + bool isMug; + bool isSelfie; + bool isFromDirector; + bool isFromRSEditor; + SnapmaticLocation location; +}; + +class SnapmaticPicture : public QObject +{ + Q_OBJECT +public: + explicit SnapmaticPicture(const QString &fileName = "", QObject *parent = 0); + ~SnapmaticPicture(); + void reset(); + bool preloadFile(); + bool readingPictureFromFile(const QString &fileName, bool writeEnabled = true, bool cacheEnabled = false, bool fastLoad = true, bool lowRamMode = false); + bool readingPicture(bool writeEnabled = true, bool cacheEnabled = false, bool fastLoad = true, bool lowRamMode = false); + bool isPicOk(); + void clearCache(); + QImage getImage(bool fastLoad = false); + QString getLastStep(); + QString getPictureStr(); + QString getPictureHead(); + QString getPictureTitl(); + QString getPictureDesc(); + QString getPictureSortStr(); + QString getPictureFileName(); + QString getPictureFilePath(); + QString getExportPictureFileName(); + int getContentMaxLength(); + bool setImage(const QImage &picture); + bool setPictureTitl(const QString &newTitle); + bool setPictureStream(const QByteArray &picByteArray); + void updateStrings(); + void emitUpdate(); + + // FILE MANAGEMENT + bool exportPicture(const QString &fileName, SnapmaticFormat format = SnapmaticFormat::Auto_Format); + void setPicFileName(const QString &picFileName); + void setPicFilePath(const QString &picFilePath); + bool deletePicFile(); + + // ALTERNATIVES + QString getPictureTitle() { return getPictureTitl(); } + QString getPictureString() { return getPictureStr(); } + QString getPictureDescription() { return getPictureDesc(); } + bool setPictureTitle(const QString &newTitle) { return setPictureTitl(newTitle); } + + // JSON + bool isJsonOk(); + QString getJsonStr(); + SnapmaticProperties getSnapmaticProperties(); + bool setSnapmaticProperties(SnapmaticProperties newSpJson); + bool setJsonStr(const QString &jsonStr); + + // VISIBILITY + bool isHidden(); + bool setPictureHidden(); + bool setPictureVisible(); + + // PREDEFINED PROPERTIES + QSize getSnapmaticResolution(); + + // SNAPMATIC DEFAULTS + bool isSnapmaticDefaultsEnforced(); + void setSnapmaticDefaultsEnforced(bool enforced); + + // VERIFY CONTENT + static bool verifyTitle(const QString &title); + +private: + QString getSnapmaticHeaderString(const QByteArray &snapmaticHeader); + QString getSnapmaticJSONString(const QByteArray &jsonBytes); + QString getSnapmaticTIDEString(const QByteArray &tideBytes); + QImage cachePicture; + QString picExportFileName; + QString picFileName; + QString picFilePath; + QString pictureHead; + QString pictureStr; + QString lastStep; + QString sortStr; + QString titlStr; + QString descStr; + bool picOk; + bool lowRamMode; + bool writeEnabled; + bool cacheEnabled; + bool isLoadedInRAM; + bool isCustomFormat; + bool careSnapDefault; + int jpegRawContentSize; + int jpegRawContentSizeE; + + // PICTURE STREAM + QByteArray rawPicContent; + + // JSON + void parseJsonContent(); + bool jsonOk; + QString jsonStr; + SnapmaticProperties localSpJson; + + // VERIFY CONTENT + static bool verifyTitleChar(const QChar &titleChar); + +signals: + void preloaded(); + void updated(); + void loaded(); + +public slots: +}; + +#endif // SNAPMATICPICTURE_H diff --git a/SnapmaticWidget.cpp b/SnapmaticWidget.cpp index ddb9b73..dd5ca98 100755 --- a/SnapmaticWidget.cpp +++ b/SnapmaticWidget.cpp @@ -1,345 +1,331 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "SnapmaticWidget.h" -#include "ui_SnapmaticWidget.h" -#include "SnapmaticPicture.h" -#include "SnapmaticEditor.h" -#include "DatabaseThread.h" -#include "PictureDialog.h" -#include "PictureExport.h" -#include "StringParser.h" -#include "AppEnv.h" -#include "config.h" -#include <QMessageBox> -#include <QPixmap> -#include <QTimer> -#include <QDebug> -#include <QMenu> -#include <QFile> - -SnapmaticWidget::SnapmaticWidget(ProfileDatabase *profileDB, CrewDatabase *crewDB, DatabaseThread *threadDB, QWidget *parent) : - ProfileWidget(parent), profileDB(profileDB), crewDB(crewDB), threadDB(threadDB), - ui(new Ui::SnapmaticWidget) -{ - ui->setupUi(this); - ui->cmdView->setVisible(false); - ui->cmdCopy->setVisible(false); - ui->cmdExport->setVisible(false); - ui->cmdDelete->setVisible(false); - ui->cbSelected->setVisible(false); - - QPalette palette; - highlightBackColor = palette.highlight().color(); - highlightTextColor = palette.highlightedText().color(); - palette.setCurrentColorGroup(QPalette::Disabled); - highlightHiddenColor = palette.text().color(); - - picPath = ""; - picStr = ""; - smpic = 0; - - installEventFilter(this); -} - -SnapmaticWidget::~SnapmaticWidget() -{ - delete ui; -} - -bool SnapmaticWidget::eventFilter(QObject *obj, QEvent *ev) -{ - if (obj == this) - { - if (ev->type() == QEvent::Enter) - { - setStyleSheet(QString("QFrame#SnapmaticFrame{background-color: rgb(%1, %2, %3)}QLabel#labPicStr{color: rgb(%4, %5, %6)}").arg(QString::number(highlightBackColor.red()), QString::number(highlightBackColor.green()), QString::number(highlightBackColor.blue()), QString::number(highlightTextColor.red()), QString::number(highlightTextColor.green()), QString::number(highlightTextColor.blue()))); - return true; - } - else if(ev->type() == QEvent::Leave) - { - setStyleSheet(""); - return true; - } - } - return false; -} - -void SnapmaticWidget::setSnapmaticPicture(SnapmaticPicture *picture) -{ - smpic = picture; - picPath = picture->getPictureFilePath(); - picTitl = picture->getPictureTitl(); - picStr = picture->getPictureStr(); - QObject::connect(picture, SIGNAL(updated()), this, SLOT(snapmaticUpdated())); - - qreal screenRatio = AppEnv::screenRatio(); - ui->labPicture->setFixedSize(48 * screenRatio, 27 * screenRatio); - - QPixmap SnapmaticPixmap = QPixmap::fromImage(picture->getImage().scaled(ui->labPicture->width(), ui->labPicture->height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::AutoColor); - ui->labPicStr->setText(picStr + "\n" + picTitl + ""); - ui->labPicture->setPixmap(SnapmaticPixmap); - - picture->clearCache(); - - adjustTextColor(); -} - -void SnapmaticWidget::snapmaticUpdated() -{ - // Current only strings get updated - picPath = smpic->getPictureFilePath(); - picTitl = smpic->getPictureTitl(); - picStr = smpic->getPictureStr(); - ui->labPicStr->setText(picStr + "\n" + picTitl + ""); -} - -void SnapmaticWidget::on_cmdView_clicked() -{ - QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); - settings.beginGroup("Interface"); - bool navigationBar = settings.value("NavigationBar", false).toBool(); - settings.endGroup(); - - PictureDialog *picDialog = new PictureDialog(profileDB, crewDB, this); - picDialog->setSnapmaticPicture(smpic, true); - picDialog->setModal(true); - - // be ready for playerName updated - QObject::connect(threadDB, SIGNAL(playerNameUpdated()), picDialog, SLOT(playerNameUpdated())); - QObject::connect(picDialog, SIGNAL(nextPictureRequested()), this, SLOT(dialogNextPictureRequested())); - QObject::connect(picDialog, SIGNAL(previousPictureRequested()), this, SLOT(dialogPreviousPictureRequested())); - - // add previous next buttons - if (navigationBar) picDialog->addPreviousNextButtons(); - - // show picture dialog -#ifdef Q_OS_ANDROID - // Android ... - picDialog->showMaximized(); -#else - picDialog->show(); - if (navigationBar) picDialog->stylizeDialog(); - //picDialog->adaptNewDialogSize(); - picDialog->setMinimumSize(picDialog->size()); - picDialog->setMaximumSize(picDialog->size()); -#endif - picDialog->exec(); - delete picDialog; -} - -void SnapmaticWidget::on_cmdCopy_clicked() -{ - PictureExport::exportAsSnapmatic(this, smpic); -} - -void SnapmaticWidget::on_cmdExport_clicked() -{ - PictureExport::exportAsPicture(this, smpic); -} - -void SnapmaticWidget::on_cmdDelete_clicked() -{ - if (deletePicture()) emit pictureDeleted(); -} - -bool SnapmaticWidget::deletePicture() -{ - int uchoice = QMessageBox::question(this, tr("Delete picture"), tr("Are you sure to delete %1 from your Snapmatic pictures?").arg("\""+picStr+"\""), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); - if (uchoice == QMessageBox::Yes) - { - if (smpic->deletePicFile()) - { - return true; - } - else - { - QMessageBox::warning(this, tr("Delete picture"), tr("Failed at deleting %1 from your Snapmatic pictures").arg("\""+picStr+"\"")); - } - } - return false; -} - -void SnapmaticWidget::mousePressEvent(QMouseEvent *ev) -{ - ProfileWidget::mousePressEvent(ev); -} - -void SnapmaticWidget::mouseReleaseEvent(QMouseEvent *ev) -{ - ProfileWidget::mouseReleaseEvent(ev); - if (ui->cbSelected->isVisible()) - { - if (rect().contains(ev->pos()) && ev->button() == Qt::LeftButton) - { - ui->cbSelected->setChecked(!ui->cbSelected->isChecked()); - } - } - else - { - if (getContentMode() == 0 && rect().contains(ev->pos()) && ev->button() == Qt::LeftButton) - { - on_cmdView_clicked(); - } - } -} - -void SnapmaticWidget::mouseDoubleClickEvent(QMouseEvent *ev) -{ - ProfileWidget::mouseDoubleClickEvent(ev); - - if (!ui->cbSelected->isVisible() && getContentMode() == 1 && ev->button() == Qt::LeftButton) - { - on_cmdView_clicked(); - } -} - -void SnapmaticWidget::setSelected(bool isSelected) -{ - ui->cbSelected->setChecked(isSelected); -} - -void SnapmaticWidget::pictureSelected() -{ - setSelected(!ui->cbSelected->isChecked()); -} - -void SnapmaticWidget::contextMenuEvent(QContextMenuEvent *ev) -{ - emit contextMenuTriggered(ev); -} - -void SnapmaticWidget::dialogNextPictureRequested() -{ - emit nextPictureRequested((QWidget*)sender()); -} - -void SnapmaticWidget::dialogPreviousPictureRequested() -{ - emit previousPictureRequested((QWidget*)sender()); -} - -void SnapmaticWidget::on_cbSelected_stateChanged(int arg1) -{ - if (arg1 == Qt::Checked) - { - emit widgetSelected(); - } - else if (arg1 == Qt::Unchecked) - { - emit widgetDeselected(); - } -} - -void SnapmaticWidget::adjustTextColor() -{ - if (isHidden()) - { - ui->labPicStr->setStyleSheet(QString("QLabel{color: rgb(%1, %2, %3);}").arg(QString::number(highlightHiddenColor.red()), QString::number(highlightHiddenColor.green()), QString::number(highlightHiddenColor.blue()))); - } - else - { - ui->labPicStr->setStyleSheet(""); - } -} - -bool SnapmaticWidget::makePictureHidden() -{ - if (smpic->setPictureHidden()) - { - picPath = smpic->getPictureFilePath(); - adjustTextColor(); - return true; - } - return false; -} - -bool SnapmaticWidget::makePictureVisible() -{ - if (smpic->setPictureVisible()) - { - picPath = smpic->getPictureFilePath(); - adjustTextColor(); - return true; - } - return false; -} - -void SnapmaticWidget::makePictureHiddenSlot() -{ - makePictureHidden(); -} - -void SnapmaticWidget::makePictureVisibleSlot() -{ - makePictureVisible(); -} - -void SnapmaticWidget::editSnapmaticProperties() -{ - SnapmaticEditor *snapmaticEditor = new SnapmaticEditor(crewDB, this); - snapmaticEditor->setWindowFlags(snapmaticEditor->windowFlags()^Qt::WindowContextHelpButtonHint); - snapmaticEditor->setSnapmaticPicture(smpic); - snapmaticEditor->setModal(true); - snapmaticEditor->exec(); - delete snapmaticEditor; -} - -bool SnapmaticWidget::isSelected() -{ - return ui->cbSelected->isChecked(); -} - -bool SnapmaticWidget::isHidden() -{ - if (picPath.right(7) == ".hidden") - { - return true; - } - return false; -} - -void SnapmaticWidget::setSelectionMode(bool selectionMode) -{ - ui->cbSelected->setVisible(selectionMode); -} - -void SnapmaticWidget::selectAllWidgets() -{ - emit allWidgetsSelected(); -} - -void SnapmaticWidget::deselectAllWidgets() -{ - emit allWidgetsDeselected(); -} - -SnapmaticPicture* SnapmaticWidget::getPicture() -{ - return smpic; -} - -QString SnapmaticWidget::getPicturePath() -{ - return picPath; -} - -QString SnapmaticWidget::getWidgetType() -{ - return "SnapmaticWidget"; -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "SnapmaticWidget.h" +#include "ui_SnapmaticWidget.h" +#include "SnapmaticPicture.h" +#include "SnapmaticEditor.h" +#include "DatabaseThread.h" +#include "PictureDialog.h" +#include "PictureExport.h" +#include "StringParser.h" +#include "AppEnv.h" +#include "config.h" +#include <QStringBuilder> +#include <QMessageBox> +#include <QPixmap> +#include <QTimer> +#include <QDebug> +#include <QMenu> +#include <QFile> + +SnapmaticWidget::SnapmaticWidget(ProfileDatabase *profileDB, CrewDatabase *crewDB, DatabaseThread *threadDB, QWidget *parent) : + ProfileWidget(parent), profileDB(profileDB), crewDB(crewDB), threadDB(threadDB), + ui(new Ui::SnapmaticWidget) +{ + ui->setupUi(this); + ui->cmdView->setVisible(false); + ui->cmdCopy->setVisible(false); + ui->cmdExport->setVisible(false); + ui->cmdDelete->setVisible(false); + ui->cbSelected->setVisible(false); + + QPalette palette; + palette.setCurrentColorGroup(QPalette::Disabled); + highlightHiddenColor = palette.text().color(); + + ui->SnapmaticFrame->setMouseTracking(true); + ui->labPicture->setMouseTracking(true); + ui->labPicStr->setMouseTracking(true); + ui->cbSelected->setMouseTracking(true); + smpic = nullptr; +} + +SnapmaticWidget::~SnapmaticWidget() +{ + delete ui; +} + +void SnapmaticWidget::setSnapmaticPicture(SnapmaticPicture *picture) +{ + smpic = picture; + QObject::connect(picture, SIGNAL(updated()), this, SLOT(snapmaticUpdated())); + + qreal screenRatio = AppEnv::screenRatio(); + ui->labPicture->setFixedSize(48 * screenRatio, 27 * screenRatio); + + QPixmap SnapmaticPixmap = QPixmap::fromImage(picture->getImage().scaled(ui->labPicture->width(), ui->labPicture->height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::AutoColor); + ui->labPicStr->setText(smpic->getPictureStr() % "\n" % smpic->getPictureTitl() % ""); + ui->labPicture->setPixmap(SnapmaticPixmap); + + picture->clearCache(); + + adjustTextColor(); +} + +void SnapmaticWidget::snapmaticUpdated() +{ + ui->labPicStr->setText(smpic->getPictureStr() % "\n" % smpic->getPictureTitl() % ""); +} + +void SnapmaticWidget::retranslate() +{ + smpic->updateStrings(); + ui->labPicStr->setText(smpic->getPictureStr() % "\n" % smpic->getPictureTitl() % ""); +} + +void SnapmaticWidget::on_cmdView_clicked() +{ + QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); + settings.beginGroup("Interface"); + bool navigationBar = settings.value("NavigationBar", false).toBool(); + settings.endGroup(); + + PictureDialog *picDialog = new PictureDialog(profileDB, crewDB, this); + picDialog->setSnapmaticPicture(smpic, true); + picDialog->setModal(true); + + // be ready for crewName and playerName updated + QObject::connect(threadDB, SIGNAL(crewNameUpdated()), picDialog, SLOT(crewNameUpdated())); + QObject::connect(threadDB, SIGNAL(playerNameUpdated()), picDialog, SLOT(playerNameUpdated())); + QObject::connect(picDialog, SIGNAL(nextPictureRequested()), this, SLOT(dialogNextPictureRequested())); + QObject::connect(picDialog, SIGNAL(previousPictureRequested()), this, SLOT(dialogPreviousPictureRequested())); + + // add previous next buttons + if (navigationBar) picDialog->addPreviousNextButtons(); + + // show picture dialog +#ifdef Q_OS_ANDROID + // Android ... + picDialog->showMaximized(); +#else + picDialog->show(); + if (navigationBar) picDialog->stylizeDialog(); + //picDialog->adaptNewDialogSize(); + picDialog->setMinimumSize(picDialog->size()); + picDialog->setMaximumSize(picDialog->size()); +#endif + picDialog->exec(); + delete picDialog; +} + +void SnapmaticWidget::on_cmdCopy_clicked() +{ + PictureExport::exportAsSnapmatic(this, smpic); +} + +void SnapmaticWidget::on_cmdExport_clicked() +{ + PictureExport::exportAsPicture(this, smpic); +} + +void SnapmaticWidget::on_cmdDelete_clicked() +{ + if (deletePicture()) emit pictureDeleted(); +} + +bool SnapmaticWidget::deletePicture() +{ + int uchoice = QMessageBox::question(this, tr("Delete picture"), tr("Are you sure to delete %1 from your Snapmatic pictures?").arg("\""+smpic->getPictureStr()+"\""), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + if (uchoice == QMessageBox::Yes) + { + if (smpic->deletePicFile()) + { + return true; + } + else + { + QMessageBox::warning(this, tr("Delete picture"), tr("Failed at deleting %1 from your Snapmatic pictures").arg("\""+smpic->getPictureStr()+"\"")); + } + } + return false; +} + +void SnapmaticWidget::mousePressEvent(QMouseEvent *ev) +{ + ProfileWidget::mousePressEvent(ev); +} + +void SnapmaticWidget::mouseReleaseEvent(QMouseEvent *ev) +{ + ProfileWidget::mouseReleaseEvent(ev); + if (ui->cbSelected->isVisible()) + { + if (rect().contains(ev->pos()) && ev->button() == Qt::LeftButton) + { + ui->cbSelected->setChecked(!ui->cbSelected->isChecked()); + } + } + else + { + if (getContentMode() == 0 && rect().contains(ev->pos()) && ev->button() == Qt::LeftButton) + { + if (ev->modifiers().testFlag(Qt::ShiftModifier)) + { + ui->cbSelected->setChecked(!ui->cbSelected->isChecked()); + } + else + { + on_cmdView_clicked(); + } + } + else if (!ui->cbSelected->isVisible() && getContentMode() == 1 && ev->button() == Qt::LeftButton && ev->modifiers().testFlag(Qt::ShiftModifier)) + { + ui->cbSelected->setChecked(!ui->cbSelected->isChecked()); + } + } +} + +void SnapmaticWidget::mouseDoubleClickEvent(QMouseEvent *ev) +{ + ProfileWidget::mouseDoubleClickEvent(ev); + + if (!ui->cbSelected->isVisible() && getContentMode() == 1 && ev->button() == Qt::LeftButton) + { + on_cmdView_clicked(); + } +} + +void SnapmaticWidget::setSelected(bool isSelected) +{ + ui->cbSelected->setChecked(isSelected); +} + +void SnapmaticWidget::pictureSelected() +{ + setSelected(!ui->cbSelected->isChecked()); +} + +void SnapmaticWidget::contextMenuEvent(QContextMenuEvent *ev) +{ + emit contextMenuTriggered(ev); +} + +void SnapmaticWidget::dialogNextPictureRequested() +{ + emit nextPictureRequested((QWidget*)sender()); +} + +void SnapmaticWidget::dialogPreviousPictureRequested() +{ + emit previousPictureRequested((QWidget*)sender()); +} + +void SnapmaticWidget::on_cbSelected_stateChanged(int arg1) +{ + if (arg1 == Qt::Checked) + { + emit widgetSelected(); + } + else if (arg1 == Qt::Unchecked) + { + emit widgetDeselected(); + } +} + +void SnapmaticWidget::adjustTextColor() +{ + if (isHidden()) + { + ui->labPicStr->setStyleSheet(QString("QLabel{color: rgb(%1, %2, %3);}").arg(QString::number(highlightHiddenColor.red()), QString::number(highlightHiddenColor.green()), QString::number(highlightHiddenColor.blue()))); + } + else + { + ui->labPicStr->setStyleSheet(""); + } +} + +bool SnapmaticWidget::makePictureHidden() +{ + if (smpic->setPictureHidden()) + { + adjustTextColor(); + return true; + } + return false; +} + +bool SnapmaticWidget::makePictureVisible() +{ + if (smpic->setPictureVisible()) + { + adjustTextColor(); + return true; + } + return false; +} + +void SnapmaticWidget::makePictureHiddenSlot() +{ + makePictureHidden(); +} + +void SnapmaticWidget::makePictureVisibleSlot() +{ + makePictureVisible(); +} + +void SnapmaticWidget::editSnapmaticProperties() +{ + SnapmaticEditor *snapmaticEditor = new SnapmaticEditor(crewDB, this); + snapmaticEditor->setWindowFlags(snapmaticEditor->windowFlags()^Qt::WindowContextHelpButtonHint); + snapmaticEditor->setSnapmaticPicture(smpic); + snapmaticEditor->setModal(true); + snapmaticEditor->exec(); + delete snapmaticEditor; +} + +bool SnapmaticWidget::isSelected() +{ + return ui->cbSelected->isChecked(); +} + +bool SnapmaticWidget::isHidden() +{ + return smpic->isHidden(); +} + +void SnapmaticWidget::setSelectionMode(bool selectionMode) +{ + ui->cbSelected->setVisible(selectionMode); +} + +void SnapmaticWidget::selectAllWidgets() +{ + emit allWidgetsSelected(); +} + +void SnapmaticWidget::deselectAllWidgets() +{ + emit allWidgetsDeselected(); +} + +SnapmaticPicture* SnapmaticWidget::getPicture() +{ + return smpic; +} + +QString SnapmaticWidget::getPicturePath() +{ + return smpic->getPictureFilePath(); +} + +QString SnapmaticWidget::getWidgetType() +{ + return "SnapmaticWidget"; +} diff --git a/SnapmaticWidget.h b/SnapmaticWidget.h index a25b638..9a7b3f3 100755 --- a/SnapmaticWidget.h +++ b/SnapmaticWidget.h @@ -1,104 +1,98 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef SNAPMATICWIDGET_H -#define SNAPMATICWIDGET_H - -#include "SnapmaticPicture.h" -#include "ProfileDatabase.h" -#include "DatabaseThread.h" -#include "ProfileWidget.h" -#include "CrewDatabase.h" -#include <QContextMenuEvent> -#include <QMouseEvent> -#include <QWidget> -#include <QColor> - -namespace Ui { -class SnapmaticWidget; -} - -class SnapmaticWidget : public ProfileWidget -{ - Q_OBJECT - -public: - SnapmaticWidget(ProfileDatabase *profileDB, CrewDatabase *crewDB, DatabaseThread *threadDB, QWidget *parent = 0); - void setSnapmaticPicture(SnapmaticPicture *picture); - void setSelectionMode(bool selectionMode); - void setSelected(bool isSelected); - bool deletePicture(); - bool makePictureVisible(); - bool makePictureHidden(); - SnapmaticPicture *getPicture(); - QString getPicturePath(); - QString getWidgetType(); - bool isSelected(); - bool isHidden(); - ~SnapmaticWidget(); - -private slots: - void on_cmdView_clicked(); - void on_cmdCopy_clicked(); - void on_cmdExport_clicked(); - void on_cmdDelete_clicked(); - void on_cbSelected_stateChanged(int arg1); - void adjustTextColor(); - void pictureSelected(); - void selectAllWidgets(); - void deselectAllWidgets(); - void dialogNextPictureRequested(); - void dialogPreviousPictureRequested(); - void makePictureVisibleSlot(); - void makePictureHiddenSlot(); - void editSnapmaticProperties(); - void snapmaticUpdated(); - -protected: - bool eventFilter(QObject *obj, QEvent *ev); - void mouseDoubleClickEvent(QMouseEvent *ev); - void mouseReleaseEvent(QMouseEvent *ev); - void mousePressEvent(QMouseEvent *ev); - void contextMenuEvent(QContextMenuEvent *ev); - -private: - ProfileDatabase *profileDB; - CrewDatabase *crewDB; - DatabaseThread *threadDB; - Ui::SnapmaticWidget *ui; - SnapmaticPicture *smpic; - QColor highlightBackColor; - QColor highlightTextColor; - QColor highlightHiddenColor; - QString picPath; - QString picTitl; - QString picStr; - QWidget *snwgt; - -signals: - void pictureDeleted(); - void widgetSelected(); - void widgetDeselected(); - void allWidgetsSelected(); - void allWidgetsDeselected(); - void nextPictureRequested(QWidget *dialog); - void previousPictureRequested(QWidget *dialog); - void contextMenuTriggered(QContextMenuEvent *ev); -}; - -#endif // SNAPMATICWIDGET_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef SNAPMATICWIDGET_H +#define SNAPMATICWIDGET_H + +#include "SnapmaticPicture.h" +#include "ProfileDatabase.h" +#include "DatabaseThread.h" +#include "ProfileWidget.h" +#include "CrewDatabase.h" +#include <QContextMenuEvent> +#include <QMouseEvent> +#include <QWidget> +#include <QColor> + +namespace Ui { +class SnapmaticWidget; +} + +class SnapmaticWidget : public ProfileWidget +{ + Q_OBJECT + +public: + SnapmaticWidget(ProfileDatabase *profileDB, CrewDatabase *crewDB, DatabaseThread *threadDB, QWidget *parent = 0); + void setSnapmaticPicture(SnapmaticPicture *picture); + void setSelectionMode(bool selectionMode); + void setSelected(bool isSelected); + bool deletePicture(); + bool makePictureVisible(); + bool makePictureHidden(); + SnapmaticPicture *getPicture(); + QString getPicturePath(); + QString getWidgetType(); + bool isSelected(); + bool isHidden(); + void retranslate(); + ~SnapmaticWidget(); + +private slots: + void on_cmdView_clicked(); + void on_cmdCopy_clicked(); + void on_cmdExport_clicked(); + void on_cmdDelete_clicked(); + void on_cbSelected_stateChanged(int arg1); + void adjustTextColor(); + void pictureSelected(); + void selectAllWidgets(); + void deselectAllWidgets(); + void dialogNextPictureRequested(); + void dialogPreviousPictureRequested(); + void makePictureVisibleSlot(); + void makePictureHiddenSlot(); + void editSnapmaticProperties(); + void snapmaticUpdated(); + +protected: + void mouseDoubleClickEvent(QMouseEvent *ev); + void mouseReleaseEvent(QMouseEvent *ev); + void mousePressEvent(QMouseEvent *ev); + void contextMenuEvent(QContextMenuEvent *ev); + +private: + ProfileDatabase *profileDB; + CrewDatabase *crewDB; + DatabaseThread *threadDB; + Ui::SnapmaticWidget *ui; + SnapmaticPicture *smpic; + QColor highlightHiddenColor; + +signals: + void pictureDeleted(); + void widgetSelected(); + void widgetDeselected(); + void allWidgetsSelected(); + void allWidgetsDeselected(); + void nextPictureRequested(QWidget *dialog); + void previousPictureRequested(QWidget *dialog); + void contextMenuTriggered(QContextMenuEvent *ev); +}; + +#endif // SNAPMATICWIDGET_H diff --git a/SnapmaticWidget.ui b/SnapmaticWidget.ui index 5c720c8..a3e7e89 100755 --- a/SnapmaticWidget.ui +++ b/SnapmaticWidget.ui @@ -1,169 +1,169 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>SnapmaticWidget</class> - <widget class="QWidget" name="SnapmaticWidget"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>490</width> - <height>45</height> - </rect> - </property> - <property name="windowTitle"> - <string>Snapmatic Widget</string> - </property> - <layout class="QHBoxLayout" name="hlSnapmaticContent"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QFrame" name="SnapmaticFrame"> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Plain</enum> - </property> - <property name="lineWidth"> - <number>0</number> - </property> - <layout class="QHBoxLayout" name="hlSnapmatic"> - <item> - <widget class="QCheckBox" name="cbSelected"> - <property name="focusPolicy"> - <enum>Qt::NoFocus</enum> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="labPicture"> - <property name="minimumSize"> - <size> - <width>48</width> - <height>27</height> - </size> - </property> - <property name="maximumSize"> - <size> - <width>48</width> - <height>27</height> - </size> - </property> - <property name="lineWidth"> - <number>0</number> - </property> - <property name="text"> - <string/> - </property> - <property name="scaledContents"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="labPicStr"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>PHOTO - 00/00/00 00:00:00</string> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="cmdView"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>View picture</string> - </property> - <property name="text"> - <string>View</string> - </property> - <property name="autoDefault"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="cmdCopy"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Copy picture</string> - </property> - <property name="text"> - <string>Copy</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="cmdExport"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Export picture</string> - </property> - <property name="text"> - <string>Export</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="cmdDelete"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Delete picture</string> - </property> - <property name="text"> - <string>Delete</string> - </property> - <property name="autoDefault"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>SnapmaticWidget</class> + <widget class="QWidget" name="SnapmaticWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>490</width> + <height>45</height> + </rect> + </property> + <property name="windowTitle"> + <string>Snapmatic Widget</string> + </property> + <layout class="QHBoxLayout" name="hlSnapmaticContent"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QFrame" name="SnapmaticFrame"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <layout class="QHBoxLayout" name="hlSnapmatic"> + <item> + <widget class="QCheckBox" name="cbSelected"> + <property name="focusPolicy"> + <enum>Qt::NoFocus</enum> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="labPicture"> + <property name="minimumSize"> + <size> + <width>48</width> + <height>27</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>48</width> + <height>27</height> + </size> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="text"> + <string/> + </property> + <property name="scaledContents"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="labPicStr"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>PHOTO - 00/00/00 00:00:00</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="cmdView"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>View picture</string> + </property> + <property name="text"> + <string>View</string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="cmdCopy"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Copy picture</string> + </property> + <property name="text"> + <string>Copy</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="cmdExport"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Export picture</string> + </property> + <property name="text"> + <string>Export</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="cmdDelete"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Delete picture</string> + </property> + <property name="text"> + <string>Delete</string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/StandardPaths.cpp b/StandardPaths.cpp index dda73a3..fa5ed24 100755 --- a/StandardPaths.cpp +++ b/StandardPaths.cpp @@ -1,128 +1,128 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "StandardPaths.h" -#if QT_VERSION >= 0x050000 -#include <QStandardPaths> -#else -#include <QDesktopServices> -#endif - -StandardPaths::StandardPaths() -{ - -} - -QString StandardPaths::applicationsLocation() -{ -#if QT_VERSION >= 0x050000 - return QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation); -#else - return QDesktopServices::storageLocation(QDesktopServices::ApplicationsLocation); -#endif -} - -QString StandardPaths::cacheLocation() -{ -#if QT_VERSION >= 0x050000 - return QStandardPaths::writableLocation(QStandardPaths::CacheLocation); -#else - return QDesktopServices::storageLocation(QDesktopServices::CacheLocation); -#endif -} - -QString StandardPaths::dataLocation() -{ -#if QT_VERSION >= 0x050000 - return QStandardPaths::writableLocation(QStandardPaths::DataLocation); -#else - return QDesktopServices::storageLocation(QDesktopServices::DataLocation); -#endif -} - -QString StandardPaths::desktopLocation() -{ -#if QT_VERSION >= 0x050000 - return QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); -#else - return QDesktopServices::storageLocation(QDesktopServices::DesktopLocation); -#endif -} - -QString StandardPaths::documentsLocation() -{ -#if QT_VERSION >= 0x050000 - return QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); -#else - return QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); -#endif -} - -QString StandardPaths::moviesLocation() -{ -#if QT_VERSION >= 0x050000 - return QStandardPaths::writableLocation(QStandardPaths::MoviesLocation); -#else - return QDesktopServices::storageLocation(QDesktopServices::MoviesLocation); -#endif -} - -QString StandardPaths::picturesLocation() -{ -#if QT_VERSION >= 0x050000 - return QStandardPaths::writableLocation(QStandardPaths::PicturesLocation); -#else - return QDesktopServices::storageLocation(QDesktopServices::PicturesLocation); -#endif -} - -QString StandardPaths::fontsLocation() -{ -#if QT_VERSION >= 0x050000 - return QStandardPaths::writableLocation(QStandardPaths::FontsLocation); -#else - return QDesktopServices::storageLocation(QDesktopServices::FontsLocation); -#endif -} - -QString StandardPaths::homeLocation() -{ -#if QT_VERSION >= 0x050000 - return QStandardPaths::writableLocation(QStandardPaths::HomeLocation); -#else - return QDesktopServices::storageLocation(QDesktopServices::HomeLocation); -#endif -} - -QString StandardPaths::musicLocation() -{ -#if QT_VERSION >= 0x050000 - return QStandardPaths::writableLocation(QStandardPaths::MusicLocation); -#else - return QDesktopServices::storageLocation(QDesktopServices::MusicLocation); -#endif -} - -QString StandardPaths::tempLocation() -{ -#if QT_VERSION >= 0x050000 - return QStandardPaths::writableLocation(QStandardPaths::TempLocation); -#else - return QDesktopServices::storageLocation(QDesktopServices::TempLocation); -#endif -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "StandardPaths.h" +#if QT_VERSION >= 0x050000 +#include <QStandardPaths> +#else +#include <QDesktopServices> +#endif + +StandardPaths::StandardPaths() +{ + +} + +QString StandardPaths::applicationsLocation() +{ +#if QT_VERSION >= 0x050000 + return QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation); +#else + return QDesktopServices::storageLocation(QDesktopServices::ApplicationsLocation); +#endif +} + +QString StandardPaths::cacheLocation() +{ +#if QT_VERSION >= 0x050000 + return QStandardPaths::writableLocation(QStandardPaths::CacheLocation); +#else + return QDesktopServices::storageLocation(QDesktopServices::CacheLocation); +#endif +} + +QString StandardPaths::dataLocation() +{ +#if QT_VERSION >= 0x050000 + return QStandardPaths::writableLocation(QStandardPaths::DataLocation); +#else + return QDesktopServices::storageLocation(QDesktopServices::DataLocation); +#endif +} + +QString StandardPaths::desktopLocation() +{ +#if QT_VERSION >= 0x050000 + return QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); +#else + return QDesktopServices::storageLocation(QDesktopServices::DesktopLocation); +#endif +} + +QString StandardPaths::documentsLocation() +{ +#if QT_VERSION >= 0x050000 + return QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); +#else + return QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); +#endif +} + +QString StandardPaths::moviesLocation() +{ +#if QT_VERSION >= 0x050000 + return QStandardPaths::writableLocation(QStandardPaths::MoviesLocation); +#else + return QDesktopServices::storageLocation(QDesktopServices::MoviesLocation); +#endif +} + +QString StandardPaths::picturesLocation() +{ +#if QT_VERSION >= 0x050000 + return QStandardPaths::writableLocation(QStandardPaths::PicturesLocation); +#else + return QDesktopServices::storageLocation(QDesktopServices::PicturesLocation); +#endif +} + +QString StandardPaths::fontsLocation() +{ +#if QT_VERSION >= 0x050000 + return QStandardPaths::writableLocation(QStandardPaths::FontsLocation); +#else + return QDesktopServices::storageLocation(QDesktopServices::FontsLocation); +#endif +} + +QString StandardPaths::homeLocation() +{ +#if QT_VERSION >= 0x050000 + return QStandardPaths::writableLocation(QStandardPaths::HomeLocation); +#else + return QDesktopServices::storageLocation(QDesktopServices::HomeLocation); +#endif +} + +QString StandardPaths::musicLocation() +{ +#if QT_VERSION >= 0x050000 + return QStandardPaths::writableLocation(QStandardPaths::MusicLocation); +#else + return QDesktopServices::storageLocation(QDesktopServices::MusicLocation); +#endif +} + +QString StandardPaths::tempLocation() +{ +#if QT_VERSION >= 0x050000 + return QStandardPaths::writableLocation(QStandardPaths::TempLocation); +#else + return QDesktopServices::storageLocation(QDesktopServices::TempLocation); +#endif +} diff --git a/StandardPaths.h b/StandardPaths.h index 203953b..619bdeb 100755 --- a/StandardPaths.h +++ b/StandardPaths.h @@ -1,41 +1,41 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef STANDARDPATHS_H -#define STANDARDPATHS_H - -#include <QString> - -class StandardPaths -{ -public: - StandardPaths(); - static QString applicationsLocation(); - static QString cacheLocation(); - static QString dataLocation(); - static QString desktopLocation(); - static QString documentsLocation(); - static QString fontsLocation(); - static QString homeLocation(); - static QString moviesLocation(); - static QString picturesLocation(); - static QString musicLocation(); - static QString tempLocation(); -}; - -#endif // STANDARDPATHS_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef STANDARDPATHS_H +#define STANDARDPATHS_H + +#include <QString> + +class StandardPaths +{ +public: + StandardPaths(); + static QString applicationsLocation(); + static QString cacheLocation(); + static QString dataLocation(); + static QString desktopLocation(); + static QString documentsLocation(); + static QString fontsLocation(); + static QString homeLocation(); + static QString moviesLocation(); + static QString picturesLocation(); + static QString musicLocation(); + static QString tempLocation(); +}; + +#endif // STANDARDPATHS_H diff --git a/StringParser.cpp b/StringParser.cpp index 6addd10..1854c88 100755 --- a/StringParser.cpp +++ b/StringParser.cpp @@ -1,76 +1,80 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "StringParser.h" -#include "config.h" -#include <QTextDocument> -#ifndef GTA5VIEW_CMD -#include <QApplication> -#endif -#include <QTextCodec> -#include <QByteArray> -#include <QFileInfo> -#include <QString> -#include <QList> -#include <QDir> - -StringParser::StringParser() -{ - -} - -QString StringParser::parseTitleString(const QByteArray &commitBytes, int maxLength) -{ - Q_UNUSED(maxLength) - QString retStr = QTextCodec::codecForName("UTF-16LE")->toUnicode(commitBytes).trimmed(); - retStr.remove(QChar('\x00')); - return retStr; -} - -QString StringParser::convertDrawStringForLog(const QString &inputStr) -{ - QString outputStr = inputStr; - return outputStr.replace("&","&u;").replace(",","&c;"); -} - -QString StringParser::convertLogStringForDraw(const QString &inputStr) -{ - QString outputStr = inputStr; - return outputStr.replace("&c;",",").replace("&u;","&"); -} - -#ifndef GTA5VIEW_CMD -QString StringParser::convertBuildedString(const QString &buildedStr) -{ - QString outputStr = buildedStr; - QByteArray sharePath = GTA5SYNC_SHARE; - outputStr.replace("$SHAREDIR", QString::fromUtf8(sharePath)); - outputStr.replace("$RUNDIR", QFileInfo(qApp->applicationFilePath()).absoluteDir().absolutePath()); - outputStr.replace("$SEPARATOR", QDir::separator()); - return outputStr; -} -#endif - -QString StringParser::escapeString(const QString &toEscape) -{ -#if QT_VERSION >= 0x050000 - return toEscape.toHtmlEscaped(); -#else - return Qt::escape(toEscape); -#endif -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "StringParser.h" +#include "config.h" +#include <QTextDocument> +#include <QLibraryInfo> +#ifndef GTA5VIEW_CMD +#include <QApplication> +#endif +#include <QTextCodec> +#include <QByteArray> +#include <QFileInfo> +#include <QString> +#include <QList> +#include <QDir> + +StringParser::StringParser() +{ + +} + +QString StringParser::parseTitleString(const QByteArray &commitBytes, int maxLength) +{ + Q_UNUSED(maxLength) + QString retStr = QTextCodec::codecForName("UTF-16LE")->toUnicode(commitBytes).trimmed(); + retStr.remove(QChar('\x00')); + return retStr; +} + +QString StringParser::convertDrawStringForLog(const QString &inputStr) +{ + QString outputStr = inputStr; + return outputStr.replace("&","&u;").replace(",","&c;"); +} + +QString StringParser::convertLogStringForDraw(const QString &inputStr) +{ + QString outputStr = inputStr; + return outputStr.replace("&c;",",").replace("&u;","&"); +} + +#ifndef GTA5VIEW_CMD +QString StringParser::convertBuildedString(const QString &buildedStr) +{ + QString outputStr = buildedStr; + QByteArray sharePath = GTA5SYNC_SHARE; + outputStr.replace("APPNAME:", GTA5SYNC_APPSTR); + outputStr.replace("SHAREDDIR:", QString::fromUtf8(sharePath)); + outputStr.replace("RUNDIR:", QFileInfo(qApp->applicationFilePath()).absoluteDir().absolutePath()); + outputStr.replace("QCONFLANG:", QLibraryInfo::location(QLibraryInfo::TranslationsPath)); + outputStr.replace("QCONFPLUG:", QLibraryInfo::location(QLibraryInfo::PluginsPath)); + outputStr.replace("SEPARATOR:", QDir::separator()); + return outputStr; +} +#endif + +QString StringParser::escapeString(const QString &toEscape) +{ +#if QT_VERSION >= 0x050000 + return toEscape.toHtmlEscaped(); +#else + return Qt::escape(toEscape); +#endif +} diff --git a/StringParser.h b/StringParser.h index a9505f6..0b5d7e3 100755 --- a/StringParser.h +++ b/StringParser.h @@ -1,38 +1,38 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef STRINGPARSER_H -#define STRINGPARSER_H - -#include <QByteArray> -#include <QString> - -class StringParser -{ -public: - StringParser(); - static QString parseTitleString(const QByteArray &commitBytes, int maxLength); - static QString convertDrawStringForLog(const QString &inputStr); - static QString convertLogStringForDraw(const QString &inputStr); -#ifndef GTA5VIEW_CMD - static QString convertBuildedString(const QString &buildedStr); -#endif - static QString escapeString(const QString &toEscape); -}; - -#endif // STRINGPARSER_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef STRINGPARSER_H +#define STRINGPARSER_H + +#include <QByteArray> +#include <QString> + +class StringParser +{ +public: + StringParser(); + static QString parseTitleString(const QByteArray &commitBytes, int maxLength); + static QString convertDrawStringForLog(const QString &inputStr); + static QString convertLogStringForDraw(const QString &inputStr); +#ifndef GTA5VIEW_CMD + static QString convertBuildedString(const QString &buildedStr); +#endif + static QString escapeString(const QString &toEscape); +}; + +#endif // STRINGPARSER_H diff --git a/TranslationClass.cpp b/TranslationClass.cpp new file mode 100644 index 0000000..6dc4d7f --- /dev/null +++ b/TranslationClass.cpp @@ -0,0 +1,543 @@ +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "TranslationClass.h" +#include "AppEnv.h" +#include "config.h" +#include <QStringBuilder> +#include <QApplication> +#include <QStringList> +#include <QTranslator> +#include <QSettings> +#include <QLocale> +#include <QDebug> +#include <QFile> +#include <QDir> + +#if QT_VERSION >= 0x050000 +#define QtBaseTranslationFormat "qtbase_" +#else +#define QtBaseTranslationFormat "qt_" +#endif + +TranslationClass TranslationClass::translationClassInstance; + +void TranslationClass::initUserLanguage() +{ + QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); + settings.beginGroup("Interface"); + userLanguage = settings.value("Language", "System").toString(); + settings.endGroup(); +} + +void TranslationClass::loadTranslation(QApplication *app) +{ + if (isLangLoaded) { unloadTranslation(app); } + else { currentLangIndex = 0; } + QString exLangPath = AppEnv::getExLangFolder(); + QString inLangPath = AppEnv::getInLangFolder(); + if (userLanguage == "en" || userLanguage == "en_GB") + { + currentLanguage = "en_GB"; + if (loadQtTranslation_p(exLangPath, &exQtTranslator)) + { + app->installTranslator(&exQtTranslator); + } + else if (loadQtTranslation_p(inLangPath, &inQtTranslator)) + { + app->installTranslator(&inQtTranslator); + } + QLocale::setDefault(currentLanguage); + isLangLoaded = true; + return; + } +#ifndef GTA5SYNC_QCONF // Classic modable loading method + QString externalLanguageStr; + bool externalLanguageReady = false; + bool loadInternalLang = false; + bool trLoadSuccess = false; + if (isUserLanguageSystem_p()) + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadExSystemLanguage"; +#endif + trLoadSuccess = loadSystemTranslation_p(exLangPath, &exAppTranslator); + } + else + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadExUserLanguage"; +#endif + trLoadSuccess = loadUserTranslation_p(exLangPath, &exAppTranslator); + if (!trLoadSuccess) + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadInUserLanguage"; +#endif + trLoadSuccess = loadUserTranslation_p(inLangPath, &inAppTranslator); + if (!trLoadSuccess) + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadUserLanguageFailed"; +#endif + } + else + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadUserLanguageSuccess"; +#endif + loadInternalLang = true; + isLangLoaded = true; + } + } + else + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadUserLanguageSuccess"; +#endif + isLangLoaded = true; + } + } + if (trLoadSuccess) + { + if (currentLangIndex != 0) // Don't install the language until we know we not have a better language for the user + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "externalLanguageReady" << currentLanguage; +#endif + externalLanguageStr = currentLanguage; + externalLanguageReady = true; + } + else + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "installTranslation"; +#endif + if (loadInternalLang) + { + app->installTranslator(&inAppTranslator); + } + else + { + app->installTranslator(&exAppTranslator); + } + if (loadQtTranslation_p(exLangPath, &exQtTranslator)) + { + app->installTranslator(&exQtTranslator); + } + else if (loadQtTranslation_p(inLangPath, &inQtTranslator)) + { + app->installTranslator(&inQtTranslator); + } + QLocale::setDefault(currentLanguage); + isLangLoaded = true; + } + } + if (externalLanguageReady) + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadInSystemLanguage"; +#endif + int externalLangIndex = currentLangIndex; + trLoadSuccess = loadSystemTranslation_p(inLangPath, &inAppTranslator); +#ifdef GTA5SYNC_DEBUG + qDebug() << "externalLangIndex" << externalLangIndex << "internalLangIndex" << currentLangIndex; +#endif + if (trLoadSuccess && externalLangIndex > currentLangIndex) + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "installInternalTranslation"; +#endif + app->installTranslator(&inAppTranslator); + if (loadQtTranslation_p(exLangPath, &exQtTranslator)) + { + app->installTranslator(&exQtTranslator); + } + else if (loadQtTranslation_p(inLangPath, &inQtTranslator)) + { + app->installTranslator(&inQtTranslator); + } + QLocale::setDefault(currentLanguage); + isLangLoaded = true; + } + else + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "installExternalTranslation"; +#endif + currentLanguage = externalLanguageStr; + app->installTranslator(&exAppTranslator); + if (loadQtTranslation_p(exLangPath, &exQtTranslator)) + { + app->installTranslator(&exQtTranslator); + } + else if (loadQtTranslation_p(inLangPath, &inQtTranslator)) + { + app->installTranslator(&inQtTranslator); + } + QLocale::setDefault(currentLanguage); + isLangLoaded = true; + } + } + else if (!isLangLoaded) + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadInSystemLanguage"; +#endif + trLoadSuccess = loadSystemTranslation_p(inLangPath, &inAppTranslator); + if (trLoadSuccess) + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "installInternalTranslation"; +#endif + app->installTranslator(&inAppTranslator); + if (loadQtTranslation_p(exLangPath, &exQtTranslator)) + { + app->installTranslator(&exQtTranslator); + } + else if (loadQtTranslation_p(inLangPath, &inQtTranslator)) + { + app->installTranslator(&inQtTranslator); + } + QLocale::setDefault(currentLanguage); + isLangLoaded = true; + } + else if (!trLoadSuccess) + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "fallbackToDefaultApplicationLanguage"; +#endif + currentLanguage = "en_GB"; + if (loadQtTranslation_p(exLangPath, &exQtTranslator)) + { + app->installTranslator(&exQtTranslator); + } + else if (loadQtTranslation_p(inLangPath, &inQtTranslator)) + { + app->installTranslator(&inQtTranslator); + } + QLocale::setDefault(currentLanguage); + isLangLoaded = true; + } + } +#else // New qconf loading method + bool trLoadSuccess; + if (isUserLanguageSystem_p()) + { + trLoadSuccess = loadSystemTranslation_p(inLangPath, &inAppTranslator); + } + else + { + trLoadSuccess = loadUserTranslation_p(inLangPath, &inAppTranslator); + } + if (!trLoadSuccess && !isUserLanguageSystem_p()) + { + trLoadSuccess = loadSystemTranslation_p(inLangPath, &inAppTranslator); + } + if (trLoadSuccess) + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "installTranslation" << currentLanguage; +#endif + app->installTranslator(&inAppTranslator); + if (loadQtTranslation_p(exLangPath, &exQtTranslator)) + { + app->installTranslator(&exQtTranslator); + } + else if (loadQtTranslation_p(inLangPath, &inQtTranslator)) + { + app->installTranslator(&inQtTranslator); + } + QLocale::setDefault(currentLanguage); + isLangLoaded = true; + } +#endif +} + +QStringList TranslationClass::listTranslations(const QString &langPath) +{ + QDir langDir; + langDir.setNameFilters(QStringList("gta5sync_*.qm")); + langDir.setPath(langPath); + QStringList availableLanguages; + foreach(const QString &lang, langDir.entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::NoSort)) + { + availableLanguages << QString(lang).remove("gta5sync_").remove(".qm"); + } + return availableLanguages; +} + +bool TranslationClass::loadSystemTranslation_p(const QString &langPath, QTranslator *appTranslator) +{ +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadSystemTranslation_p"; +#endif + int currentLangCounter = 0; + foreach(const QString &languageName, QLocale::system().uiLanguages()) + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadLanguage" << languageName; +#endif + QStringList langList = QString(languageName).replace("-","_").split("_"); + if (langList.length() == 2) + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadLanguageFile" << QString(langPath % QDir::separator() % "gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm"); +#endif + if (QFile::exists(langPath % QDir::separator() % "gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm")) + { + if (appTranslator->load(langPath % QDir::separator() % "gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm")) + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadLanguageFileSuccess" << QString(langPath % QDir::separator() % "gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm"); +#endif + currentLanguage = languageName; + currentLangIndex = currentLangCounter; + return true; + } + } +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadLanguageFile" << QString(langPath % QDir::separator() % "gta5sync_" % langList.at(0) % ".qm"); +#endif + if (QFile::exists(langPath % QDir::separator() % "gta5sync_" % langList.at(0) % ".qm")) + { + if (appTranslator->load(langPath % QDir::separator() % "gta5sync_" % langList.at(0) % ".qm")) + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadLanguageFileSuccess" << QString(langPath % QDir::separator() % "gta5sync_" % langList.at(0) % ".qm"); +#endif + currentLanguage = languageName; + currentLangIndex = currentLangCounter; + return true; + } + } + if (langList.at(0) == "en") + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "languageEnglishMode index" << currentLangCounter; +#endif + currentLanguage = languageName; + currentLangIndex = currentLangCounter; + return true; + } + } + else if (langList.length() == 1) + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadLanguageFile" << QString(langPath % QDir::separator() % "gta5sync_" % langList.at(0) % ".qm"); +#endif + if (QFile::exists(langPath % QDir::separator() % "gta5sync_" % langList.at(0) % ".qm")) + { + if (appTranslator->load(langPath % QDir::separator() % "gta5sync_" % langList.at(0) % ".qm")) + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadLanguageFileSuccess" << QString(langPath % QDir::separator() % "gta5sync_" % langList.at(0) % ".qm"); +#endif + currentLanguage = languageName; + return true; + } + } + } +#ifdef GTA5SYNC_DEBUG + qDebug() << "currentLangCounter bump"; +#endif + currentLangCounter++; + } + return false; +} + +bool TranslationClass::loadUserTranslation_p(const QString &langPath, QTranslator *appTranslator) +{ +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadUserTranslation_p"; +#endif + QString languageName = userLanguage; + QStringList langList = QString(languageName).replace("-","_").split("_"); + if (langList.length() == 2) + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadLanguageFile" << QString(langPath % QDir::separator() % "gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm"); +#endif + if (QFile::exists(langPath % QDir::separator() % "gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm")) + { + if (appTranslator->load(langPath % QDir::separator() % "gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm")) + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadLanguageFileSuccess" << QString(langPath % QDir::separator() % "gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm"); +#endif + currentLanguage = languageName; + return true; + } + } +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadLanguageFile" << QString(langPath % QDir::separator() % "gta5sync_" % langList.at(0) % ".qm"); +#endif + if (QFile::exists(langPath % QDir::separator() % "gta5sync_" % langList.at(0) % ".qm")) + { + if (appTranslator->load(langPath % QDir::separator() % "gta5sync_" % langList.at(0) % ".qm")) + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadLanguageFileSuccess" << QString(langPath % QDir::separator() % "gta5sync_" % langList.at(0) % ".qm"); +#endif + currentLanguage = languageName; + return true; + } + } + } + else if (langList.length() == 1) + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadLanguageFile" << QString(langPath % QDir::separator() % "gta5sync_" % langList.at(0) % ".qm"); +#endif + if (QFile::exists(langPath % QDir::separator() % "gta5sync_" % langList.at(0) % ".qm")) + { + if (appTranslator->load(langPath % QDir::separator() % "gta5sync_" % langList.at(0) % ".qm")) + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadLanguageFileSuccess" << QString(langPath % QDir::separator() % "gta5sync_" % langList.at(0) % ".qm"); +#endif + currentLanguage = languageName; + return true; + } + } + } + return false; +} + +bool TranslationClass::loadQtTranslation_p(const QString &langPath, QTranslator *qtTranslator) +{ +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadQtTranslation_p" << currentLanguage; +#endif + QString languageName = currentLanguage; + QStringList langList = QString(languageName).replace("-","_").split("_"); + if (langList.length() == 2) + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadLanguageFile" << QString(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % "_" % langList.at(1) % ".qm"); +#endif + if (QFile::exists(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % "_" % langList.at(1) % ".qm")) + { + if (qtTranslator->load(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % "_" % langList.at(1) % ".qm")) + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadLanguageFileSuccess" << QString(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % "_" % langList.at(1) % ".qm"); +#endif + return true; + } + } +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadLanguageFile" << QString(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % ".qm"); +#endif + if (QFile::exists(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % ".qm")) + { + if (qtTranslator->load(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % ".qm")) + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadLanguageFileSuccess" << QString(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % ".qm"); +#endif + return true; + } + } + } + else if (langList.length() == 1) + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadLanguageFile" << QString(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % ".qm"); +#endif + if (QFile::exists(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % ".qm")) + { + if (qtTranslator->load(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % ".qm")) + { +#ifdef GTA5SYNC_DEBUG + qDebug() << "loadLanguageFileSuccess" << QString(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % ".qm"); +#endif + return true; + } + } + } + return false; +} + +bool TranslationClass::isUserLanguageSystem_p() +{ + return (userLanguage == "System" || userLanguage.trimmed().isEmpty()); +} + +QString TranslationClass::getCurrentLanguage() +{ + return currentLanguage; +} + +bool TranslationClass::isLanguageLoaded() +{ + return isLangLoaded; +} + +void TranslationClass::unloadTranslation(QApplication *app) +{ + if (isLangLoaded) + { +#ifndef GTA5SYNC_QCONF + app->removeTranslator(&exAppTranslator); + app->removeTranslator(&exQtTranslator); + app->removeTranslator(&inAppTranslator); + app->removeTranslator(&inQtTranslator); +#else + app->removeTranslator(&inAppTranslator); + app->removeTranslator(&exQtTranslator); +#endif + currentLangIndex = 0; + currentLanguage = QString(); + QLocale::setDefault(QLocale::c()); + isLangLoaded = false; + } +#ifdef _MSC_VER // Fix dumb Microsoft compiler warning + Q_UNUSED(app) +#endif +} + +QString TranslationClass::getCountryCode(QLocale::Country country) +{ + QList<QLocale> locales = QLocale::matchingLocales(QLocale::AnyLanguage, + QLocale::AnyScript, + country); + if (locales.isEmpty()) return QString(); + QStringList localeStrList = locales.at(0).name().split("_"); + if (localeStrList.length() <= 2) + { + return localeStrList.at(1).toLower(); + } + else + { + return QString(); + } +} + +QString TranslationClass::getCountryCode(QLocale locale) +{ + QStringList localeStrList = locale.name().split("_"); + if (localeStrList.length() <= 2) + { + return localeStrList.at(1).toLower(); + } + else + { + return QString(); + } +} diff --git a/TranslationClass.h b/TranslationClass.h new file mode 100644 index 0000000..4ad4242 --- /dev/null +++ b/TranslationClass.h @@ -0,0 +1,63 @@ +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef TRANSLATIONCLASS_H +#define TRANSLATIONCLASS_H + +#include <QApplication> +#include <QTranslator> +#include <QStringList> +#include <QString> +#include <QObject> +#include <QLocale> + +class TranslationClass : public QObject +{ + Q_OBJECT +public: + static TranslationClass* getInstance() { return &translationClassInstance; } + static QString getCountryCode(QLocale::Country country); + static QString getCountryCode(QLocale locale); + void initUserLanguage(); + void loadTranslation(QApplication *app); + void unloadTranslation(QApplication *app); + QStringList listTranslations(const QString &langPath); + QString getCurrentLanguage(); + bool isLanguageLoaded(); + +private: + static TranslationClass translationClassInstance; + bool loadSystemTranslation_p(const QString &langPath, QTranslator *appTranslator); + bool loadUserTranslation_p(const QString &langPath, QTranslator *appTranslator); + bool loadQtTranslation_p(const QString &langPath, QTranslator *qtTranslator); + bool isUserLanguageSystem_p(); + QTranslator exAppTranslator; + QTranslator exQtTranslator; + QTranslator inAppTranslator; + QTranslator inQtTranslator; + QString currentLanguage; + QString userLanguage; + int currentLangIndex; + bool isLangLoaded; +}; + +extern TranslationClass translationClass; + +#define TCInstance TranslationClass::getInstance() + +#endif // TRANSLATIONCLASS_H diff --git a/UserInterface.cpp b/UserInterface.cpp index b029c6e..e6c4cf0 100755 --- a/UserInterface.cpp +++ b/UserInterface.cpp @@ -1,529 +1,552 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "UserInterface.h" -#include "ui_UserInterface.h" -#include "ProfileInterface.h" -#include "SnapmaticPicture.h" -#include "SidebarGenerator.h" -#include "SavegameDialog.h" -#include "StandardPaths.h" -#include "OptionsDialog.h" -#include "PictureDialog.h" -#include "SavegameData.h" -#include "AboutDialog.h" -#include "IconLoader.h" -#include "AppEnv.h" -#include "config.h" -#include <QtGlobal> -#include <QStyleFactory> -#include <QFileDialog> -#include <QHBoxLayout> -#include <QSpacerItem> -#include <QPushButton> -#include <QMessageBox> -#include <QSettings> -#include <QFileInfo> -#include <QProcess> -#include <QDebug> -#include <QFile> -#include <QDir> -#include <QMap> - -UserInterface::UserInterface(ProfileDatabase *profileDB, CrewDatabase *crewDB, DatabaseThread *threadDB, QWidget *parent) : - QMainWindow(parent), profileDB(profileDB), crewDB(crewDB), threadDB(threadDB), - ui(new Ui::UserInterface) -{ - ui->setupUi(this); - contentMode = 0; - profileOpen = 0; - profileUI = 0; - ui->menuProfile->setEnabled(false); - ui->actionSelect_profile->setEnabled(false); - ui->actionAbout_gta5sync->setIcon(IconLoader::loadingAppIcon()); - ui->actionAbout_gta5sync->setText(tr("&About %1").arg(GTA5SYNC_APPSTR)); - defaultWindowTitle = tr("%2 - %1").arg("%1", GTA5SYNC_APPSTR); - - this->setWindowTitle(defaultWindowTitle.arg(tr("Select Profile"))); - ui->labVersion->setText(ui->labVersion->text().arg(GTA5SYNC_APPSTR, GTA5SYNC_APPVER)); - - if (QIcon::hasThemeIcon("dialog-close")) - { - ui->cmdClose->setIcon(QIcon::fromTheme("dialog-close")); - } - if (QIcon::hasThemeIcon("preferences-system")) - { -#ifndef Q_OS_MACOS // Setting icon for preferences/settings/options lead to a crash in Mac OS X - ui->actionOptions->setIcon(QIcon::fromTheme("preferences-system")); -#endif - } - if (QIcon::hasThemeIcon("application-exit")) - { -#ifndef Q_OS_MACOS // Setting icon for exit/quit lead to a crash in Mac OS X - ui->actionExit->setIcon(QIcon::fromTheme("application-exit")); -#endif - } - - // DPI calculation - qreal screenRatio = AppEnv::screenRatio(); - resize(625 * screenRatio, 500 * screenRatio); - ui->vlUserInterface->setSpacing(6 * screenRatio); - ui->vlUserInterface->setContentsMargins(9 * screenRatio, 9 * screenRatio, 9 * screenRatio, 9 * screenRatio); -} - -void UserInterface::setupDirEnv() -{ - // settings init - QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); - - bool folderExists; - GTAV_Folder = AppEnv::getGameFolder(&folderExists); - if (folderExists) - { - QDir::setCurrent(GTAV_Folder); - } - else - { - GTAV_Folder = QFileDialog::getExistingDirectory(this, tr("Select GTA V Folder..."), StandardPaths::documentsLocation(), QFileDialog::ShowDirsOnly); - if (QFileInfo(GTAV_Folder).exists()) - { - folderExists = true; - QDir::setCurrent(GTAV_Folder); - AppEnv::setGameFolder(GTAV_Folder); - - // First time folder selection save - settings.beginGroup("dir"); - if (settings.value("dir", "").toString().isEmpty()) - { - settings.setValue("dir", GTAV_Folder); - } - settings.endGroup(); - } - } - - // profiles init - settings.beginGroup("Profile"); - QString defaultProfile = settings.value("Default", "").toString(); - - bool contentModeOk; - contentMode = settings.value("ContentMode", 0).toInt(&contentModeOk); - if (contentMode != 0 && contentMode != 1 && contentMode != 2) - { - contentMode = 0; - } - - if (folderExists) - { - QDir GTAV_ProfilesDir; - GTAV_ProfilesFolder = GTAV_Folder + QDir::separator() + "Profiles"; - GTAV_ProfilesDir.setPath(GTAV_ProfilesFolder); - - GTAV_Profiles = GTAV_ProfilesDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::NoSort); - setupProfileUi(); - - if (GTAV_Profiles.length() == 1) - { - openProfile(GTAV_Profiles.at(0)); - } - else if(GTAV_Profiles.contains(defaultProfile)) - { - openProfile(defaultProfile); - } - } - else - { - GTAV_Profiles = QStringList(); - setupProfileUi(); - } - settings.endGroup(); -} - -void UserInterface::setupProfileUi() -{ - qreal screenRatio = AppEnv::screenRatio(); - if (GTAV_Profiles.length() == 0) - { - QPushButton *changeDirBtn = new QPushButton(tr("Select >A V Folder..."), ui->swSelection); - changeDirBtn->setObjectName("cmdChangeDir"); - changeDirBtn->setMinimumSize(0, 40 * screenRatio); - changeDirBtn->setAutoDefault(true); - ui->vlButtons->addWidget(changeDirBtn); - profileBtns.append(changeDirBtn); - - QObject::connect(changeDirBtn, SIGNAL(clicked(bool)), this, SLOT(changeFolder_clicked())); - } - else foreach(const QString >AV_Profile, GTAV_Profiles) - { - QPushButton *profileBtn = new QPushButton(GTAV_Profile, ui->swSelection); - profileBtn->setObjectName(GTAV_Profile); - profileBtn->setMinimumSize(0, 40 * screenRatio); - profileBtn->setAutoDefault(true); - ui->vlButtons->addWidget(profileBtn); - profileBtns.append(profileBtn); - - QObject::connect(profileBtn, SIGNAL(clicked(bool)), this, SLOT(profileButton_clicked())); - } - profileBtns.at(0)->setFocus(); -} - -void UserInterface::changeFolder_clicked() -{ - on_actionSelect_GTA_Folder_triggered(); -} - -void UserInterface::on_cmdReload_clicked() -{ - foreach(QPushButton *profileBtn, profileBtns) - { - ui->vlButtons->removeWidget(profileBtn); - profileBtns.removeAll(profileBtn); - delete profileBtn; - } - setupDirEnv(); -} - -void UserInterface::profileButton_clicked() -{ - QPushButton *profileBtn = (QPushButton*)sender(); - openProfile(profileBtn->objectName()); -} - -void UserInterface::openProfile(QString profileName) -{ - profileOpen = true; - profileUI = new ProfileInterface(profileDB, crewDB, threadDB); - ui->swProfile->addWidget(profileUI); - ui->swProfile->setCurrentWidget(profileUI); - profileUI->setProfileFolder(GTAV_ProfilesFolder + QDir::separator() + profileName, profileName); - profileUI->settingsApplied(contentMode, language); - profileUI->setupProfileInterface(); - QObject::connect(profileUI, SIGNAL(profileClosed()), this, SLOT(closeProfile())); - QObject::connect(profileUI, SIGNAL(profileLoaded()), this, SLOT(profileLoaded())); - this->setWindowTitle(defaultWindowTitle.arg(profileName)); -} - -void UserInterface::closeProfile() -{ - if (profileOpen) - { - profileOpen = false; - ui->menuProfile->setEnabled(false); - ui->actionSelect_profile->setEnabled(false); - ui->swProfile->removeWidget(profileUI); - delete profileUI; - } - this->setWindowTitle(defaultWindowTitle.arg(tr("Select Profile"))); -} - -void UserInterface::closeEvent(QCloseEvent *ev) -{ - Q_UNUSED(ev) - threadDB->doEndThread(); -} - -UserInterface::~UserInterface() -{ - foreach (QPushButton *profileBtn, profileBtns) - { - delete profileBtn; - } - delete ui; -} - -void UserInterface::on_actionExit_triggered() -{ - this->close(); -} - -void UserInterface::on_actionSelect_profile_triggered() -{ - closeProfile(); - openSelectProfile(); -} - -void UserInterface::openSelectProfile() -{ - // not needed right now -} - -void UserInterface::on_actionAbout_gta5sync_triggered() -{ - AboutDialog *aboutDialog = new AboutDialog(this); - aboutDialog->setWindowIcon(windowIcon()); - aboutDialog->setModal(true); -#ifdef Q_OS_ANDROID - // Android ... - aboutDialog->showMaximized(); -#else - aboutDialog->show(); -#endif - aboutDialog->exec(); - delete aboutDialog; -} - -void UserInterface::profileLoaded() -{ - ui->menuProfile->setEnabled(true); - ui->actionSelect_profile->setEnabled(true); -} - -void UserInterface::on_actionSelect_all_triggered() -{ - if (profileOpen) - { - profileUI->selectAllWidgets(); - } -} - -void UserInterface::on_actionDeselect_all_triggered() -{ - if (profileOpen) - { - profileUI->deselectAllWidgets(); - } -} - -void UserInterface::on_actionExport_selected_triggered() -{ - if (profileOpen) - { - profileUI->exportSelected(); - } -} - -void UserInterface::on_actionDelete_selected_triggered() -{ - if (profileOpen) - { - profileUI->deleteSelected(); - } -} - -void UserInterface::on_actionOptions_triggered() -{ - OptionsDialog *optionsDialog = new OptionsDialog(profileDB, this); - optionsDialog->setWindowIcon(windowIcon()); - optionsDialog->commitProfiles(GTAV_Profiles); - QObject::connect(optionsDialog, SIGNAL(settingsApplied(int, QString)), this, SLOT(settingsApplied(int, QString))); - - optionsDialog->setModal(true); -#ifdef Q_OS_ANDROID - // Android ... - optionsDialog->showMaximized(); -#else - optionsDialog->show(); -#endif - optionsDialog->exec(); - - delete optionsDialog; -} - -void UserInterface::on_action_Import_triggered() -{ - if (profileOpen) - { - profileUI->importFiles(); - } -} - -void UserInterface::on_actionOpen_File_triggered() -{ - QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); - settings.beginGroup("FileDialogs"); - -fileDialogPreOpen: - QFileDialog fileDialog(this); - fileDialog.setFileMode(QFileDialog::ExistingFiles); - fileDialog.setViewMode(QFileDialog::Detail); - fileDialog.setAcceptMode(QFileDialog::AcceptOpen); - fileDialog.setOption(QFileDialog::DontUseNativeDialog, false); - fileDialog.setWindowFlags(fileDialog.windowFlags()^Qt::WindowContextHelpButtonHint); - fileDialog.setWindowTitle(tr("Open File...")); - - QStringList filters; - filters << ProfileInterface::tr("All profile files (*.g5e SGTA* PGTA*)"); - filters << ProfileInterface::tr("GTA V Export (*.g5e)"); - filters << ProfileInterface::tr("Savegames files (SGTA*)"); - filters << ProfileInterface::tr("Snapmatic pictures (PGTA*)"); - filters << ProfileInterface::tr("All files (**)"); - fileDialog.setNameFilters(filters); - - QList<QUrl> sidebarUrls = SidebarGenerator::generateSidebarUrls(fileDialog.sidebarUrls()); - - fileDialog.setSidebarUrls(sidebarUrls); - fileDialog.setDirectory(settings.value("OpenDialogDirectory", StandardPaths::documentsLocation()).toString()); - fileDialog.restoreGeometry(settings.value("OpenDialogGeometry","").toByteArray()); - - if (fileDialog.exec()) - { - QStringList selectedFiles = fileDialog.selectedFiles(); - if (selectedFiles.length() == 1) - { - QString selectedFile = selectedFiles.at(0); - if (!openFile(selectedFile, true)) goto fileDialogPreOpen; - } - } - - settings.setValue("OpenDialogGeometry", fileDialog.saveGeometry()); - settings.setValue("OpenDialogDirectory", fileDialog.directory().absolutePath()); - settings.endGroup(); -} - -bool UserInterface::openFile(QString selectedFile, bool warn) -{ - QString selectedFileName = QFileInfo(selectedFile).fileName(); - if (QFile::exists(selectedFile)) - { - if (selectedFileName.left(4) == "PGTA" || selectedFileName.right(4) == ".g5e") - { - SnapmaticPicture *picture = new SnapmaticPicture(selectedFile); - if (picture->readingPicture()) - { - openSnapmaticFile(picture); - delete picture; - return true; - } - else - { - if (warn) QMessageBox::warning(this, tr("Open File"), ProfileInterface::tr("Failed to read Snapmatic picture")); - delete picture; - return false; - } - } - else if (selectedFileName.left(4) == "SGTA") - { - SavegameData *savegame = new SavegameData(selectedFile); - if (savegame->readingSavegame()) - { - openSavegameFile(savegame); - delete savegame; - return true; - } - else - { - if (warn) QMessageBox::warning(this, tr("Open File"), ProfileInterface::tr("Failed to read Savegame file")); - delete savegame; - return false; - } - } - else - { - SnapmaticPicture *picture = new SnapmaticPicture(selectedFile); - SavegameData *savegame = new SavegameData(selectedFile); - if (picture->readingPicture()) - { - delete savegame; - openSnapmaticFile(picture); - delete picture; - return true; - } - else if (savegame->readingSavegame()) - { - delete picture; - openSavegameFile(savegame); - delete savegame; - return true; - } - else - { - delete savegame; - delete picture; - if (warn) QMessageBox::warning(this, tr("Open File"), tr("Can't open %1 because of not valid file format").arg("\""+selectedFileName+"\"")); - return false; - } - } - } - if (warn) QMessageBox::warning(this, tr("Open File"), ProfileInterface::tr("No valid file is selected")); - return false; -} - -void UserInterface::openSnapmaticFile(SnapmaticPicture *picture) -{ - PictureDialog picDialog(profileDB, crewDB, this); - picDialog.setSnapmaticPicture(picture, true); - picDialog.setModal(true); - - int crewID = picture->getSnapmaticProperties().crewID; - if (crewID != 0) { crewDB->addCrew(crewID); } - - QObject::connect(threadDB, SIGNAL(playerNameFound(int, QString)), profileDB, SLOT(setPlayerName(int, QString))); - QObject::connect(threadDB, SIGNAL(playerNameUpdated()), &picDialog, SLOT(playerNameUpdated())); - -#ifdef Q_OS_ANDROID - // Android optimization should be put here - picDialog.showMaximized(); -#else - picDialog.show(); - picDialog.setMinimumSize(picDialog.size()); - picDialog.setMaximumSize(picDialog.size()); -#endif - - picDialog.exec(); -} - -void UserInterface::openSavegameFile(SavegameData *savegame) -{ - SavegameDialog sgdDialog(this); - sgdDialog.setSavegameData(savegame, savegame->getSavegameFileName(), true); - sgdDialog.setModal(true); -#ifdef Q_OS_ANDROID - // Android optimization should be put here - sgdDialog.showMaximized(); -#else - sgdDialog.show(); -#endif - sgdDialog.exec(); -} - -void UserInterface::settingsApplied(int _contentMode, QString _language) -{ - language = _language; - contentMode = _contentMode; - if (profileOpen) - { - profileUI->settingsApplied(contentMode, language); - } -} - -void UserInterface::on_actionSelect_GTA_Folder_triggered() -{ - QString GTAV_Folder_Temp = QFileDialog::getExistingDirectory(this, tr("Select GTA V Folder..."), StandardPaths::documentsLocation(), QFileDialog::ShowDirsOnly); - if (QFileInfo(GTAV_Folder_Temp).exists()) - { - GTAV_Folder = GTAV_Folder_Temp; - QDir::setCurrent(GTAV_Folder); - AppEnv::setGameFolder(GTAV_Folder); - on_cmdReload_clicked(); - } -} - -void UserInterface::on_action_Enable_In_game_triggered() -{ - if (profileOpen) - { - profileUI->enableSelected(); - } -} - -void UserInterface::on_action_Disable_In_game_triggered() -{ - if (profileOpen) - { - profileUI->disableSelected(); - } -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "UserInterface.h" +#include "ui_UserInterface.h" +#include "ProfileInterface.h" +#include "SnapmaticPicture.h" +#include "SidebarGenerator.h" +#include "SavegameDialog.h" +#include "StandardPaths.h" +#include "OptionsDialog.h" +#include "PictureDialog.h" +#include "SavegameData.h" +#include "AboutDialog.h" +#include "IconLoader.h" +#include "AppEnv.h" +#include "config.h" +#include <QtGlobal> +#include <QStringBuilder> +#include <QStyleFactory> +#include <QFileDialog> +#include <QHBoxLayout> +#include <QSpacerItem> +#include <QPushButton> +#include <QMessageBox> +#include <QSettings> +#include <QFileInfo> +#include <QProcess> +#include <QDebug> +#include <QFile> +#include <QDir> +#include <QMap> + +UserInterface::UserInterface(ProfileDatabase *profileDB, CrewDatabase *crewDB, DatabaseThread *threadDB, QWidget *parent) : + QMainWindow(parent), profileDB(profileDB), crewDB(crewDB), threadDB(threadDB), + ui(new Ui::UserInterface) +{ + ui->setupUi(this); + contentMode = 0; + profileOpen = 0; + profileUI = 0; + ui->menuProfile->setEnabled(false); + ui->actionSelect_profile->setEnabled(false); + ui->actionAbout_gta5sync->setIcon(IconLoader::loadingAppIcon()); + ui->actionAbout_gta5sync->setText(tr("&About %1").arg(GTA5SYNC_APPSTR)); + ui->cmdClose->setToolTip(ui->cmdClose->toolTip().arg(GTA5SYNC_APPSTR)); + defaultWindowTitle = tr("%2 - %1").arg("%1", GTA5SYNC_APPSTR); + + this->setWindowTitle(defaultWindowTitle.arg(tr("Select Profile"))); + ui->labVersion->setText(QString("%1 %2").arg(GTA5SYNC_APPSTR, GTA5SYNC_APPVER)); + + if (QIcon::hasThemeIcon("dialog-close")) + { + ui->cmdClose->setIcon(QIcon::fromTheme("dialog-close")); + } + if (QIcon::hasThemeIcon("preferences-system")) + { +#ifndef Q_OS_MACOS // Setting icon for preferences/settings/options lead to a crash in Mac OS X + ui->actionOptions->setIcon(QIcon::fromTheme("preferences-system")); +#endif + } + if (QIcon::hasThemeIcon("application-exit")) + { +#ifndef Q_OS_MACOS // Setting icon for exit/quit lead to a crash in Mac OS X + ui->actionExit->setIcon(QIcon::fromTheme("application-exit")); +#endif + } + + // DPI calculation + qreal screenRatio = AppEnv::screenRatio(); + resize(625 * screenRatio, 500 * screenRatio); + ui->vlUserInterface->setSpacing(6 * screenRatio); + ui->vlUserInterface->setContentsMargins(9 * screenRatio, 9 * screenRatio, 9 * screenRatio, 9 * screenRatio); +} + +void UserInterface::setupDirEnv() +{ + // settings init + QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); + + bool folderExists; + GTAV_Folder = AppEnv::getGameFolder(&folderExists); + if (folderExists) + { + QDir::setCurrent(GTAV_Folder); + } + else + { + GTAV_Folder = QFileDialog::getExistingDirectory(this, tr("Select GTA V Folder..."), StandardPaths::documentsLocation(), QFileDialog::ShowDirsOnly); + if (QFileInfo(GTAV_Folder).exists()) + { + folderExists = true; + QDir::setCurrent(GTAV_Folder); + AppEnv::setGameFolder(GTAV_Folder); + + // First time folder selection save + settings.beginGroup("dir"); + if (settings.value("dir", "").toString().isEmpty()) + { + settings.setValue("dir", GTAV_Folder); + } + settings.endGroup(); + } + } + + // profiles init + settings.beginGroup("Profile"); + QString defaultProfile = settings.value("Default", "").toString(); + + bool contentModeOk; + contentMode = settings.value("ContentMode", 0).toInt(&contentModeOk); + if (contentMode != 0 && contentMode != 1 && contentMode != 2) + { + contentMode = 0; + } + + if (folderExists) + { + QDir GTAV_ProfilesDir; + GTAV_ProfilesFolder = GTAV_Folder % QDir::separator() % "Profiles"; + GTAV_ProfilesDir.setPath(GTAV_ProfilesFolder); + + GTAV_Profiles = GTAV_ProfilesDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::NoSort); + setupProfileUi(); + + if (GTAV_Profiles.length() == 1) + { + openProfile(GTAV_Profiles.at(0)); + } + else if(GTAV_Profiles.contains(defaultProfile)) + { + openProfile(defaultProfile); + } + } + else + { + GTAV_Profiles = QStringList(); + setupProfileUi(); + } + settings.endGroup(); +} + +void UserInterface::setupProfileUi() +{ + qreal screenRatio = AppEnv::screenRatio(); + if (GTAV_Profiles.length() == 0) + { + QPushButton *changeDirBtn = new QPushButton(tr("Select >A V Folder..."), ui->swSelection); + changeDirBtn->setObjectName("cmdChangeDir"); + changeDirBtn->setMinimumSize(0, 40 * screenRatio); + changeDirBtn->setAutoDefault(true); + ui->vlButtons->addWidget(changeDirBtn); + profileBtns += changeDirBtn; + + QObject::connect(changeDirBtn, SIGNAL(clicked(bool)), this, SLOT(changeFolder_clicked())); + } + else foreach(const QString >AV_Profile, GTAV_Profiles) + { + QPushButton *profileBtn = new QPushButton(GTAV_Profile, ui->swSelection); + profileBtn->setObjectName(GTAV_Profile); + profileBtn->setMinimumSize(0, 40 * screenRatio); + profileBtn->setAutoDefault(true); + ui->vlButtons->addWidget(profileBtn); + profileBtns += profileBtn; + + QObject::connect(profileBtn, SIGNAL(clicked(bool)), this, SLOT(profileButton_clicked())); + } + profileBtns.at(0)->setFocus(); +} + +void UserInterface::changeFolder_clicked() +{ + on_actionSelect_GTA_Folder_triggered(); +} + +void UserInterface::on_cmdReload_clicked() +{ + foreach(QPushButton *profileBtn, profileBtns) + { + ui->vlButtons->removeWidget(profileBtn); + profileBtns.removeAll(profileBtn); + delete profileBtn; + } + setupDirEnv(); +} + +void UserInterface::profileButton_clicked() +{ + QPushButton *profileBtn = (QPushButton*)sender(); + openProfile(profileBtn->objectName()); +} + +void UserInterface::openProfile(const QString &profileName_) +{ + profileOpen = true; + profileName = profileName_; + profileUI = new ProfileInterface(profileDB, crewDB, threadDB); + ui->swProfile->addWidget(profileUI); + ui->swProfile->setCurrentWidget(profileUI); + profileUI->setProfileFolder(GTAV_ProfilesFolder % QDir::separator() % profileName, profileName); + profileUI->settingsApplied(contentMode, language); + profileUI->setupProfileInterface(); + QObject::connect(profileUI, SIGNAL(profileClosed()), this, SLOT(closeProfile())); + QObject::connect(profileUI, SIGNAL(profileLoaded()), this, SLOT(profileLoaded())); + this->setWindowTitle(defaultWindowTitle.arg(profileName)); +} + +void UserInterface::closeProfile() +{ + if (profileOpen) + { + profileOpen = false; + profileName.clear(); + ui->menuProfile->setEnabled(false); + ui->actionSelect_profile->setEnabled(false); + ui->swProfile->removeWidget(profileUI); + delete profileUI; + } + this->setWindowTitle(defaultWindowTitle.arg(tr("Select Profile"))); +} + +void UserInterface::closeEvent(QCloseEvent *ev) +{ + Q_UNUSED(ev) + threadDB->doEndThread(); +} + +UserInterface::~UserInterface() +{ + foreach (QPushButton *profileBtn, profileBtns) + { + delete profileBtn; + } + delete ui; +} + +void UserInterface::on_actionExit_triggered() +{ + this->close(); +} + +void UserInterface::on_actionSelect_profile_triggered() +{ + closeProfile(); + openSelectProfile(); +} + +void UserInterface::openSelectProfile() +{ + // not needed right now +} + +void UserInterface::on_actionAbout_gta5sync_triggered() +{ + AboutDialog *aboutDialog = new AboutDialog(this); + aboutDialog->setWindowIcon(windowIcon()); + aboutDialog->setModal(true); +#ifdef Q_OS_ANDROID + // Android ... + aboutDialog->showMaximized(); +#else + aboutDialog->show(); +#endif + aboutDialog->exec(); + delete aboutDialog; +} + +void UserInterface::profileLoaded() +{ + ui->menuProfile->setEnabled(true); + ui->actionSelect_profile->setEnabled(true); +} + +void UserInterface::on_actionSelect_all_triggered() +{ + if (profileOpen) + { + profileUI->selectAllWidgets(); + } +} + +void UserInterface::on_actionDeselect_all_triggered() +{ + if (profileOpen) + { + profileUI->deselectAllWidgets(); + } +} + +void UserInterface::on_actionExport_selected_triggered() +{ + if (profileOpen) + { + profileUI->exportSelected(); + } +} + +void UserInterface::on_actionDelete_selected_triggered() +{ + if (profileOpen) + { + profileUI->deleteSelected(); + } +} + +void UserInterface::on_actionOptions_triggered() +{ + OptionsDialog *optionsDialog = new OptionsDialog(profileDB, this); + optionsDialog->setWindowIcon(windowIcon()); + optionsDialog->commitProfiles(GTAV_Profiles); + QObject::connect(optionsDialog, SIGNAL(settingsApplied(int, QString)), this, SLOT(settingsApplied(int, QString))); + + optionsDialog->setModal(true); +#ifdef Q_OS_ANDROID + // Android ... + optionsDialog->showMaximized(); +#else + optionsDialog->show(); +#endif + optionsDialog->exec(); + + delete optionsDialog; +} + +void UserInterface::on_action_Import_triggered() +{ + if (profileOpen) + { + profileUI->importFiles(); + } +} + +void UserInterface::on_actionOpen_File_triggered() +{ + QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); + settings.beginGroup("FileDialogs"); + +fileDialogPreOpen: + QFileDialog fileDialog(this); + fileDialog.setFileMode(QFileDialog::ExistingFiles); + fileDialog.setViewMode(QFileDialog::Detail); + fileDialog.setAcceptMode(QFileDialog::AcceptOpen); + fileDialog.setOption(QFileDialog::DontUseNativeDialog, false); + fileDialog.setWindowFlags(fileDialog.windowFlags()^Qt::WindowContextHelpButtonHint); + fileDialog.setWindowTitle(tr("Open File...")); + + QStringList filters; + filters << ProfileInterface::tr("All profile files (*.g5e SGTA* PGTA*)"); + filters << ProfileInterface::tr("GTA V Export (*.g5e)"); + filters << ProfileInterface::tr("Savegames files (SGTA*)"); + filters << ProfileInterface::tr("Snapmatic pictures (PGTA*)"); + filters << ProfileInterface::tr("All files (**)"); + fileDialog.setNameFilters(filters); + + QList<QUrl> sidebarUrls = SidebarGenerator::generateSidebarUrls(fileDialog.sidebarUrls()); + + fileDialog.setSidebarUrls(sidebarUrls); + fileDialog.setDirectory(settings.value("OpenDialogDirectory", StandardPaths::documentsLocation()).toString()); + fileDialog.restoreGeometry(settings.value("OpenDialogGeometry","").toByteArray()); + + if (fileDialog.exec()) + { + QStringList selectedFiles = fileDialog.selectedFiles(); + if (selectedFiles.length() == 1) + { + QString selectedFile = selectedFiles.at(0); + if (!openFile(selectedFile, true)) goto fileDialogPreOpen; + } + } + + settings.setValue("OpenDialogGeometry", fileDialog.saveGeometry()); + settings.setValue("OpenDialogDirectory", fileDialog.directory().absolutePath()); + settings.endGroup(); +} + +bool UserInterface::openFile(QString selectedFile, bool warn) +{ + QString selectedFileName = QFileInfo(selectedFile).fileName(); + if (QFile::exists(selectedFile)) + { + if (selectedFileName.left(4) == "PGTA" || selectedFileName.right(4) == ".g5e") + { + SnapmaticPicture *picture = new SnapmaticPicture(selectedFile); + if (picture->readingPicture()) + { + openSnapmaticFile(picture); + delete picture; + return true; + } + else + { + if (warn) QMessageBox::warning(this, tr("Open File"), ProfileInterface::tr("Failed to read Snapmatic picture")); + delete picture; + return false; + } + } + else if (selectedFileName.left(4) == "SGTA") + { + SavegameData *savegame = new SavegameData(selectedFile); + if (savegame->readingSavegame()) + { + openSavegameFile(savegame); + delete savegame; + return true; + } + else + { + if (warn) QMessageBox::warning(this, tr("Open File"), ProfileInterface::tr("Failed to read Savegame file")); + delete savegame; + return false; + } + } + else + { + SnapmaticPicture *picture = new SnapmaticPicture(selectedFile); + SavegameData *savegame = new SavegameData(selectedFile); + if (picture->readingPicture()) + { + delete savegame; + openSnapmaticFile(picture); + delete picture; + return true; + } + else if (savegame->readingSavegame()) + { + delete picture; + openSavegameFile(savegame); + delete savegame; + return true; + } + else + { + delete savegame; + delete picture; + if (warn) QMessageBox::warning(this, tr("Open File"), tr("Can't open %1 because of not valid file format").arg("\""+selectedFileName+"\"")); + return false; + } + } + } + if (warn) QMessageBox::warning(this, tr("Open File"), ProfileInterface::tr("No valid file is selected")); + return false; +} + +void UserInterface::openSnapmaticFile(SnapmaticPicture *picture) +{ + PictureDialog picDialog(profileDB, crewDB, this); + picDialog.setSnapmaticPicture(picture, true); + picDialog.setModal(true); + + int crewID = picture->getSnapmaticProperties().crewID; + if (crewID != 0) { crewDB->addCrew(crewID); } + + QObject::connect(threadDB, SIGNAL(crewNameUpdated()), &picDialog, SLOT(crewNameUpdated())); + QObject::connect(threadDB, SIGNAL(playerNameUpdated()), &picDialog, SLOT(playerNameUpdated())); + +#ifdef Q_OS_ANDROID + // Android optimization should be put here + picDialog.showMaximized(); +#else + picDialog.show(); + picDialog.setMinimumSize(picDialog.size()); + picDialog.setMaximumSize(picDialog.size()); +#endif + + picDialog.exec(); +} + +void UserInterface::openSavegameFile(SavegameData *savegame) +{ + SavegameDialog sgdDialog(this); + sgdDialog.setSavegameData(savegame, savegame->getSavegameFileName(), true); + sgdDialog.setModal(true); +#ifdef Q_OS_ANDROID + // Android optimization should be put here + sgdDialog.showMaximized(); +#else + sgdDialog.show(); +#endif + sgdDialog.exec(); +} + +void UserInterface::settingsApplied(int _contentMode, QString _language) +{ + if (language != _language) + { + retranslateUi(); + language = _language; + } + contentMode = _contentMode; + if (profileOpen) + { + profileUI->settingsApplied(contentMode, language); + } +} + +void UserInterface::on_actionSelect_GTA_Folder_triggered() +{ + QString GTAV_Folder_Temp = QFileDialog::getExistingDirectory(this, tr("Select GTA V Folder..."), StandardPaths::documentsLocation(), QFileDialog::ShowDirsOnly); + if (QFileInfo(GTAV_Folder_Temp).exists()) + { + GTAV_Folder = GTAV_Folder_Temp; + QDir::setCurrent(GTAV_Folder); + AppEnv::setGameFolder(GTAV_Folder); + on_cmdReload_clicked(); + } +} + +void UserInterface::on_action_Enable_In_game_triggered() +{ + if (profileOpen) + { + profileUI->enableSelected(); + } +} + +void UserInterface::on_action_Disable_In_game_triggered() +{ + if (profileOpen) + { + profileUI->disableSelected(); + } +} + +void UserInterface::retranslateUi() +{ + ui->retranslateUi(this); + ui->actionAbout_gta5sync->setText(tr("&About %1").arg(GTA5SYNC_APPSTR)); + ui->labVersion->setText(QString("%1 %2").arg(GTA5SYNC_APPSTR, GTA5SYNC_APPVER)); + if (profileOpen) + { + this->setWindowTitle(defaultWindowTitle.arg(profileName)); + } + else + { + this->setWindowTitle(defaultWindowTitle.arg(tr("Select Profile"))); + } +} diff --git a/UserInterface.h b/UserInterface.h index 028cf6e..0ce9e7c 100755 --- a/UserInterface.h +++ b/UserInterface.h @@ -1,93 +1,96 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef USERINTERFACE_H -#define USERINTERFACE_H - -#include "SnapmaticPicture.h" -#include "ProfileInterface.h" -#include "ProfileDatabase.h" -#include "DatabaseThread.h" -#include "CrewDatabase.h" -#include "SavegameData.h" -#include <QMainWindow> -#include <QCloseEvent> -#include <QString> -#include <QMap> - -namespace Ui { -class UserInterface; -} - -class UserInterface : public QMainWindow -{ - Q_OBJECT -public: - explicit UserInterface(ProfileDatabase *profileDB, CrewDatabase *crewDB, DatabaseThread *threadDB, QWidget *parent = 0); - void setupDirEnv(); - ~UserInterface(); - -private slots: - void closeProfile(); - void profileLoaded(); - void changeFolder_clicked(); - void profileButton_clicked(); - void on_cmdReload_clicked(); - void on_actionExit_triggered(); - void on_actionSelect_profile_triggered(); - void on_actionAbout_gta5sync_triggered(); - void on_actionSelect_all_triggered(); - void on_actionDeselect_all_triggered(); - void on_actionExport_selected_triggered(); - void on_actionDelete_selected_triggered(); - void on_actionOptions_triggered(); - void on_action_Import_triggered(); - void on_actionOpen_File_triggered(); - void on_actionSelect_GTA_Folder_triggered(); - void on_action_Enable_In_game_triggered(); - void on_action_Disable_In_game_triggered(); - void settingsApplied(int contentMode, QString language); - -protected: - void closeEvent(QCloseEvent *ev); - -private: - ProfileDatabase *profileDB; - CrewDatabase *crewDB; - DatabaseThread *threadDB; - Ui::UserInterface *ui; - ProfileInterface *profileUI; - QList<QPushButton*> profileBtns; - bool profileOpen; - int contentMode; - QString language; - QString defaultWindowTitle; - QString GTAV_Folder; - QString GTAV_ProfilesFolder; - QStringList GTAV_Profiles; - void setupProfileUi(); - void openProfile(QString profileName); - void openSelectProfile(); - - // Open File - bool openFile(QString selectedFile, bool warn = true); - void openSavegameFile(SavegameData *savegame); - void openSnapmaticFile(SnapmaticPicture *picture); -}; - -#endif // USERINTERFACE_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef USERINTERFACE_H +#define USERINTERFACE_H + +#include "SnapmaticPicture.h" +#include "ProfileInterface.h" +#include "ProfileDatabase.h" +#include "DatabaseThread.h" +#include "CrewDatabase.h" +#include "SavegameData.h" +#include <QMainWindow> +#include <QMouseEvent> +#include <QCloseEvent> +#include <QString> +#include <QMap> + +namespace Ui { +class UserInterface; +} + +class UserInterface : public QMainWindow +{ + Q_OBJECT +public: + explicit UserInterface(ProfileDatabase *profileDB, CrewDatabase *crewDB, DatabaseThread *threadDB, QWidget *parent = 0); + void setupDirEnv(); + ~UserInterface(); + +private slots: + void closeProfile(); + void profileLoaded(); + void changeFolder_clicked(); + void profileButton_clicked(); + void on_cmdReload_clicked(); + void on_actionExit_triggered(); + void on_actionSelect_profile_triggered(); + void on_actionAbout_gta5sync_triggered(); + void on_actionSelect_all_triggered(); + void on_actionDeselect_all_triggered(); + void on_actionExport_selected_triggered(); + void on_actionDelete_selected_triggered(); + void on_actionOptions_triggered(); + void on_action_Import_triggered(); + void on_actionOpen_File_triggered(); + void on_actionSelect_GTA_Folder_triggered(); + void on_action_Enable_In_game_triggered(); + void on_action_Disable_In_game_triggered(); + void settingsApplied(int contentMode, QString language); + +protected: + void closeEvent(QCloseEvent *ev); + +private: + ProfileDatabase *profileDB; + CrewDatabase *crewDB; + DatabaseThread *threadDB; + Ui::UserInterface *ui; + ProfileInterface *profileUI; + QList<QPushButton*> profileBtns; + QString profileName; + bool profileOpen; + int contentMode; + QString language; + QString defaultWindowTitle; + QString GTAV_Folder; + QString GTAV_ProfilesFolder; + QStringList GTAV_Profiles; + void setupProfileUi(); + void openProfile(const QString &profileName); + void openSelectProfile(); + void retranslateUi(); + + // Open File + bool openFile(QString selectedFile, bool warn = true); + void openSavegameFile(SavegameData *savegame); + void openSnapmaticFile(SnapmaticPicture *picture); +}; + +#endif // USERINTERFACE_H diff --git a/UserInterface.ui b/UserInterface.ui index 5a34fce..9e2ab52 100755 --- a/UserInterface.ui +++ b/UserInterface.ui @@ -1,348 +1,354 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>UserInterface</class> - <widget class="QMainWindow" name="UserInterface"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>625</width> - <height>500</height> - </rect> - </property> - <property name="minimumSize"> - <size> - <width>625</width> - <height>500</height> - </size> - </property> - <property name="windowTitle"> - <string>%2 - %1</string> - </property> - <widget class="QWidget" name="cwUI"> - <layout class="QVBoxLayout" name="vlUI"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QStackedWidget" name="swProfile"> - <property name="lineWidth"> - <number>0</number> - </property> - <widget class="QWidget" name="swSelection"> - <layout class="QVBoxLayout" name="vlUserInterface"> - <property name="spacing"> - <number>6</number> - </property> - <property name="leftMargin"> - <number>9</number> - </property> - <property name="topMargin"> - <number>9</number> - </property> - <property name="rightMargin"> - <number>9</number> - </property> - <property name="bottomMargin"> - <number>9</number> - </property> - <item> - <spacer name="vsUpper"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="labSelectProfile"> - <property name="text"> - <string>Select profile</string> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <layout class="QVBoxLayout" name="vlButtons"/> - </item> - <item> - <spacer name="vsFooter"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <layout class="QHBoxLayout" name="hlButtons"> - <item> - <widget class="QLabel" name="labVersion"> - <property name="text"> - <string>%1 %2</string> - </property> - </widget> - </item> - <item> - <spacer name="hsButtons"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="cmdReload"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>&Reload</string> - </property> - <property name="autoDefault"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="cmdClose"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>&Close</string> - </property> - <property name="autoDefault"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - </widget> - </item> - </layout> - </widget> - <widget class="QMenuBar" name="menuBar"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>625</width> - <height>21</height> - </rect> - </property> - <widget class="QMenu" name="menuFile"> - <property name="title"> - <string>&File</string> - </property> - <addaction name="actionSelect_GTA_Folder"/> - <addaction name="actionOpen_File"/> - <addaction name="actionSelect_profile"/> - <addaction name="separator"/> - <addaction name="actionExit"/> - </widget> - <widget class="QMenu" name="menuHelp"> - <property name="title"> - <string>&Help</string> - </property> - <addaction name="actionAbout_gta5sync"/> - </widget> - <widget class="QMenu" name="menuEdit"> - <property name="title"> - <string>&Edit</string> - </property> - <addaction name="actionOptions"/> - </widget> - <widget class="QMenu" name="menuProfile"> - <property name="title"> - <string>&Profile</string> - </property> - <widget class="QMenu" name="menuSelection_visibility"> - <property name="title"> - <string>&Selection visibility</string> - </property> - <addaction name="action_Enable_In_game"/> - <addaction name="action_Disable_In_game"/> - </widget> - <addaction name="action_Import"/> - <addaction name="actionExport_selected"/> - <addaction name="actionDelete_selected"/> - <addaction name="separator"/> - <addaction name="menuSelection_visibility"/> - <addaction name="separator"/> - <addaction name="actionSelect_all"/> - <addaction name="actionDeselect_all"/> - </widget> - <addaction name="menuFile"/> - <addaction name="menuEdit"/> - <addaction name="menuProfile"/> - <addaction name="menuHelp"/> - </widget> - <action name="actionAbout_gta5sync"> - <property name="text"> - <string>&About %1</string> - </property> - <property name="shortcut"> - <string>Ctrl+P</string> - </property> - </action> - <action name="actionExit"> - <property name="text"> - <string>&Exit</string> - </property> - <property name="toolTip"> - <string>Exit</string> - </property> - <property name="shortcut"> - <string>Ctrl+Q</string> - </property> - </action> - <action name="actionSelect_profile"> - <property name="text"> - <string>Close &Profile</string> - </property> - <property name="shortcut"> - <string>Ctrl+End</string> - </property> - </action> - <action name="actionOptions"> - <property name="text"> - <string>&Settings</string> - </property> - <property name="shortcut"> - <string>Ctrl+S</string> - </property> - </action> - <action name="actionSelect_all"> - <property name="text"> - <string>Select &All</string> - </property> - <property name="shortcut"> - <string>Ctrl+A</string> - </property> - </action> - <action name="actionDeselect_all"> - <property name="text"> - <string>&Deselect All</string> - </property> - <property name="shortcut"> - <string>Ctrl+D</string> - </property> - </action> - <action name="actionExport_selected"> - <property name="text"> - <string>&Export selected...</string> - </property> - <property name="shortcut"> - <string>Ctrl+E</string> - </property> - </action> - <action name="actionDelete_selected"> - <property name="text"> - <string>&Remove selected</string> - </property> - <property name="shortcut"> - <string>Ctrl+Del</string> - </property> - </action> - <action name="action_Import"> - <property name="text"> - <string>&Import files...</string> - </property> - <property name="shortcut"> - <string>Ctrl+I</string> - </property> - </action> - <action name="actionOpen_File"> - <property name="text"> - <string>&Open File...</string> - </property> - <property name="shortcut"> - <string>Ctrl+O</string> - </property> - </action> - <action name="actionSelect_GTA_Folder"> - <property name="text"> - <string>Select &GTA V Folder...</string> - </property> - <property name="toolTip"> - <string>Select GTA V Folder...</string> - </property> - <property name="shortcut"> - <string>Ctrl+G</string> - </property> - </action> - <action name="action_Enable_In_game"> - <property name="text"> - <string>Show In-gam&e</string> - </property> - <property name="shortcut"> - <string>Shift+E</string> - </property> - </action> - <action name="action_Disable_In_game"> - <property name="text"> - <string>Hi&de In-game</string> - </property> - <property name="shortcut"> - <string>Shift+D</string> - </property> - </action> - </widget> - <resources/> - <connections> - <connection> - <sender>cmdClose</sender> - <signal>clicked()</signal> - <receiver>UserInterface</receiver> - <slot>close()</slot> - <hints> - <hint type="sourcelabel"> - <x>572</x> - <y>476</y> - </hint> - <hint type="destinationlabel"> - <x>312</x> - <y>249</y> - </hint> - </hints> - </connection> - </connections> -</ui> +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>UserInterface</class> + <widget class="QMainWindow" name="UserInterface"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>625</width> + <height>500</height> + </rect> + </property> + <property name="minimumSize"> + <size> + <width>625</width> + <height>500</height> + </size> + </property> + <property name="windowTitle"> + <string>%2 - %1</string> + </property> + <widget class="QWidget" name="cwUI"> + <layout class="QVBoxLayout" name="vlUI"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QStackedWidget" name="swProfile"> + <property name="lineWidth"> + <number>0</number> + </property> + <widget class="QWidget" name="swSelection"> + <layout class="QVBoxLayout" name="vlUserInterface"> + <property name="spacing"> + <number>6</number> + </property> + <property name="leftMargin"> + <number>9</number> + </property> + <property name="topMargin"> + <number>9</number> + </property> + <property name="rightMargin"> + <number>9</number> + </property> + <property name="bottomMargin"> + <number>9</number> + </property> + <item> + <spacer name="vsUpper"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="labSelectProfile"> + <property name="text"> + <string>Select profile</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <layout class="QVBoxLayout" name="vlButtons"/> + </item> + <item> + <spacer name="vsFooter"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QHBoxLayout" name="hlButtons"> + <item> + <widget class="QLabel" name="labVersion"> + <property name="text"> + <string>%1 %2</string> + </property> + </widget> + </item> + <item> + <spacer name="hsButtons"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="cmdReload"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Reload profile overview</string> + </property> + <property name="text"> + <string>&Reload</string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="cmdClose"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string extracomment="Close %1 <- (gta5view/gta5sync) - %1 will be replaced automatically">Close %1</string> + </property> + <property name="text"> + <string>&Close</string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menuBar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>625</width> + <height>21</height> + </rect> + </property> + <widget class="QMenu" name="menuFile"> + <property name="title"> + <string>&File</string> + </property> + <addaction name="actionSelect_GTA_Folder"/> + <addaction name="actionOpen_File"/> + <addaction name="actionSelect_profile"/> + <addaction name="separator"/> + <addaction name="actionExit"/> + </widget> + <widget class="QMenu" name="menuHelp"> + <property name="title"> + <string>&Help</string> + </property> + <addaction name="actionAbout_gta5sync"/> + </widget> + <widget class="QMenu" name="menuEdit"> + <property name="title"> + <string>&Edit</string> + </property> + <addaction name="actionOptions"/> + </widget> + <widget class="QMenu" name="menuProfile"> + <property name="title"> + <string>&Profile</string> + </property> + <widget class="QMenu" name="menuSelection_visibility"> + <property name="title"> + <string>&Selection visibility</string> + </property> + <addaction name="action_Enable_In_game"/> + <addaction name="action_Disable_In_game"/> + </widget> + <addaction name="action_Import"/> + <addaction name="actionExport_selected"/> + <addaction name="actionDelete_selected"/> + <addaction name="separator"/> + <addaction name="menuSelection_visibility"/> + <addaction name="separator"/> + <addaction name="actionSelect_all"/> + <addaction name="actionDeselect_all"/> + </widget> + <addaction name="menuFile"/> + <addaction name="menuEdit"/> + <addaction name="menuProfile"/> + <addaction name="menuHelp"/> + </widget> + <action name="actionAbout_gta5sync"> + <property name="text"> + <string>&About %1</string> + </property> + <property name="shortcut"> + <string>Ctrl+P</string> + </property> + </action> + <action name="actionExit"> + <property name="text"> + <string>&Exit</string> + </property> + <property name="toolTip"> + <string>Exit</string> + </property> + <property name="shortcut"> + <string>Ctrl+Q</string> + </property> + </action> + <action name="actionSelect_profile"> + <property name="text"> + <string>Close &Profile</string> + </property> + <property name="shortcut"> + <string>Ctrl+End</string> + </property> + </action> + <action name="actionOptions"> + <property name="text"> + <string>&Settings</string> + </property> + <property name="shortcut"> + <string>Ctrl+S</string> + </property> + </action> + <action name="actionSelect_all"> + <property name="text"> + <string>Select &All</string> + </property> + <property name="shortcut"> + <string>Ctrl+A</string> + </property> + </action> + <action name="actionDeselect_all"> + <property name="text"> + <string>&Deselect All</string> + </property> + <property name="shortcut"> + <string>Ctrl+D</string> + </property> + </action> + <action name="actionExport_selected"> + <property name="text"> + <string>&Export selected...</string> + </property> + <property name="shortcut"> + <string>Ctrl+E</string> + </property> + </action> + <action name="actionDelete_selected"> + <property name="text"> + <string>&Remove selected</string> + </property> + <property name="shortcut"> + <string>Ctrl+Del</string> + </property> + </action> + <action name="action_Import"> + <property name="text"> + <string>&Import files...</string> + </property> + <property name="shortcut"> + <string>Ctrl+I</string> + </property> + </action> + <action name="actionOpen_File"> + <property name="text"> + <string>&Open File...</string> + </property> + <property name="shortcut"> + <string>Ctrl+O</string> + </property> + </action> + <action name="actionSelect_GTA_Folder"> + <property name="text"> + <string>Select &GTA V Folder...</string> + </property> + <property name="toolTip"> + <string>Select GTA V Folder...</string> + </property> + <property name="shortcut"> + <string>Ctrl+G</string> + </property> + </action> + <action name="action_Enable_In_game"> + <property name="text"> + <string>Show In-gam&e</string> + </property> + <property name="shortcut"> + <string>Shift+E</string> + </property> + </action> + <action name="action_Disable_In_game"> + <property name="text"> + <string>Hi&de In-game</string> + </property> + <property name="shortcut"> + <string>Shift+D</string> + </property> + </action> + </widget> + <resources/> + <connections> + <connection> + <sender>cmdClose</sender> + <signal>clicked()</signal> + <receiver>UserInterface</receiver> + <slot>close()</slot> + <hints> + <hint type="sourcelabel"> + <x>572</x> + <y>476</y> + </hint> + <hint type="destinationlabel"> + <x>312</x> + <y>249</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/config.h b/config.h index 25c313c..5e52fdf 100755 --- a/config.h +++ b/config.h @@ -1,101 +1,161 @@ -/***************************************************************************** -* gta5view Grand Theft Auto V Profile Viewer -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef CONFIG_H -#define CONFIG_H -#include <QString> - -#ifndef GTA5SYNC_APPVENDOR -#define GTA5SYNC_APPVENDOR "Syping" -#endif - -#ifndef GTA5SYNC_APPVENDORLINK -#define GTA5SYNC_APPVENDORLINK "https://github.com/Syping/" -#endif - -#ifndef GTA5SYNC_DISABLED -#define GTA5SYNC_ENABLED -#endif - -#ifndef GTA5SYNC_APPSTR -#ifdef GTA5SYNC_ENABLED -#define GTA5SYNC_APPSTR "gta5sync" -#else -#define GTA5SYNC_APPSTR "gta5view" -#endif -#endif - -#ifndef GTA5SYNC_APPDES -#define GTA5SYNC_APPDES "INSERT YOUR APPLICATION DESCRIPTION HERE" -#endif - -#ifndef GTA5SYNC_COPYRIGHT -#define GTA5SYNC_COPYRIGHT "2016-2017" -#endif - -#ifndef GTA5SYNC_APPVER -#ifndef GTA5SYNC_DAILYB -#define GTA5SYNC_APPVER "1.4.4" -#else -#define GTA5SYNC_APPVER QString("%1").arg(GTA5SYNC_DAILYB) -#endif -#endif - -#ifndef GTA5SYNC_BUILDTYPE -#define GTA5SYNC_BUILDTYPE "Custom" -#endif - -#ifndef GTA5SYNC_SHARE -#define GTA5SYNC_SHARE "$RUNDIR" -#endif - -#ifndef GTA5SYNC_LANG -#define GTA5SYNC_LANG "$SHAREDIR$SEPARATORlang" -#endif - -#ifndef GTA5SYNC_PLUG -#define GTA5SYNC_PLUG "$RUNDIR$SEPARATORplugins" -#endif - -#ifdef GTA5SYNC_WINRT -#undef GTA5SYNC_WIN -#endif - -#ifndef GTA5SYNC_COMPILER -#ifdef __clang__ -#define GTA5SYNC_COMPILER QString("Clang %1.%2.%3").arg(QString::number(__clang_major__), QString::number(__clang_minor__), QString::number(__clang_patchlevel__)) -#elif defined(__GNUC__) -#define GTA5SYNC_COMPILER QString("GCC %1.%2.%3").arg(QString::number(__GNUC__), QString::number(__GNUC_MINOR__), QString::number(__GNUC_PATCHLEVEL__)) -#elif defined(__GNUG__) -#define GTA5SYNC_COMPILER QString("GCC %1.%2.%3").arg(QString::number(__GNUG__), QString::number(__GNUC_MINOR__), QString::number(__GNUC_PATCHLEVEL__)) -#elif defined(_MSC_VER) -#define GTA5SYNC_COMPILER QString("MSVC %1").arg(QString::number(_MSC_VER).insert(2, ".")) -#else -#define GTA5SYNC_COMPILER QString("Unknown Compiler") -#endif -#endif - -#ifndef GTA5SYNC_BUILDDATETIME -#define GTA5SYNC_BUILDDATETIME QString("%1, %2").arg(__DATE__, __TIME__); -#endif - -#ifndef GTA5SYNC_BUILDSTRING -#define GTA5SYNC_BUILDSTRING QString("%1, %2").arg(QT_VERSION_STR, GTA5SYNC_COMPILER); -#endif - -#endif // CONFIG_H +/***************************************************************************** +* gta5view Grand Theft Auto V Profile Viewer +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef CONFIG_H +#define CONFIG_H +#include <QtGlobal> +#include <QString> + +#ifndef GTA5SYNC_APPVENDOR +#define GTA5SYNC_APPVENDOR "Syping" +#endif + +#ifndef GTA5SYNC_APPVENDORLINK +#define GTA5SYNC_APPVENDORLINK "https://github.com/Syping/" +#endif + +#ifndef GTA5SYNC_DISABLED +#define GTA5SYNC_ENABLED +#endif + +#ifndef GTA5SYNC_APPSTR +#ifdef GTA5SYNC_ENABLED +#define GTA5SYNC_APPSTR "gta5sync" +#else +#define GTA5SYNC_APPSTR "gta5view" +#endif +#endif + +#ifndef GTA5SYNC_APPDES +#define GTA5SYNC_APPDES "INSERT YOUR APPLICATION DESCRIPTION HERE" +#endif + +#ifndef GTA5SYNC_COPYRIGHT +#define GTA5SYNC_COPYRIGHT "2016-2017" +#endif + +#ifndef GTA5SYNC_APPVER +#ifndef GTA5SYNC_DAILYB +#define GTA5SYNC_APPVER "1.5.0-dev1" +#else +#define GTA5SYNC_APPVER GTA5SYNC_DAILYB +#endif +#endif + +#ifdef GTA5SYNC_BUILDTYPE_REL +#ifndef GTA5SYNC_BUILDTYPE +#define GTA5SYNC_BUILDTYPE QT_TRANSLATE_NOOP("AboutDialog", "Release") +#endif +#endif + +#ifdef GTA5SYNC_BUILDTYPE_RC +#ifndef GTA5SYNC_BUILDTYPE +#define GTA5SYNC_BUILDTYPE QT_TRANSLATE_NOOP("AboutDialog", "Release Candidate") +#endif +#endif + +#ifdef GTA5SYNC_BUILDTYPE_DAILY +#ifndef GTA5SYNC_BUILDTYPE +#define GTA5SYNC_BUILDTYPE QT_TRANSLATE_NOOP("AboutDialog", "Daily Build") +#endif +#endif + +#ifdef GTA5SYNC_BUILDTYPE_DEV +#ifndef GTA5SYNC_BUILDTYPE +#define GTA5SYNC_BUILDTYPE QT_TRANSLATE_NOOP("AboutDialog", "Developer") +#endif +#endif + +#ifdef GTA5SYNC_BUILDTYPE_BETA +#ifndef GTA5SYNC_BUILDTYPE +#define GTA5SYNC_BUILDTYPE QT_TRANSLATE_NOOP("AboutDialog", "Beta") +#endif +#endif + +#ifdef GTA5SYNC_BUILDTYPE_ALPHA +#ifndef GTA5SYNC_BUILDTYPE +#define GTA5SYNC_BUILDTYPE QT_TRANSLATE_NOOP("AboutDialog", "Alpha") +#endif +#endif + +#ifdef GTA5SYNC_DAILYB +#ifndef GTA5SYNC_BUILDTYPE +#define GTA5SYNC_BUILDTYPE "Daily Build" +#endif +#endif + +#ifndef GTA5SYNC_BUILDTYPE +#define GTA5SYNC_BUILDTYPE "Custom" +#endif + +#ifdef GTA5SYNC_QCONF +#ifndef GTA5SYNC_SHARE +#define GTA5SYNC_SHARE "RUNDIR:SEPARATOR:..SEPARATOR:share" +#endif +#ifndef GTA5SYNC_LANG +#define GTA5SYNC_LANG "QCONFLANG:" +#endif +#ifndef GTA5SYNC_PLUG +#define GTA5SYNC_PLUG "QCONFPLUG:" +#endif +#ifdef GTA5SYNC_QCONF_IN +#ifndef GTA5SYNC_INLANG +#define GTA5SYNC_INLANG ":/tr" +#endif +#endif +#endif + +#ifndef GTA5SYNC_SHARE +#define GTA5SYNC_SHARE "RUNDIR:" +#endif + +#ifndef GTA5SYNC_LANG +#define GTA5SYNC_LANG "SHAREDDIR:SEPARATOR:lang" +#endif + +#ifndef GTA5SYNC_PLUG +#define GTA5SYNC_PLUG "RUNDIR:SEPARATOR:plugins" +#endif + +#ifdef GTA5SYNC_WINRT +#undef GTA5SYNC_WIN +#endif + +#ifndef GTA5SYNC_COMPILER +#ifdef __clang__ +#define GTA5SYNC_COMPILER QString("Clang %1.%2.%3").arg(QString::number(__clang_major__), QString::number(__clang_minor__), QString::number(__clang_patchlevel__)) +#elif defined(__GNUC__) +#define GTA5SYNC_COMPILER QString("GCC %1.%2.%3").arg(QString::number(__GNUC__), QString::number(__GNUC_MINOR__), QString::number(__GNUC_PATCHLEVEL__)) +#elif defined(__GNUG__) +#define GTA5SYNC_COMPILER QString("GCC %1.%2.%3").arg(QString::number(__GNUG__), QString::number(__GNUC_MINOR__), QString::number(__GNUC_PATCHLEVEL__)) +#elif defined(_MSC_VER) +#define GTA5SYNC_COMPILER QString("MSVC %1").arg(QString::number(_MSC_VER).insert(2, ".")) +#else +#define GTA5SYNC_COMPILER QString("Unknown Compiler") +#endif +#endif + +#ifndef GTA5SYNC_BUILDDATETIME +#define GTA5SYNC_BUILDDATETIME QString("%1, %2").arg(__DATE__, __TIME__) +#endif + +#ifndef GTA5SYNC_BUILDSTRING +#define GTA5SYNC_BUILDSTRING QString("%1, %2").arg(QT_VERSION_STR, GTA5SYNC_COMPILER) +#endif + +#endif // CONFIG_H diff --git a/gta5view.pro b/gta5view.pro index 58e2987..e2a3418 100755 --- a/gta5view.pro +++ b/gta5view.pro @@ -1,172 +1,196 @@ -#/***************************************************************************** -#* gta5view Grand Theft Auto V Profile Viewer -#* Copyright (C) 2015-2017 Syping -#* -#* This program is free software: you can redistribute it and/or modify -#* it under the terms of the GNU General Public License as published by -#* the Free Software Foundation, either version 3 of the License, or -#* (at your option) any later version. -#* -#* This program is distributed in the hope that it will be useful, -#* but WITHOUT ANY WARRANTY; without even the implied warranty of -#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -#* GNU General Public License for more details. -#* -#* You should have received a copy of the GNU General Public License -#* along with this program. If not, see <http://www.gnu.org/licenses/>. -#*****************************************************************************/ - -QT += core gui network - -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets -greaterThan(QT_MAJOR_VERSION, 4): greaterThan(QT_MINOR_VERSION, 1): win32: QT += winextras - -DEFINES += GTA5SYNC_DISABLED - -DEPLOYMENT.display_name = gta5view -TARGET = gta5view -TEMPLATE = app - -SOURCES += main.cpp \ - AboutDialog.cpp \ - AppEnv.cpp \ - CrewDatabase.cpp \ - DatabaseThread.cpp \ - ExportDialog.cpp \ - ExportThread.cpp \ - GlobalString.cpp \ - IconLoader.cpp \ - ImportDialog.cpp \ - OptionsDialog.cpp \ - PictureDialog.cpp \ - PictureExport.cpp \ - PictureWidget.cpp \ - ProfileDatabase.cpp \ - ProfileInterface.cpp \ - ProfileLoader.cpp \ - ProfileWidget.cpp \ - SavegameCopy.cpp \ - SavegameData.cpp \ - SavegameDialog.cpp \ - SavegameWidget.cpp \ - SidebarGenerator.cpp \ - SnapmaticEditor.cpp \ - SnapmaticPicture.cpp \ - SnapmaticWidget.cpp \ - StandardPaths.cpp \ - StringParser.cpp \ - UserInterface.cpp \ - uimod/UiModLabel.cpp \ - uimod/UiModWidget.cpp - -HEADERS += \ - AboutDialog.h \ - AppEnv.h \ - CrewDatabase.h \ - DatabaseThread.h \ - ExportDialog.h \ - ExportThread.h \ - GlobalString.h \ - IconLoader.h \ - ImportDialog.h \ - OptionsDialog.h \ - PictureDialog.h \ - PictureExport.h \ - PictureWidget.h \ - ProfileDatabase.h \ - ProfileInterface.h \ - ProfileLoader.h \ - ProfileWidget.h \ - SavegameCopy.h \ - SavegameData.h \ - SavegameDialog.h \ - SavegameWidget.h \ - SidebarGenerator.h \ - SnapmaticEditor.h \ - SnapmaticPicture.h \ - SnapmaticWidget.h \ - StandardPaths.h \ - StringParser.h \ - UserInterface.h \ - uimod/UiModLabel.h \ - uimod/UiModWidget.h - -PRECOMPILED_HEADER += config.h - -FORMS += \ - AboutDialog.ui \ - ExportDialog.ui \ - ImportDialog.ui \ - OptionsDialog.ui \ - PictureDialog.ui \ - ProfileInterface.ui \ - SavegameDialog.ui \ - SavegameWidget.ui \ - SnapmaticEditor.ui \ - SnapmaticWidget.ui \ - UserInterface.ui - -TRANSLATIONS += \ - res/gta5sync_de.ts \ - res/gta5sync_fr.ts \ - res/gta5sync_ru.ts - -RESOURCES += \ - res/tr_g5p.qrc \ - res/app.qrc - -DISTFILES += res/app.rc \ - res/gta5sync.desktop \ - res/gta5sync_de.ts \ - res/gta5sync_fr.ts \ - res/gta5sync_ru.ts \ - res/gta5view.exe.manifest \ - res/gta5view.png \ - lang/README.txt - -INCLUDEPATH += ./uimod - -# WINDOWS ONLY - -win32: DEFINES += GTA5SYNC_WIN -win32: RC_FILE += res/app.rc -win32: LIBS += -luser32 -win32: CONFIG -= embed_manifest_exe - -# MAC OS X ONLY -macx: ICON = res/5sync.icns - -# QT4 ONLY STUFF - -isEqual(QT_MAJOR_VERSION, 4): INCLUDEPATH += ./qjson4 -isEqual(QT_MAJOR_VERSION, 4): HEADERS += qjson4/QJsonArray.h \ - qjson4/QJsonDocument.h \ - qjson4/QJsonObject.h \ - qjson4/QJsonParseError.h \ - qjson4/QJsonValue.h \ - qjson4/QJsonValueRef.h \ - qjson4/QJsonParser.h \ - qjson4/QJsonRoot.h - -isEqual(QT_MAJOR_VERSION, 4): SOURCES += qjson4/QJsonArray.cpp \ - qjson4/QJsonDocument.cpp \ - qjson4/QJsonObject.cpp \ - qjson4/QJsonParseError.cpp \ - qjson4/QJsonValue.cpp \ - qjson4/QJsonValueRef.cpp \ - qjson4/QJsonParser.cpp - -isEqual(QT_MAJOR_VERSION, 4): RESOURCES += res/tr_qt4.qrc - -# QT5 ONLY STUFF - -isEqual(QT_MAJOR_VERSION, 5): RESOURCES += res/tr_qt5.qrc - -# UNIX SYSTEM STUFF - -unix: !macx: appfiles.path = $$(INSTALL_PATH)/share/applications -unix: !macx: appfiles.files = $$PWD/res/gta5view.desktop -unix: !macx: pixmaps.path = $$(INSTALL_PATH)/share/pixmaps -unix: !macx: pixmaps.files = $$PWD/res/gta5view.png -unix: !macx: target.path = $$(INSTALL_PATH)/bin -unix: !macx: INSTALLS += target pixmaps appfiles +#/***************************************************************************** +#* gta5view Grand Theft Auto V Profile Viewer +#* Copyright (C) 2015-2017 Syping +#* +#* This program is free software: you can redistribute it and/or modify +#* it under the terms of the GNU General Public License as published by +#* the Free Software Foundation, either version 3 of the License, or +#* (at your option) any later version. +#* +#* This program is distributed in the hope that it will be useful, +#* but WITHOUT ANY WARRANTY; without even the implied warranty of +#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#* GNU General Public License for more details. +#* +#* You should have received a copy of the GNU General Public License +#* along with this program. If not, see <http://www.gnu.org/licenses/>. +#*****************************************************************************/ + +QT += core gui network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets +greaterThan(QT_MAJOR_VERSION, 4): greaterThan(QT_MINOR_VERSION, 1): win32: QT += winextras + +DEFINES += GTA5SYNC_DISABLED + +DEPLOYMENT.display_name = gta5view +TARGET = gta5view +TEMPLATE = app + +DEFINES += GTA5SYNC_CSDF # Not assisting at proper usage of SnapmaticPicture class +HEADERS += config.h +PRECOMPILED_HEADER += config.h + +SOURCES += main.cpp \ + AboutDialog.cpp \ + AppEnv.cpp \ + CrewDatabase.cpp \ + DatabaseThread.cpp \ + ExportDialog.cpp \ + ExportThread.cpp \ + GlobalString.cpp \ + IconLoader.cpp \ + ImportDialog.cpp \ + MapPreviewDialog.cpp \ + OptionsDialog.cpp \ + PictureDialog.cpp \ + PictureExport.cpp \ + PictureWidget.cpp \ + ProfileDatabase.cpp \ + ProfileInterface.cpp \ + ProfileLoader.cpp \ + ProfileWidget.cpp \ + SavegameCopy.cpp \ + SavegameData.cpp \ + SavegameDialog.cpp \ + SavegameWidget.cpp \ + SidebarGenerator.cpp \ + SnapmaticEditor.cpp \ + SnapmaticPicture.cpp \ + SnapmaticWidget.cpp \ + StandardPaths.cpp \ + StringParser.cpp \ + TranslationClass.cpp \ + UserInterface.cpp \ + uimod/UiModLabel.cpp \ + uimod/UiModWidget.cpp + +HEADERS += \ + AboutDialog.h \ + AppEnv.h \ + CrewDatabase.h \ + DatabaseThread.h \ + ExportDialog.h \ + ExportThread.h \ + GlobalString.h \ + IconLoader.h \ + ImportDialog.h \ + MapPreviewDialog.h \ + OptionsDialog.h \ + PictureDialog.h \ + PictureExport.h \ + PictureWidget.h \ + ProfileDatabase.h \ + ProfileInterface.h \ + ProfileLoader.h \ + ProfileWidget.h \ + SavegameCopy.h \ + SavegameData.h \ + SavegameDialog.h \ + SavegameWidget.h \ + SidebarGenerator.h \ + SnapmaticEditor.h \ + SnapmaticPicture.h \ + SnapmaticWidget.h \ + StandardPaths.h \ + StringParser.h \ + TranslationClass.h \ + UserInterface.h \ + uimod/UiModLabel.h \ + uimod/UiModWidget.h + +FORMS += \ + AboutDialog.ui \ + ExportDialog.ui \ + ImportDialog.ui \ + MapPreviewDialog.ui \ + OptionsDialog.ui \ + PictureDialog.ui \ + ProfileInterface.ui \ + SavegameDialog.ui \ + SavegameWidget.ui \ + SnapmaticEditor.ui \ + SnapmaticWidget.ui \ + UserInterface.ui + +TRANSLATIONS += \ + res/gta5sync_en_US.ts \ + res/gta5sync_de.ts \ + res/gta5sync_fr.ts \ + res/gta5sync_ru.ts \ + lang/gta5sync_no.ts + +RESOURCES += \ + res/tr_g5p.qrc \ + res/app.qrc + +DISTFILES += res/app.rc \ + res/gta5view.desktop \ + res/gta5sync_de.ts \ + res/gta5sync_fr.ts \ + res/gta5sync_ru.ts \ + res/gta5view.exe.manifest \ + res/gta5view.png \ + lang/gta5sync_no.ts \ + lang/README.txt + +INCLUDEPATH += ./uimod + +# WINDOWS ONLY + +win32: DEFINES += GTA5SYNC_WIN +win32: RC_FILE += res/app.rc +win32: LIBS += -luser32 +win32: CONFIG -= embed_manifest_exe + +# MAC OS X ONLY +macx: ICON = res/5sync.icns + +# QT4 ONLY STUFF + +isEqual(QT_MAJOR_VERSION, 4): INCLUDEPATH += ./qjson4 +isEqual(QT_MAJOR_VERSION, 4): HEADERS += qjson4/QJsonArray.h \ + qjson4/QJsonDocument.h \ + qjson4/QJsonObject.h \ + qjson4/QJsonParseError.h \ + qjson4/QJsonValue.h \ + qjson4/QJsonValueRef.h \ + qjson4/QJsonParser.h \ + qjson4/QJsonRoot.h + +isEqual(QT_MAJOR_VERSION, 4): SOURCES += qjson4/QJsonArray.cpp \ + qjson4/QJsonDocument.cpp \ + qjson4/QJsonObject.cpp \ + qjson4/QJsonParseError.cpp \ + qjson4/QJsonValue.cpp \ + qjson4/QJsonValueRef.cpp \ + qjson4/QJsonParser.cpp + +isEqual(QT_MAJOR_VERSION, 4): RESOURCES += res/tr_qt4.qrc + +# QT5 ONLY STUFF +isEqual(QT_MAJOR_VERSION, 5): RESOURCES += res/tr_qt5.qrc + +# PROJECT INSTALLATION + +isEmpty(GTA5SYNC_PREFIX): GTA5SYNC_PREFIX = /usr/local + +appfiles.path = $$GTA5SYNC_PREFIX/share/applications +appfiles.files = $$PWD/res/gta5view.desktop +pixmaps.path = $$GTA5SYNC_PREFIX/share/pixmaps +pixmaps.files = $$PWD/res/gta5view.png +target.path = $$GTA5SYNC_PREFIX/bin +INSTALLS += target pixmaps appfiles + +# QCONF BASED BUILD STUFF + +contains(DEFINES, GTA5SYNC_QCONF){ + isEqual(QT_MAJOR_VERSION, 4): RESOURCES -= res/tr_qt4.qrc + isEqual(QT_MAJOR_VERSION, 5): RESOURCES -= res/tr_qt5.qrc + !contains(DEFINES, GTA5SYNC_QCONF_IN){ + RESOURCES -= res/tr_g5p.qrc + langfiles.path = $$GTA5SYNC_PREFIX/share/gta5view/translations + langfiles.files = $$PWD/res/gta5sync_en_US.qm $$PWD/res/gta5sync_de.qm $$PWD/res/gta5sync_fr.qm $$PWD/res/gta5sync_ru.qm $$PWD/res/qtbase_en_GB.qm + INSTALLS += langfiles + } +} diff --git a/lang/gta5sync_no.qm b/lang/gta5sync_no.qm new file mode 100644 index 0000000000000000000000000000000000000000..9dad8dffceb9623e88f8b96d9cd0caf25574c6fa GIT binary patch literal 23 fcmcE7ks@*G{hX<16=n7(EZlpygMop8iIEWihQJ9+ literal 0 HcmV?d00001 diff --git a/lang/gta5sync_no.ts b/lang/gta5sync_no.ts new file mode 100644 index 0000000..f18d088 --- /dev/null +++ b/lang/gta5sync_no.ts @@ -0,0 +1,1619 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="nb_NO"> +<context> + <name>AboutDialog</name> + <message> + <location filename="../AboutDialog.ui" line="14"/> + <source>About %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../AboutDialog.ui" line="29"/> + <source><span style=" font-weight:600;">%1</span><br/> +<br/> +%2<br/> +<br/> +Version %3<br/> +Created on %4<br/> +Built with Qt %5<br/> +Running with Qt %6<br/> +<br/> +%7</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../AboutDialog.ui" line="75"/> + <source>&Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../AboutDialog.cpp" line="41"/> + <source>Using %1 %2</source> + <extracomment>Using specific library, example Using libmyfuck</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../AboutDialog.cpp" line="43"/> + <source>Translated by %1</source> + <extracomment>Translated by translator, example Translated by Syping</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../AboutDialog.cpp" line="45"/> + <source>NAME_OF_TRANSLATOR</source> + <extracomment>Enter your name there</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../AboutDialog.cpp" line="47"/> + <source>TRANSLATOR_PROFILE</source> + <extracomment>Enter your proilfe there, example a GitHub profile, E-Mail with "mailto: afucker@sumfuck.com" or a webpage</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../AboutDialog.cpp" line="78"/> + <source>A project for viewing and sync Grand Theft Auto V Snapmatic<br/> +Pictures and Savegames</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../AboutDialog.cpp" line="80"/> + <source>A project for viewing Grand Theft Auto V Snapmatic<br/> +Pictures and Savegames</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../AboutDialog.cpp" line="84"/> + <source>Copyright &copy; <a href="%1">%2</a> %3</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../AboutDialog.cpp" line="86"/> + <source>%1 is licensed under <a href="https://www.gnu.org/licenses/gpl-3.0.html#content">GNU GPLv3</a></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../config.h" line="62"/> + <source>Release</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../config.h" line="68"/> + <source>Release Candidate</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../config.h" line="74"/> + <source>Daily Build</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../config.h" line="80"/> + <source>Developer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../config.h" line="86"/> + <source>Beta</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../config.h" line="92"/> + <source>Alpha</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>CrewDatabase</name> + <message> + <location filename="../CrewDatabase.cpp" line="102"/> + <source>No Crew</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ExportDialog</name> + <message> + <location filename="../ExportDialog.ui" line="14"/> + <source>Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ExportDialog.ui" line="45"/> + <source>Export Format</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ExportDialog.ui" line="51"/> + <source>&JPEG/PNG format</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ExportDialog.ui" line="58"/> + <source>GTA &Snapmatic format</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ExportDialog.ui" line="68"/> + <source>Export Size</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ExportDialog.ui" line="74"/> + <source>Default &Size</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ExportDialog.ui" line="81"/> + <source>&Desktop Size</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ExportDialog.ui" line="88"/> + <source>&Custom Size</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ExportDialog.ui" line="100"/> + <source>Custom Size:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ExportDialog.ui" line="123"/> + <source>x</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ExportDialog.ui" line="198"/> + <source>&Export</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ExportDialog.ui" line="211"/> + <source>&Close</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ImportDialog</name> + <message> + <location filename="../ImportDialog.ui" line="26"/> + <source>Import...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="90"/> + <source>Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="98"/> + <location filename="../ImportDialog.cpp" line="57"/> + <location filename="../ImportDialog.cpp" line="216"/> + <source>Background Colour: <span style="color: %1">%1</span></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="148"/> + <source>Ignore Aspect Ratio</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="135"/> + <source>Avatar</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="105"/> + <source>...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="194"/> + <source>Import picture</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="197"/> + <source>&OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="210"/> + <source>Discard picture</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="213"/> + <source>&Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ImportDialog.cpp" line="173"/> + <source>Are you sure to use a square image outside of the Avatar Zone? +When you want to use it as Avatar the image will be detached!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ImportDialog.cpp" line="173"/> + <source>Snapmatic Avatar Zone</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ImportDialog.cpp" line="212"/> + <source>Select Colour...</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MapPreviewDialog</name> + <message> + <location filename="../MapPreviewDialog.ui" line="26"/> + <source>Snapmatic Map Viewer</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>OptionsDialog</name> + <message> + <location filename="../OptionsDialog.ui" line="14"/> + <source>%1 - Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="27"/> + <source>Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="33"/> + <source>Content Open/Select Mode</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="39"/> + <source>Open with Singleclick</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="49"/> + <source>Open with Doubleclick</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="56"/> + <source>Select with Singleclick</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="66"/> + <source>Default Profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="78"/> + <source>Custom GTA V Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="84"/> + <source>Force using Custom Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="96"/> + <source>...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="122"/> + <source>Pictures</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="128"/> + <source>Export Size</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="134"/> + <source>Default: %1x%2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="144"/> + <source>Screen Resolution: %1x%2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="153"/> + <location filename="../OptionsDialog.ui" line="163"/> + <source>Custom Size:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="189"/> + <source>x</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="229"/> + <source>Ignore Aspect Ratio</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="241"/> + <source>Export Quality</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="247"/> + <source>Enable Custom Quality</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="259"/> + <source>Quality:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="288"/> + <source>%1%</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="303"/> + <source>Picture Viewer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="309"/> + <source>Enable Navigation Bar</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="333"/> + <source>Players</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="373"/> + <source>ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="378"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="387"/> + <location filename="../OptionsDialog.ui" line="393"/> + <source>Language</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="419"/> + <source>Sync</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="425"/> + <source>Sync is not implemented at current time</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="463"/> + <source>Apply changes</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="466"/> + <source>&OK</source> + <extracomment>OK, Cancel, Apply</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="479"/> + <source>Discard changes</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="482"/> + <source>&Cancel</source> + <extracomment>OK, Cancel, Apply</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.cpp" line="132"/> + <source>%1 (Next Closest Language)</source> + <comment>First language a person can talk with a different person/application. "Native" or "Not Native".</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.cpp" line="132"/> + <source>System</source> + <comment>System in context of System default</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.cpp" line="289"/> + <source>%1</source> + <comment>%1</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.cpp" line="289"/> + <source>The new Custom Folder will initialise after you restart %1.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.cpp" line="299"/> + <source>No Profile</source> + <comment>No Profile, as default</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.cpp" line="307"/> + <location filename="../OptionsDialog.cpp" line="311"/> + <location filename="../OptionsDialog.cpp" line="313"/> + <source>Profile: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PictureDialog</name> + <message> + <location filename="../PictureDialog.ui" line="14"/> + <source>%1 - Snapmatic Picture Viewer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureDialog.ui" line="117"/> + <source><span style=" font-weight:600;">Title: </span>%6<br/> +<span style=" font-weight:600;">Location: </span>%7 (%1, %2, %3)<br/> +<span style=" font-weight:600;">Players: </span>%4 (Crew %5)<br/> +<span style=" font-weight:600;">Created: </span>%8</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureDialog.ui" line="177"/> + <source>Manage picture</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureDialog.ui" line="180"/> + <source>&Manage</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureDialog.ui" line="199"/> + <source>Close viewer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureDialog.ui" line="202"/> + <source>&Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="145"/> + <source>Export as &Picture...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="146"/> + <source>Export as &Snapmatic...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="148"/> + <source>Open &Map View...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="150"/> + <source>&Edit Properties...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="373"/> + <source>Key 1 - Avatar Preview Mode +Key 2 - Toggle Overlay +Arrow Keys - Navigate</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="433"/> + <location filename="../PictureDialog.cpp" line="476"/> + <source>Snapmatic Picture Viewer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="433"/> + <location filename="../PictureDialog.cpp" line="476"/> + <source>Failed at %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="475"/> + <location filename="../PictureDialog.cpp" line="589"/> + <source>No Crew</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="475"/> + <source>Unknown Location</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="475"/> + <location filename="../PictureDialog.cpp" line="614"/> + <source>No Players</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="560"/> + <source>Avatar Preview Mode +Press 1 for Default View</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="91"/> + <location filename="../PictureExport.cpp" line="223"/> + <source>Export</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="90"/> + <source>Export as Picture...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="94"/> + <source>JPEG Graphics (*.jpg *.jpeg)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="95"/> + <source>Portable Network Graphics (*.png)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="145"/> + <location filename="../PictureExport.cpp" line="260"/> + <source>Overwrite %1 with current Snapmatic picture?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="145"/> + <location filename="../PictureExport.cpp" line="149"/> + <location filename="../PictureExport.cpp" line="183"/> + <location filename="../PictureExport.cpp" line="189"/> + <source>Export as Picture</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="149"/> + <location filename="../PictureExport.cpp" line="264"/> + <source>Failed to overwrite %1 with current Snapmatic picture</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="183"/> + <location filename="../PictureExport.cpp" line="279"/> + <location filename="../PictureExport.cpp" line="288"/> + <source>Failed to export current Snapmatic picture</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="189"/> + <location filename="../PictureExport.cpp" line="299"/> + <source>No valid file is selected</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="222"/> + <source>Export as Snapmatic...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="226"/> + <source>GTA V Export (*.g5e)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="227"/> + <source>GTA V Raw Export (*.auto)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="228"/> + <source>Snapmatic pictures (PGTA*)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="260"/> + <location filename="../PictureExport.cpp" line="264"/> + <location filename="../PictureExport.cpp" line="279"/> + <location filename="../PictureExport.cpp" line="288"/> + <location filename="../PictureExport.cpp" line="293"/> + <location filename="../PictureExport.cpp" line="299"/> + <source>Export as Snapmatic</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="293"/> + <source>Exported Snapmatic to "%1" because of using the .auto extension.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ProfileInterface</name> + <message> + <location filename="../ProfileInterface.ui" line="14"/> + <source>Profile Interface</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.ui" line="55"/> + <source>Loading file %1 of %2 files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.ui" line="172"/> + <source>%1 %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.ui" line="198"/> + <source>Import file</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.ui" line="201"/> + <source>&Import...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.ui" line="217"/> + <source>Close profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.ui" line="220"/> + <source>&Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ExportThread.cpp" line="97"/> + <location filename="../ExportThread.cpp" line="136"/> + <location filename="../ExportThread.cpp" line="157"/> + <source>Export file %1 of %2 files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="65"/> + <source>Enabled pictures: %1 of %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="129"/> + <source>Loading...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="426"/> + <location filename="../ProfileInterface.cpp" line="491"/> + <source>Import...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="427"/> + <location filename="../ProfileInterface.cpp" line="470"/> + <location filename="../ProfileInterface.cpp" line="522"/> + <location filename="../ProfileInterface.cpp" line="542"/> + <location filename="../ProfileInterface.cpp" line="558"/> + <location filename="../ProfileInterface.cpp" line="674"/> + <location filename="../ProfileInterface.cpp" line="755"/> + <location filename="../ProfileInterface.cpp" line="760"/> + <location filename="../ProfileInterface.cpp" line="778"/> + <location filename="../ProfileInterface.cpp" line="783"/> + <location filename="../ProfileInterface.cpp" line="794"/> + <location filename="../ProfileInterface.cpp" line="831"/> + <location filename="../ProfileInterface.cpp" line="837"/> + <source>Import</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="443"/> + <location filename="../UserInterface.cpp" line="364"/> + <source>GTA V Export (*.g5e)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="444"/> + <location filename="../UserInterface.cpp" line="365"/> + <source>Savegames files (SGTA*)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="445"/> + <location filename="../UserInterface.cpp" line="366"/> + <source>Snapmatic pictures (PGTA*)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="442"/> + <source>Importable files (%1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="446"/> + <source>All image files (%1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="447"/> + <location filename="../UserInterface.cpp" line="367"/> + <source>All files (**)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="470"/> + <location filename="../ProfileInterface.cpp" line="760"/> + <location filename="../UserInterface.cpp" line="455"/> + <source>No valid file is selected</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="492"/> + <location filename="../ProfileInterface.cpp" line="507"/> + <source>Import file %1 of %2 files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="522"/> + <source>Import failed with... + +%1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="542"/> + <location filename="../UserInterface.cpp" line="407"/> + <source>Failed to read Snapmatic picture</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="558"/> + <location filename="../UserInterface.cpp" line="423"/> + <source>Failed to read Savegame file</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="674"/> + <source>Can't import %1 because file can't be parsed properly</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="755"/> + <source>Can't import %1 because file format can't be detected</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="778"/> + <source>Failed to import the Snapmatic picture, file not begin with PGTA or end with .g5e</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="783"/> + <source>Failed to import the Snapmatic picture, the picture is already in the game</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="794"/> + <source>Failed to import the Snapmatic picture, can't copy the file into profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="831"/> + <source>Failed to import the Savegame, can't copy the file into profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="837"/> + <source>Failed to import the Savegame, no Savegame slot is left</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="900"/> + <location filename="../ProfileInterface.cpp" line="938"/> + <location filename="../ProfileInterface.cpp" line="1017"/> + <location filename="../ProfileInterface.cpp" line="1037"/> + <source>Export selected</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="923"/> + <location filename="../ProfileInterface.cpp" line="941"/> + <source>JPG pictures and GTA Snapmatic</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="924"/> + <location filename="../ProfileInterface.cpp" line="946"/> + <source>JPG pictures only</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="925"/> + <location filename="../ProfileInterface.cpp" line="950"/> + <source>GTA Snapmatic only</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="938"/> + <source>%1Export Snapmatic pictures%2<br><br>JPG pictures make it possible to open the picture with a Image Viewer<br>GTA Snapmatic make it possible to import the picture into the game<br><br>Export as:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="983"/> + <source>Export selected...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="984"/> + <source>Initialising export...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1017"/> + <source>Export failed with... + +%1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1037"/> + <location filename="../ProfileInterface.cpp" line="1079"/> + <source>No Snapmatic pictures or Savegames files are selected</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1045"/> + <location filename="../ProfileInterface.cpp" line="1073"/> + <location filename="../ProfileInterface.cpp" line="1079"/> + <source>Remove selected</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1045"/> + <source>You really want remove the selected Snapmatic picutres and Savegame files?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1073"/> + <source>Failed at remove the complete selected Snapmatic pictures and/or Savegame files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.cpp" line="363"/> + <source>All profile files (*.g5e SGTA* PGTA*)</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QApplication</name> + <message> + <location filename="../main.cpp" line="66"/> + <source>Font</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../main.cpp" line="66"/> + <source>Selected Font: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SavegameDialog</name> + <message> + <location filename="../SavegameDialog.ui" line="14"/> + <location filename="../SavegameDialog.cpp" line="38"/> + <source>Savegame Viewer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SavegameDialog.ui" line="23"/> + <source><span style=" font-weight:600;">Savegame</span><br><br>%1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SavegameDialog.ui" line="70"/> + <source>&Export</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SavegameDialog.ui" line="83"/> + <source>&Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SavegameDialog.cpp" line="38"/> + <source>Failed at %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SavegameWidget</name> + <message> + <location filename="../SavegameWidget.ui" line="14"/> + <source>Savegame Widget</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SavegameWidget.ui" line="67"/> + <source>SAVE %3 - %1<br>%2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SavegameWidget.ui" line="83"/> + <source>View savegame</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SavegameWidget.ui" line="86"/> + <source>View</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SavegameWidget.ui" line="99"/> + <source>Copy savegame</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SavegameWidget.ui" line="102"/> + <location filename="../SavegameCopy.cpp" line="48"/> + <source>Export</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SavegameWidget.ui" line="118"/> + <location filename="../SavegameWidget.cpp" line="131"/> + <location filename="../SavegameWidget.cpp" line="144"/> + <source>Delete savegame</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SavegameWidget.ui" line="121"/> + <source>Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1225"/> + <source>&View</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1226"/> + <source>&Export</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1227"/> + <source>&Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1229"/> + <source>&Select</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1230"/> + <source>&Deselect</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1233"/> + <source>Select &All</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1237"/> + <source>&Deselect All</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SavegameCopy.cpp" line="51"/> + <source>Savegame files (SGTA*)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SavegameCopy.cpp" line="52"/> + <source>All files (**)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SavegameCopy.cpp" line="70"/> + <location filename="../SavegameCopy.cpp" line="74"/> + <location filename="../SavegameCopy.cpp" line="87"/> + <location filename="../SavegameCopy.cpp" line="93"/> + <source>Export Savegame</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SavegameCopy.cpp" line="70"/> + <source>Overwrite %1 with current Savegame?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SavegameCopy.cpp" line="74"/> + <source>Failed to overwrite %1 with current Savegame</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SavegameCopy.cpp" line="87"/> + <source>Failed to export current Savegame</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SavegameCopy.cpp" line="93"/> + <source>No valid file is selected</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SavegameWidget.cpp" line="57"/> + <source>Export Savegame...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SavegameWidget.cpp" line="60"/> + <location filename="../SavegameWidget.cpp" line="117"/> + <source>AUTOSAVE - %1 +%2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SavegameWidget.cpp" line="61"/> + <location filename="../SavegameWidget.cpp" line="118"/> + <source>SAVE %3 - %1 +%2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SavegameWidget.cpp" line="89"/> + <location filename="../SavegameWidget.cpp" line="90"/> + <source>WRONG FORMAT</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SavegameWidget.cpp" line="111"/> + <source>UNKNOWN</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SavegameWidget.cpp" line="131"/> + <source>Are you sure to delete %1 from your savegames?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SavegameWidget.cpp" line="144"/> + <source>Failed at deleting %1 from your savegames</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SnapmaticEditor</name> + <message> + <location filename="../SnapmaticEditor.ui" line="14"/> + <location filename="../SnapmaticEditor.ui" line="81"/> + <location filename="../SnapmaticEditor.cpp" line="245"/> + <source>Snapmatic Properties</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="44"/> + <source>Snapmatic Type</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="50"/> + <source>Editor</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="57"/> + <source>Selfie</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="64"/> + <source>Regular</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="71"/> + <source>Mugshot</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="87"/> + <source>Meme</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="94"/> + <source>Director</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="104"/> + <source>Snapmatic Values</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="113"/> + <location filename="../SnapmaticEditor.cpp" line="200"/> + <source>Crew: %1 (%2)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="126"/> + <location filename="../SnapmaticEditor.cpp" line="185"/> + <source>Title: %1 (%2)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="136"/> + <location filename="../SnapmaticEditor.cpp" line="189"/> + <location filename="../SnapmaticEditor.cpp" line="193"/> + <source>Appropriate: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="149"/> + <source>Extras</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="155"/> + <source>Qualify as Avatar automatically at apply</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="168"/> + <source>Qualify as Avatar allows you to use this Snapmatic as a Social Club profile picture</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="218"/> + <source>&Apply</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="231"/> + <source>&Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticEditor.cpp" line="184"/> + <location filename="../SnapmaticEditor.cpp" line="199"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticEditor.cpp" line="189"/> + <source>Yes</source> + <comment>Yes, should work fine</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticEditor.cpp" line="193"/> + <source>No</source> + <comment>No, could lead to issues</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticEditor.cpp" line="245"/> + <source>Patching of Snapmatic Properties failed because of I/O Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticEditor.cpp" line="295"/> + <source>Snapmatic Title</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticEditor.cpp" line="295"/> + <source>New Snapmatic title:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticEditor.cpp" line="324"/> + <source>Snapmatic Crew</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticEditor.cpp" line="324"/> + <source>New Snapmatic crew:</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SnapmaticPicture</name> + <message> + <location filename="../SnapmaticPicture.cpp" line="411"/> + <source>PHOTO - %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SnapmaticWidget</name> + <message> + <location filename="../SnapmaticWidget.ui" line="14"/> + <source>Snapmatic Widget</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticWidget.ui" line="85"/> + <source>PHOTO - 00/00/00 00:00:00</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticWidget.ui" line="101"/> + <source>View picture</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticWidget.ui" line="104"/> + <source>View</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticWidget.ui" line="120"/> + <source>Copy picture</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticWidget.ui" line="123"/> + <source>Copy</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticWidget.ui" line="136"/> + <source>Export picture</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticWidget.ui" line="139"/> + <source>Export</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticWidget.ui" line="152"/> + <location filename="../SnapmaticWidget.cpp" line="144"/> + <location filename="../SnapmaticWidget.cpp" line="153"/> + <source>Delete picture</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticWidget.ui" line="155"/> + <source>Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1178"/> + <source>Edi&t</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1181"/> + <source>Show &In-game</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1185"/> + <source>Hide &In-game</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1187"/> + <source>&Edit Properties...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1188"/> + <source>&Export</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1189"/> + <source>Export as &Picture...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1190"/> + <source>Export as &Snapmatic...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1191"/> + <source>&View</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1194"/> + <source>&Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1196"/> + <source>&Select</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1197"/> + <source>&Deselect</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1200"/> + <source>Select &All</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1204"/> + <source>&Deselect All</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticWidget.cpp" line="144"/> + <source>Are you sure to delete %1 from your Snapmatic pictures?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../SnapmaticWidget.cpp" line="153"/> + <source>Failed at deleting %1 from your Snapmatic pictures</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>UserInterface</name> + <message> + <location filename="../UserInterface.ui" line="20"/> + <location filename="../UserInterface.cpp" line="62"/> + <source>%2 - %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="74"/> + <source>Select profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="105"/> + <source>%1 %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="131"/> + <source>Reload profile overview</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="134"/> + <source>&Reload</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="150"/> + <source>Close %1</source> + <extracomment>Close %1 <- (gta5view/gta5sync) - %1 will be replaced automatically</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="153"/> + <source>&Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="179"/> + <source>&File</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="189"/> + <source>&Help</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="195"/> + <source>&Edit</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="201"/> + <source>&Profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="205"/> + <source>&Selection visibility</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="226"/> + <location filename="../UserInterface.cpp" line="60"/> + <location filename="../UserInterface.cpp" line="542"/> + <source>&About %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="229"/> + <source>Ctrl+P</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="234"/> + <source>&Exit</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="237"/> + <source>Exit</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="240"/> + <source>Ctrl+Q</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="245"/> + <source>Close &Profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="248"/> + <source>Ctrl+End</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="253"/> + <source>&Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="256"/> + <source>Ctrl+S</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="261"/> + <source>Select &All</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="264"/> + <source>Ctrl+A</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="269"/> + <source>&Deselect All</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="272"/> + <source>Ctrl+D</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="277"/> + <source>&Export selected...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="280"/> + <source>Ctrl+E</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="285"/> + <source>&Remove selected</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="288"/> + <source>Ctrl+Del</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="293"/> + <source>&Import files...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="296"/> + <source>Ctrl+I</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="301"/> + <source>&Open File...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="304"/> + <source>Ctrl+O</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="309"/> + <location filename="../UserInterface.cpp" line="163"/> + <source>Select &GTA V Folder...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="312"/> + <location filename="../OptionsDialog.cpp" line="445"/> + <location filename="../UserInterface.cpp" line="104"/> + <location filename="../UserInterface.cpp" line="513"/> + <source>Select GTA V Folder...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="315"/> + <source>Ctrl+G</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="320"/> + <source>Show In-gam&e</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="323"/> + <source>Shift+E</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="328"/> + <source>Hi&de In-game</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="331"/> + <source>Shift+D</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.cpp" line="64"/> + <location filename="../UserInterface.cpp" line="234"/> + <location filename="../UserInterface.cpp" line="550"/> + <source>Select Profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.cpp" line="360"/> + <source>Open File...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.cpp" line="407"/> + <location filename="../UserInterface.cpp" line="423"/> + <location filename="../UserInterface.cpp" line="450"/> + <location filename="../UserInterface.cpp" line="455"/> + <source>Open File</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.cpp" line="450"/> + <source>Can't open %1 because of not valid file format</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/main.cpp b/main.cpp index 0a6593b..8ba3e9b 100755 --- a/main.cpp +++ b/main.cpp @@ -1,493 +1,203 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "SnapmaticPicture.h" -#include "ProfileDatabase.h" -#include "DatabaseThread.h" -#include "SavegameDialog.h" -#include "PictureDialog.h" -#include "UserInterface.h" -#include "CrewDatabase.h" -#include "SavegameData.h" -#include "IconLoader.h" -#include "AppEnv.h" -#include "config.h" -#include <QDesktopWidget> -#include <QApplication> -#include <QStringList> -#include <QTranslator> -#include <QMessageBox> -#include <QFileInfo> -#include <QSysInfo> -#include <QRawFont> -#include <QObject> -#include <QString> -#include <QDebug> -#include <QFont> -#include <QFile> -#include <QDir> - -#ifdef GTA5SYNC_WIN -#include "windows.h" -#include <iostream> -#endif - -int main(int argc, char *argv[]) -{ - QApplication a(argc, argv); - a.setApplicationName(GTA5SYNC_APPSTR); - a.setApplicationVersion(GTA5SYNC_APPVER); - -#ifdef GTA5SYNC_WIN -#if QT_VERSION >= 0x050400 - if (QSysInfo::windowsVersion() >= 0x0080) - { - // Get Windows Font - NONCLIENTMETRICS ncm; - ncm.cbSize = sizeof(ncm); - SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0); - LOGFONTW uiFont = ncm.lfMessageFont; - QString uiFontStr(QString::fromStdWString(std::wstring(uiFont.lfFaceName))); - -#ifdef GTA5SYNC_DEBUG - QMessageBox::information(a.desktop(), QApplication::tr("Font"), QApplication::tr("Selected Font: %1").arg(uiFontStr)); -#endif - - // Set Application Font - QFont appFont(uiFontStr, 9); - a.setFont(appFont); - } -#endif -#endif - - QString pluginsDir = AppEnv::getPluginsFolder(); - if (QFileInfo(pluginsDir).exists()) - { - a.addLibraryPath(pluginsDir); - } - - // Loading translation settings - QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); - settings.beginGroup("Interface"); - QString language = settings.value("Language","System").toString(); - settings.endGroup(); - - // Start external translate loading - QString langpath = AppEnv::getLangFolder(); - bool trsf = false; - bool svlp = false; - QTranslator EappTranslator; - if (language == "System" || language.trimmed() == "") - { - QString languageName = QLocale::system().name(); - QStringList langList = languageName.split("_"); - if (langList.length() >= 1) - { - if (QFile::exists(langpath + QDir::separator() + "gta5sync_" + langList.at(0) + ".qm")) - { - EappTranslator.load(langpath + QDir::separator() + "/gta5sync_" + langList.at(0) + ".qm"); - QLocale::setDefault(QLocale::system()); - } - } - } - else - { - QString languageName = language; - QStringList langList = languageName.split("_"); - if (langList.length() >= 1) - { - if (QFile::exists(langpath + QDir::separator() + "gta5sync_" + langList.at(0) + ".qm")) - { - if (!EappTranslator.load(langpath + QDir::separator() + "gta5sync_" + langList.at(0) + ".qm")) - { - if (langList.at(0) != "en") - { - trsf = true; - } - } - else - { - QLocale::setDefault(QLocale(langList.at(0))); - svlp = true; - } - } - else - { - if (langList.at(0) != "en") - { - trsf = true; - } - } - } - } - if (trsf) - { - QString languageName = QLocale::system().name(); - QStringList langList = languageName.split("_"); - if (langList.length() >= 1) - { - if (QFile::exists(langpath + QDir::separator() + "gta5sync_" + langList.at(0) + ".qm")) - { - EappTranslator.load(langpath + QDir::separator() + "gta5sync_" + langList.at(0) + ".qm"); - QLocale::setDefault(QLocale(langList.at(0))); - } - } - } - a.installTranslator(&EappTranslator); -#if QT_VERSION >= 0x050000 - QTranslator EqtTranslator1; - if (language == "System" || language.trimmed() == "") - { - QString languageName = QLocale::system().name(); - QStringList langList = languageName.split("_"); - if (langList.length() >= 1) - { - if (QFile::exists(langpath + QDir::separator() + "qtbase_" + langList.at(0) + ".qm")) - { - EqtTranslator1.load(langpath + QDir::separator() + "qtbase_" + langList.at(0) + ".qm"); - } - } - } - else - { - QString languageName = language; - QStringList langList = languageName.split("_"); - if (langList.length() >= 1) - { - if (QFile::exists(langpath + QDir::separator() + "qtbase_" + langList.at(0) + ".qm")) - { - EqtTranslator1.load(langpath + QDir::separator() + "qtbase_" + langList.at(0) + ".qm"); - } - } - } - if (trsf) - { - QString languageName = QLocale::system().name(); - QStringList langList = languageName.split("_"); - if (langList.length() >= 1) - { - if (QFile::exists(langpath + QDir::separator() + "qtbase_" + langList.at(0) + ".qm")) - { - EqtTranslator1.load(langpath + QDir::separator() + "qtbase_" + langList.at(0) + ".qm"); - } - } - } - a.installTranslator(&EqtTranslator1); -#else - QTranslator EqtTranslator; - if (language == "System" || language.trimmed() == "") - { - QString languageName = QLocale::system().name(); - QStringList langList = languageName.split("_"); - if (langList.length() >= 1) - { - if (QFile::exists(langpath + QDir::separator() + "qt_" + langList.at(0) + ".qm")) - { - EqtTranslator.load(langpath + QDir::separator() + "qt_" + langList.at(0) + ".qm"); - } - } - } - else - { - QString languageName = language; - QStringList langList = languageName.split("_"); - if (langList.length() >= 1) - { - if (QFile::exists(langpath + QDir::separator() + "qt_" + langList.at(0) + ".qm")) - { - EqtTranslator.load(langpath + QDir::separator() + "qt_" + langList.at(0) + ".qm"); - } - } - } - if (trsf) - { - QString languageName = QLocale::system().name(); - QStringList langList = languageName.split("_"); - if (langList.length() >= 1) - { - if (QFile::exists(langpath + QDir::separator() + "qt_" + langList.at(0) + ".qm")) - { - EqtTranslator.load(langpath + QDir::separator() + "qt_" + langList.at(0) + ".qm"); - } - } - } - a.installTranslator(&EqtTranslator); -#endif - // End external translate loading - // Start internal translate loading - QTranslator appTranslator; - trsf = false; - if (language == "System" || language.trimmed() == "") - { - QString languageName = QLocale::system().name(); - QStringList langList = languageName.split("_"); - if (langList.length() >= 1) - { - if (QFile::exists(":/tr/gta5sync_" + langList.at(0) + ".qm")) - { - if (!appTranslator.load(":/tr/gta5sync_" + langList.at(0) + ".qm")) - { - if (langList.at(0) != "en") - { - if (svlp) { trsf = true; } - } - } - else - { - QLocale::setDefault(QLocale(langList.at(0))); - } - } - else - { - if (langList.at(0) != "en") - { - if (svlp) { trsf = true; } - } - } - } - } - else if (language == "en" || language == "English") - { - QLocale::setDefault(QLocale(QLocale::English, QLocale::AnyCountry)); - } - else - { - QString languageName = language; - QStringList langList = languageName.split("_"); - if (langList.length() >= 1) - { - if (QFile::exists(":/tr/gta5sync_" + langList.at(0) + ".qm")) - { - appTranslator.load(":/tr/gta5sync_" + langList.at(0) + ".qm"); - QLocale::setDefault(QLocale(langList.at(0))); - - } - } - } - if (trsf) - { - QString languageName = QLocale::system().name(); - QStringList langList = languageName.split("_"); - if (langList.length() >= 1) - { - if (QFile::exists(":/tr/gta5sync_" + langList.at(0) + ".qm")) - { - appTranslator.load(":/tr/gta5sync_" + langList.at(0) + ".qm"); - QLocale::setDefault(QLocale(langList.at(0))); - } - } - } - a.installTranslator(&appTranslator); -#if QT_VERSION >= 0x050000 - QTranslator qtTranslator1; - if (language == "System" || language.trimmed() == "") - { - QString languageName = QLocale::system().name(); - QStringList langList = languageName.split("_"); - if (langList.length() >= 1) - { - if (QFile::exists(":/tr/qtbase_" + langList.at(0) + ".qm")) - { - qtTranslator1.load(":/tr/qtbase_" + langList.at(0) + ".qm"); - } - } - } - else - { - QString languageName = language; - QStringList langList = languageName.split("_"); - if (langList.length() >= 1) - { - if (QFile::exists(":/tr/qtbase_" + langList.at(0) + ".qm")) - { - qtTranslator1.load(":/tr/qtbase_" + langList.at(0) + ".qm"); - } - } - } - if (trsf) - { - QString languageName = QLocale::system().name(); - QStringList langList = languageName.split("_"); - if (langList.length() >= 1) - { - if (QFile::exists(":/tr/qtbase_" + langList.at(0) + ".qm")) - { - qtTranslator1.load(":/tr/qtbase_" + langList.at(0) + ".qm"); - } - } - } - a.installTranslator(&qtTranslator1); -#else - QTranslator qtTranslator1; - if (language == "System" || language.trimmed() == "") - { - QString languageName = QLocale::system().name(); - QStringList langList = languageName.split("_"); - if (langList.length() >= 1) - { - if (QFile::exists(":/tr/qt_" + langList.at(0) + ".qm")) - { - qtTranslator1.load(":/tr/qt_" + langList.at(0) + ".qm"); - } - } - } - else - { - QString languageName = language; - QStringList langList = languageName.split("_"); - if (langList.length() >= 1) - { - if (QFile::exists(":/tr/qt_" + langList.at(0) + ".qm")) - { - qtTranslator1.load(":/tr/qt_" + langList.at(0) + ".qm"); - } - } - } - if (trsf) - { - QString languageName = QLocale::system().name(); - QStringList langList = languageName.split("_"); - if (langList.length() >= 1) - { - if (QFile::exists(":/tr/qt_" + langList.at(0) + ".qm")) - { - qtTranslator1.load(":/tr/qt_" + langList.at(0) + ".qm"); - } - } - } - a.installTranslator(&qtTranslator1); -#endif - // End internal translate loading - - QStringList applicationArgs = a.arguments(); - QString selectedAction; - QString arg1; - applicationArgs.removeAt(0); - - foreach(QString currentArg, applicationArgs) - { - QString reworkedArg; - if (currentArg.left(9) == "-showpic=" && selectedAction == "") - { - reworkedArg = currentArg.remove(0,9); - arg1 = reworkedArg; - selectedAction = "showpic"; - } - else if (currentArg.left(9) == "-showsgd=" && selectedAction == "") - { - reworkedArg = currentArg.remove(0,9); - arg1 = reworkedArg; - selectedAction = "showsgd"; - } - else if (selectedAction == "") - { - QFile argumentFile(currentArg); - QFileInfo argumentFileInfo(argumentFile); - if (argumentFile.exists()) - { - QString argumentFileName = argumentFileInfo.fileName(); - QString argumentFileType = argumentFileName.left(4); - QString argumentFileExt = argumentFileName.right(4); - - if (argumentFileType == "PGTA" || argumentFileExt == ".g5e") - { - arg1 = currentArg; - selectedAction = "showpic"; - } - else if (argumentFileType == "SGTA") - { - arg1 = currentArg; - selectedAction = "showsgd"; - } - else if (argumentFileType == "MISR") - { - arg1 = currentArg; - selectedAction = "showsgd"; - } - } - } - } - - if (selectedAction == "showpic") - { - CrewDatabase crewDB; - ProfileDatabase profileDB; - DatabaseThread threadDB(&crewDB); - PictureDialog picDialog(true, &profileDB, &crewDB); - SnapmaticPicture picture; - - bool readOk = picture.readingPictureFromFile(arg1); - picDialog.setWindowIcon(IconLoader::loadingAppIcon()); - picDialog.setSnapmaticPicture(&picture, readOk); - - int crewID = picture.getSnapmaticProperties().crewID; - if (crewID != 0) { crewDB.addCrew(crewID); } - if (!readOk) { return 1; } - - QEventLoop threadLoop; - QObject::connect(&threadDB, SIGNAL(playerNameFound(int, QString)), &profileDB, SLOT(setPlayerName(int, QString))); - QObject::connect(&threadDB, SIGNAL(playerNameUpdated()), &picDialog, SLOT(playerNameUpdated())); - QObject::connect(&threadDB, SIGNAL(finished()), &threadLoop, SLOT(quit())); - QObject::connect(&picDialog, SIGNAL(endDatabaseThread()), &threadDB, SLOT(doEndThread())); - threadDB.start(); - - picDialog.show(); - - threadLoop.exec(); - - return 0; - } - else if (selectedAction == "showsgd") - { - SavegameDialog savegameDialog; - SavegameData savegame; - - bool readOk = savegame.readingSavegameFromFile(arg1); - savegameDialog.setWindowIcon(IconLoader::loadingAppIcon()); - savegameDialog.setSavegameData(&savegame, arg1, readOk); - - if (!readOk) { return 1; } - - savegameDialog.show(); - - return a.exec(); - } - - CrewDatabase crewDB; - ProfileDatabase profileDB; - DatabaseThread threadDB(&crewDB); - - QEventLoop threadLoop; - QObject::connect(&threadDB, SIGNAL(playerNameFound(int, QString)), &profileDB, SLOT(setPlayerName(int, QString))); - QObject::connect(&threadDB, SIGNAL(finished()), &threadLoop, SLOT(quit())); - threadDB.start(); - - UserInterface uiWindow(&profileDB, &crewDB, &threadDB); - uiWindow.setWindowIcon(IconLoader::loadingAppIcon()); - uiWindow.setupDirEnv(); -#ifdef Q_OS_ANDROID - uiWindow.showMaximized(); -#else - uiWindow.show(); -#endif - - threadLoop.exec(); - - return 0; -} - +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "TranslationClass.h" +#include "SnapmaticPicture.h" +#include "ProfileDatabase.h" +#include "DatabaseThread.h" +#include "SavegameDialog.h" +#include "PictureDialog.h" +#include "UserInterface.h" +#include "CrewDatabase.h" +#include "SavegameData.h" +#include "IconLoader.h" +#include "AppEnv.h" +#include "config.h" +#include <QStringBuilder> +#include <QApplication> +#include <QStringList> +#include <QTranslator> +#include <QFileInfo> +#include <QSysInfo> +#include <QObject> +#include <QString> +#include <QDebug> +#include <QFont> +#include <QFile> + +#ifdef GTA5SYNC_WIN +#include "windows.h" +#include <iostream> +#endif + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + a.setApplicationName(GTA5SYNC_APPSTR); + a.setApplicationVersion(GTA5SYNC_APPVER); + +#ifdef GTA5SYNC_WIN +#if QT_VERSION >= 0x050400 + if (QSysInfo::windowsVersion() >= 0x0080) + { + // Get Windows Font + NONCLIENTMETRICS ncm; + ncm.cbSize = sizeof(ncm); + SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0); + LOGFONTW uiFont = ncm.lfMessageFont; + QString uiFontStr(QString::fromStdWString(std::wstring(uiFont.lfFaceName))); + +#ifdef GTA5SYNC_DEBUG + qDebug() << QApplication::tr("Font") << QApplication::tr("Selected Font: %1").arg(uiFontStr); +#endif + + // Set Application Font + QFont appFont(uiFontStr, 9); + a.setFont(appFont); + } +#endif +#endif + + QString pluginsDir = AppEnv::getPluginsFolder(); + if (QFileInfo(pluginsDir).exists()) + { + a.addLibraryPath(pluginsDir); + } + + TCInstance->initUserLanguage(); + TCInstance->loadTranslation(&a); + + QStringList applicationArgs = a.arguments(); + QString selectedAction; + QString arg1; + applicationArgs.removeAt(0); + + foreach(QString currentArg, applicationArgs) + { + QString reworkedArg; + if (currentArg.left(9) == "-showpic=" && selectedAction == "") + { + reworkedArg = currentArg.remove(0,9); + arg1 = reworkedArg; + selectedAction = "showpic"; + } + else if (currentArg.left(9) == "-showsgd=" && selectedAction == "") + { + reworkedArg = currentArg.remove(0,9); + arg1 = reworkedArg; + selectedAction = "showsgd"; + } + else if (selectedAction == "") + { + QFile argumentFile(currentArg); + QFileInfo argumentFileInfo(argumentFile); + if (argumentFile.exists()) + { + QString argumentFileName = argumentFileInfo.fileName(); + QString argumentFileType = argumentFileName.left(4); + QString argumentFileExt = argumentFileName.right(4); + + if (argumentFileType == "PGTA" || argumentFileExt == ".g5e") + { + arg1 = currentArg; + selectedAction = "showpic"; + } + else if (argumentFileType == "SGTA") + { + arg1 = currentArg; + selectedAction = "showsgd"; + } + else if (argumentFileType == "MISR") + { + arg1 = currentArg; + selectedAction = "showsgd"; + } + } + } + } + + if (selectedAction == "showpic") + { + CrewDatabase crewDB; + ProfileDatabase profileDB; + DatabaseThread threadDB(&crewDB); + PictureDialog picDialog(true, &profileDB, &crewDB); + SnapmaticPicture picture; + + bool readOk = picture.readingPictureFromFile(arg1); + picDialog.setWindowIcon(IconLoader::loadingAppIcon()); + picDialog.setSnapmaticPicture(&picture, readOk); + + int crewID = picture.getSnapmaticProperties().crewID; + if (crewID != 0) { crewDB.addCrew(crewID); } + if (!readOk) { return 1; } + + QEventLoop threadLoop; + QObject::connect(&threadDB, SIGNAL(crewNameFound(int, QString)), &crewDB, SLOT(setCrewName(int, QString))); + QObject::connect(&threadDB, SIGNAL(crewNameUpdated()), &picDialog, SLOT(crewNameUpdated())); + QObject::connect(&threadDB, SIGNAL(playerNameFound(int, QString)), &profileDB, SLOT(setPlayerName(int, QString))); + QObject::connect(&threadDB, SIGNAL(playerNameUpdated()), &picDialog, SLOT(playerNameUpdated())); + QObject::connect(&threadDB, SIGNAL(finished()), &threadLoop, SLOT(quit())); + QObject::connect(&picDialog, SIGNAL(endDatabaseThread()), &threadDB, SLOT(doEndThread())); + threadDB.start(); + + picDialog.show(); + + threadLoop.exec(); + + return 0; + } + else if (selectedAction == "showsgd") + { + SavegameDialog savegameDialog; + SavegameData savegame; + + bool readOk = savegame.readingSavegameFromFile(arg1); + savegameDialog.setWindowIcon(IconLoader::loadingAppIcon()); + savegameDialog.setSavegameData(&savegame, arg1, readOk); + + if (!readOk) { return 1; } + + savegameDialog.show(); + + return a.exec(); + } + + CrewDatabase crewDB; + ProfileDatabase profileDB; + DatabaseThread threadDB(&crewDB); + + QEventLoop threadLoop; + QObject::connect(&threadDB, SIGNAL(crewNameFound(int,QString)), &crewDB, SLOT(setCrewName(int, QString))); + QObject::connect(&threadDB, SIGNAL(playerNameFound(int, QString)), &profileDB, SLOT(setPlayerName(int, QString))); + QObject::connect(&threadDB, SIGNAL(finished()), &threadLoop, SLOT(quit())); + threadDB.start(); + + UserInterface uiWindow(&profileDB, &crewDB, &threadDB); + uiWindow.setWindowIcon(IconLoader::loadingAppIcon()); + uiWindow.setupDirEnv(); +#ifdef Q_OS_ANDROID + uiWindow.showMaximized(); +#else + uiWindow.show(); +#endif + + threadLoop.exec(); + + return 0; +} diff --git a/qjson4/QJsonArray b/qjson4/QJsonArray index 93afb31..89dbf4e 100755 --- a/qjson4/QJsonArray +++ b/qjson4/QJsonArray @@ -1 +1 @@ -#include "QJsonArray.h" +#include "QJsonArray.h" diff --git a/qjson4/QJsonArray.cpp b/qjson4/QJsonArray.cpp index f932825..531941f 100755 --- a/qjson4/QJsonArray.cpp +++ b/qjson4/QJsonArray.cpp @@ -1,410 +1,410 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "QJsonArray.h" -#include "QJsonValueRef.h" -#include "QJsonValue.h" -#include <QtCore/QStringList> - -#if QT_VERSION < 0x050000 - -//------------------------------------------------------------------------------ -// Name: QJsonArray -// Desc: default constructor -//------------------------------------------------------------------------------ -QJsonArray::QJsonArray() { - -} - -//------------------------------------------------------------------------------ -// Name: QJsonArray -// Desc: copy constructor -//------------------------------------------------------------------------------ -QJsonArray::QJsonArray(const QJsonArray &other) : values_(other.values_) { - -} - -#if __cplusplus >= 201103L -//------------------------------------------------------------------------------ -// Name: QJsonArray -// Desc: Creates an array initialized from args initialization list. -//------------------------------------------------------------------------------ -QJsonArray::QJsonArray(std::initializer_list<QJsonValue> args) { - for(const QJsonValue &arg : args) { - values_.append(arg); - } -} -#endif - -//------------------------------------------------------------------------------ -// Name: ~QJsonArray -// Desc: destructor -//------------------------------------------------------------------------------ -QJsonArray::~QJsonArray() { - -} - -//------------------------------------------------------------------------------ -// Name: operator= -// Desc: assignment operator -//------------------------------------------------------------------------------ -QJsonArray &QJsonArray::operator=(const QJsonArray &other) { - QJsonArray(other).swap(*this); - return *this; -} - -//------------------------------------------------------------------------------ -// Name: operator+= -// Desc: -//------------------------------------------------------------------------------ -QJsonArray &QJsonArray::operator+=(const QJsonValue &value) { - values_.append(value); - return *this; -} - -//------------------------------------------------------------------------------ -// Name: operator<< -// Desc: -//------------------------------------------------------------------------------ -QJsonArray &QJsonArray::operator<<(const QJsonValue &value) { - values_.append(value); - return *this; -} - -//------------------------------------------------------------------------------ -// Name: operator+ -// Desc: -//------------------------------------------------------------------------------ -QJsonArray QJsonArray::operator+(const QJsonValue &value) const { - QJsonArray arr(*this); - arr.append(value); - return arr; -} - -//------------------------------------------------------------------------------ -// Name: operator!= -// Desc: returns true if the compared array IS NOT equal to this -//------------------------------------------------------------------------------ -bool QJsonArray::operator!=(const QJsonArray &other) const { - return values_ != other.values_; -} - -//------------------------------------------------------------------------------ -// Name: operator== -// Desc: returns true if the compared array IS equal to this -//------------------------------------------------------------------------------ -bool QJsonArray::operator==(const QJsonArray &other) const { - return values_ == other.values_; -} - -//------------------------------------------------------------------------------ -// Name: begin -// Desc: returns an iterator to the first contained element -//------------------------------------------------------------------------------ -QJsonArray::const_iterator QJsonArray::begin() const { - return values_.begin(); -} - -//------------------------------------------------------------------------------ -// Name: end -// Desc: returns an iterator to one past the last contained element -//------------------------------------------------------------------------------ -QJsonArray::const_iterator QJsonArray::end() const { - return values_.end(); -} - -//------------------------------------------------------------------------------ -// Name: begin -// Desc: returns an iterator to the first contained element -//------------------------------------------------------------------------------ -QJsonArray::iterator QJsonArray::begin() { - return values_.begin(); -} - -//------------------------------------------------------------------------------ -// Name: end -// Desc: returns an iterator to one past the last contained element -//------------------------------------------------------------------------------ -QJsonArray::iterator QJsonArray::end() { - return values_.end(); -} - -//------------------------------------------------------------------------------ -// Name: constBegin -// Desc: returns an iterator to the first contained element -//------------------------------------------------------------------------------ -QJsonArray::const_iterator QJsonArray::constBegin() const { - return begin(); -} - -//------------------------------------------------------------------------------ -// Name: constEnd -// Desc: returns an iterator to one past the last contained element -//------------------------------------------------------------------------------ -QJsonArray::const_iterator QJsonArray::constEnd() const { - return end(); -} - -//------------------------------------------------------------------------------ -// Name: first -// Desc: returns the first element by value -//------------------------------------------------------------------------------ -QJsonValue QJsonArray::first() const { - Q_ASSERT(!empty()); - return values_.first(); -} - -//------------------------------------------------------------------------------ -// Name: last -// Desc: returns the last element by value -//------------------------------------------------------------------------------ -QJsonValue QJsonArray::last() const { - Q_ASSERT(!empty()); - return values_.last(); -} - -//------------------------------------------------------------------------------ -// Name: operator[] -//------------------------------------------------------------------------------ -QJsonValueRef QJsonArray::operator[](int i) { - return QJsonValueRef(this, i); -} - -//------------------------------------------------------------------------------ -// Name: operator[] -//------------------------------------------------------------------------------ -QJsonValue QJsonArray::operator[](int i) const { - return values_[i]; -} - -//------------------------------------------------------------------------------ -// Name: at -//------------------------------------------------------------------------------ -QJsonValue QJsonArray::at(int i) const { - return values_.at(i); -} - -//------------------------------------------------------------------------------ -// Name: size -//------------------------------------------------------------------------------ -int QJsonArray::size() const { - return values_.size(); -} - -//------------------------------------------------------------------------------ -// Name: count -//------------------------------------------------------------------------------ -int QJsonArray::count() const { - return size(); -} - -//------------------------------------------------------------------------------ -// Name: empty -//------------------------------------------------------------------------------ -bool QJsonArray::empty() const { - return values_.empty(); -} - -//------------------------------------------------------------------------------ -// Name: isEmpty -//------------------------------------------------------------------------------ -bool QJsonArray::isEmpty() const { - return empty(); -} - -//------------------------------------------------------------------------------ -// Name: pop_back -//------------------------------------------------------------------------------ -void QJsonArray::pop_back() { - values_.pop_back(); -} - -//------------------------------------------------------------------------------ -// Name: pop_front -//------------------------------------------------------------------------------ -void QJsonArray::pop_front() { - values_.pop_front(); -} - -//------------------------------------------------------------------------------ -// Name: push_back -//------------------------------------------------------------------------------ -void QJsonArray::push_back(const QJsonValue &value) { - values_.push_back(value); -} - -//------------------------------------------------------------------------------ -// Name: push_front -//------------------------------------------------------------------------------ -void QJsonArray::push_front(const QJsonValue &value) { - values_.push_front(value); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -void QJsonArray::append(const QJsonValue &value) { - values_.append(value); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -bool QJsonArray::contains(const QJsonValue &value) const { - return values_.contains(value); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonArray::iterator QJsonArray::erase(iterator it) { - return values_.erase(it); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -void QJsonArray::insert(int i, const QJsonValue &value) { - values_.insert(i, value); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonArray::iterator QJsonArray::insert(iterator before, const QJsonValue &value) { - return values_.insert(before, value); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -void QJsonArray::prepend(const QJsonValue &value) { - values_.prepend(value); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -void QJsonArray::removeAt(int i) { - values_.removeAt(i); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -void QJsonArray::removeFirst() { - values_.removeFirst(); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -void QJsonArray::removeLast() { - values_.removeLast(); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -void QJsonArray::replace(int i, const QJsonValue &value) { - values_.replace(i, value); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonValue QJsonArray::takeAt(int i) { - return values_.takeAt(i); -} - -//------------------------------------------------------------------------------ -// Name: toVariantList -//------------------------------------------------------------------------------ -QVariantList QJsonArray::toVariantList() const { - QVariantList a; - Q_FOREACH(const QJsonValue &v, *this) { - a.push_back(v.toVariant()); - } - return a; -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonArray QJsonArray::fromStringList(const QStringList &list) { - QJsonArray a; - Q_FOREACH(const QString &s, list) { - a.push_back(QJsonValue(s)); - } - return a; -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonArray QJsonArray::fromVariantList(const QVariantList &list) { - QJsonArray a; - Q_FOREACH(const QVariant &v, list) { - a.push_back(QJsonValue::fromVariant(v)); - } - return a; -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonRoot *QJsonArray::clone() const { - return new QJsonArray(*this); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -const QJsonObject *QJsonArray::toObject() const { - return 0; -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonObject *QJsonArray::toObject() { - return 0; -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonArray *QJsonArray::toArray() { - return this; -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -const QJsonArray *QJsonArray::toArray() const { - return this; -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -void QJsonArray::swap(QJsonArray &other) { - qSwap(values_, other.values_); -} - -#endif +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "QJsonArray.h" +#include "QJsonValueRef.h" +#include "QJsonValue.h" +#include <QtCore/QStringList> + +#if QT_VERSION < 0x050000 + +//------------------------------------------------------------------------------ +// Name: QJsonArray +// Desc: default constructor +//------------------------------------------------------------------------------ +QJsonArray::QJsonArray() { + +} + +//------------------------------------------------------------------------------ +// Name: QJsonArray +// Desc: copy constructor +//------------------------------------------------------------------------------ +QJsonArray::QJsonArray(const QJsonArray &other) : values_(other.values_) { + +} + +#if __cplusplus >= 201103L +//------------------------------------------------------------------------------ +// Name: QJsonArray +// Desc: Creates an array initialized from args initialization list. +//------------------------------------------------------------------------------ +QJsonArray::QJsonArray(std::initializer_list<QJsonValue> args) { + for(const QJsonValue &arg : args) { + values_.append(arg); + } +} +#endif + +//------------------------------------------------------------------------------ +// Name: ~QJsonArray +// Desc: destructor +//------------------------------------------------------------------------------ +QJsonArray::~QJsonArray() { + +} + +//------------------------------------------------------------------------------ +// Name: operator= +// Desc: assignment operator +//------------------------------------------------------------------------------ +QJsonArray &QJsonArray::operator=(const QJsonArray &other) { + QJsonArray(other).swap(*this); + return *this; +} + +//------------------------------------------------------------------------------ +// Name: operator+= +// Desc: +//------------------------------------------------------------------------------ +QJsonArray &QJsonArray::operator+=(const QJsonValue &value) { + values_.append(value); + return *this; +} + +//------------------------------------------------------------------------------ +// Name: operator<< +// Desc: +//------------------------------------------------------------------------------ +QJsonArray &QJsonArray::operator<<(const QJsonValue &value) { + values_.append(value); + return *this; +} + +//------------------------------------------------------------------------------ +// Name: operator+ +// Desc: +//------------------------------------------------------------------------------ +QJsonArray QJsonArray::operator+(const QJsonValue &value) const { + QJsonArray arr(*this); + arr.append(value); + return arr; +} + +//------------------------------------------------------------------------------ +// Name: operator!= +// Desc: returns true if the compared array IS NOT equal to this +//------------------------------------------------------------------------------ +bool QJsonArray::operator!=(const QJsonArray &other) const { + return values_ != other.values_; +} + +//------------------------------------------------------------------------------ +// Name: operator== +// Desc: returns true if the compared array IS equal to this +//------------------------------------------------------------------------------ +bool QJsonArray::operator==(const QJsonArray &other) const { + return values_ == other.values_; +} + +//------------------------------------------------------------------------------ +// Name: begin +// Desc: returns an iterator to the first contained element +//------------------------------------------------------------------------------ +QJsonArray::const_iterator QJsonArray::begin() const { + return values_.begin(); +} + +//------------------------------------------------------------------------------ +// Name: end +// Desc: returns an iterator to one past the last contained element +//------------------------------------------------------------------------------ +QJsonArray::const_iterator QJsonArray::end() const { + return values_.end(); +} + +//------------------------------------------------------------------------------ +// Name: begin +// Desc: returns an iterator to the first contained element +//------------------------------------------------------------------------------ +QJsonArray::iterator QJsonArray::begin() { + return values_.begin(); +} + +//------------------------------------------------------------------------------ +// Name: end +// Desc: returns an iterator to one past the last contained element +//------------------------------------------------------------------------------ +QJsonArray::iterator QJsonArray::end() { + return values_.end(); +} + +//------------------------------------------------------------------------------ +// Name: constBegin +// Desc: returns an iterator to the first contained element +//------------------------------------------------------------------------------ +QJsonArray::const_iterator QJsonArray::constBegin() const { + return begin(); +} + +//------------------------------------------------------------------------------ +// Name: constEnd +// Desc: returns an iterator to one past the last contained element +//------------------------------------------------------------------------------ +QJsonArray::const_iterator QJsonArray::constEnd() const { + return end(); +} + +//------------------------------------------------------------------------------ +// Name: first +// Desc: returns the first element by value +//------------------------------------------------------------------------------ +QJsonValue QJsonArray::first() const { + Q_ASSERT(!empty()); + return values_.first(); +} + +//------------------------------------------------------------------------------ +// Name: last +// Desc: returns the last element by value +//------------------------------------------------------------------------------ +QJsonValue QJsonArray::last() const { + Q_ASSERT(!empty()); + return values_.last(); +} + +//------------------------------------------------------------------------------ +// Name: operator[] +//------------------------------------------------------------------------------ +QJsonValueRef QJsonArray::operator[](int i) { + return QJsonValueRef(this, i); +} + +//------------------------------------------------------------------------------ +// Name: operator[] +//------------------------------------------------------------------------------ +QJsonValue QJsonArray::operator[](int i) const { + return values_[i]; +} + +//------------------------------------------------------------------------------ +// Name: at +//------------------------------------------------------------------------------ +QJsonValue QJsonArray::at(int i) const { + return values_.at(i); +} + +//------------------------------------------------------------------------------ +// Name: size +//------------------------------------------------------------------------------ +int QJsonArray::size() const { + return values_.size(); +} + +//------------------------------------------------------------------------------ +// Name: count +//------------------------------------------------------------------------------ +int QJsonArray::count() const { + return size(); +} + +//------------------------------------------------------------------------------ +// Name: empty +//------------------------------------------------------------------------------ +bool QJsonArray::empty() const { + return values_.empty(); +} + +//------------------------------------------------------------------------------ +// Name: isEmpty +//------------------------------------------------------------------------------ +bool QJsonArray::isEmpty() const { + return empty(); +} + +//------------------------------------------------------------------------------ +// Name: pop_back +//------------------------------------------------------------------------------ +void QJsonArray::pop_back() { + values_.pop_back(); +} + +//------------------------------------------------------------------------------ +// Name: pop_front +//------------------------------------------------------------------------------ +void QJsonArray::pop_front() { + values_.pop_front(); +} + +//------------------------------------------------------------------------------ +// Name: push_back +//------------------------------------------------------------------------------ +void QJsonArray::push_back(const QJsonValue &value) { + values_.push_back(value); +} + +//------------------------------------------------------------------------------ +// Name: push_front +//------------------------------------------------------------------------------ +void QJsonArray::push_front(const QJsonValue &value) { + values_.push_front(value); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +void QJsonArray::append(const QJsonValue &value) { + values_.append(value); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +bool QJsonArray::contains(const QJsonValue &value) const { + return values_.contains(value); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonArray::iterator QJsonArray::erase(iterator it) { + return values_.erase(it); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +void QJsonArray::insert(int i, const QJsonValue &value) { + values_.insert(i, value); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonArray::iterator QJsonArray::insert(iterator before, const QJsonValue &value) { + return values_.insert(before, value); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +void QJsonArray::prepend(const QJsonValue &value) { + values_.prepend(value); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +void QJsonArray::removeAt(int i) { + values_.removeAt(i); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +void QJsonArray::removeFirst() { + values_.removeFirst(); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +void QJsonArray::removeLast() { + values_.removeLast(); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +void QJsonArray::replace(int i, const QJsonValue &value) { + values_.replace(i, value); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonValue QJsonArray::takeAt(int i) { + return values_.takeAt(i); +} + +//------------------------------------------------------------------------------ +// Name: toVariantList +//------------------------------------------------------------------------------ +QVariantList QJsonArray::toVariantList() const { + QVariantList a; + Q_FOREACH(const QJsonValue &v, *this) { + a.push_back(v.toVariant()); + } + return a; +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonArray QJsonArray::fromStringList(const QStringList &list) { + QJsonArray a; + Q_FOREACH(const QString &s, list) { + a.push_back(QJsonValue(s)); + } + return a; +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonArray QJsonArray::fromVariantList(const QVariantList &list) { + QJsonArray a; + Q_FOREACH(const QVariant &v, list) { + a.push_back(QJsonValue::fromVariant(v)); + } + return a; +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonRoot *QJsonArray::clone() const { + return new QJsonArray(*this); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +const QJsonObject *QJsonArray::toObject() const { + return 0; +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonObject *QJsonArray::toObject() { + return 0; +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonArray *QJsonArray::toArray() { + return this; +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +const QJsonArray *QJsonArray::toArray() const { + return this; +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +void QJsonArray::swap(QJsonArray &other) { + qSwap(values_, other.values_); +} + +#endif diff --git a/qjson4/QJsonArray.h b/qjson4/QJsonArray.h index 2e443b4..94aab1b 100755 --- a/qjson4/QJsonArray.h +++ b/qjson4/QJsonArray.h @@ -1,139 +1,139 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef QJSON_ARRAY_H_ -#define QJSON_ARRAY_H_ - -#include <QtCore/QtGlobal> - -#if QT_VERSION >= 0x050000 -#include <QtCore/QJsonArray> -#else - -#include "QJsonRoot.h" -#include <QtCore/QList> -#include <QtCore/QVariantList> - -class QJsonValue; -class QJsonValueRef; - -class QJsonArray : public QJsonRoot { - friend class QJsonDocument; - friend class QJsonValue; - friend class QJsonValueRef; - friend class QJsonParser; -public: - // TODO(eteran): manually implement the array, for now we use QList - // but the real thing has a custom implementation - // I guess for the purposes of less interdependancies? - // maybe so it's easier to forward declare the iterators? - - typedef QList<QJsonValue>::const_iterator const_iterator; - typedef QList<QJsonValue>::iterator iterator; - typedef const_iterator ConstIterator; - typedef iterator Iterator; - typedef QList<QJsonValue>::const_pointer const_pointer; - typedef QList<QJsonValue>::const_reference const_reference; - typedef QList<QJsonValue>::difference_type difference_type; - typedef QList<QJsonValue>::pointer pointer; - typedef QList<QJsonValue>::reference reference; - typedef QList<QJsonValue>::size_type size_type; - typedef QList<QJsonValue>::value_type value_type; - -public: - QJsonArray(); - QJsonArray(const QJsonArray &other); -#if __cplusplus >= 201103L - QJsonArray(std::initializer_list<QJsonValue> args); -#endif - ~QJsonArray(); - -public: - QJsonArray &operator=(const QJsonArray &other); - -public: - bool operator!=(const QJsonArray &other) const; - bool operator==(const QJsonArray &other) const; - QJsonArray operator+(const QJsonValue &value) const; - QJsonArray &operator+=(const QJsonValue &value); - QJsonArray &operator<<(const QJsonValue &value); - -public: - const_iterator begin() const; - const_iterator end() const; - iterator begin(); - iterator end(); - const_iterator constBegin() const; - const_iterator constEnd() const; - -public: - QJsonValueRef operator[](int i); - QJsonValue operator[](int i) const; - QJsonValue at(int i) const; - QJsonValue first() const; - QJsonValue last() const; - -public: - int size() const; - int count() const; - bool empty() const; - bool isEmpty() const; - -public: - void pop_back(); - void pop_front(); - void push_back(const QJsonValue &value); - void push_front(const QJsonValue &value); - -public: - void append(const QJsonValue &value); - bool contains(const QJsonValue &value) const; - iterator erase(iterator it); - void insert(int i, const QJsonValue &value); - iterator insert(iterator before, const QJsonValue &value); - void prepend(const QJsonValue &value); - void removeAt(int i); - void removeFirst(); - void removeLast(); - void replace(int i, const QJsonValue &value); - QJsonValue takeAt(int i); - -public: - QVariantList toVariantList() const; - -public: - static QJsonArray fromStringList(const QStringList &list); - static QJsonArray fromVariantList(const QVariantList &list); - -private: - virtual QJsonRoot *clone() const; - virtual QJsonArray *toArray(); - virtual QJsonObject *toObject(); - virtual const QJsonArray *toArray() const; - virtual const QJsonObject *toObject() const; - -private: - void swap(QJsonArray &other); - -private: - QList<QJsonValue> values_; -}; - -#endif - -#endif +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef QJSON_ARRAY_H_ +#define QJSON_ARRAY_H_ + +#include <QtCore/QtGlobal> + +#if QT_VERSION >= 0x050000 +#include <QtCore/QJsonArray> +#else + +#include "QJsonRoot.h" +#include <QtCore/QList> +#include <QtCore/QVariantList> + +class QJsonValue; +class QJsonValueRef; + +class QJsonArray : public QJsonRoot { + friend class QJsonDocument; + friend class QJsonValue; + friend class QJsonValueRef; + friend class QJsonParser; +public: + // TODO(eteran): manually implement the array, for now we use QList + // but the real thing has a custom implementation + // I guess for the purposes of less interdependancies? + // maybe so it's easier to forward declare the iterators? + + typedef QList<QJsonValue>::const_iterator const_iterator; + typedef QList<QJsonValue>::iterator iterator; + typedef const_iterator ConstIterator; + typedef iterator Iterator; + typedef QList<QJsonValue>::const_pointer const_pointer; + typedef QList<QJsonValue>::const_reference const_reference; + typedef QList<QJsonValue>::difference_type difference_type; + typedef QList<QJsonValue>::pointer pointer; + typedef QList<QJsonValue>::reference reference; + typedef QList<QJsonValue>::size_type size_type; + typedef QList<QJsonValue>::value_type value_type; + +public: + QJsonArray(); + QJsonArray(const QJsonArray &other); +#if __cplusplus >= 201103L + QJsonArray(std::initializer_list<QJsonValue> args); +#endif + ~QJsonArray(); + +public: + QJsonArray &operator=(const QJsonArray &other); + +public: + bool operator!=(const QJsonArray &other) const; + bool operator==(const QJsonArray &other) const; + QJsonArray operator+(const QJsonValue &value) const; + QJsonArray &operator+=(const QJsonValue &value); + QJsonArray &operator<<(const QJsonValue &value); + +public: + const_iterator begin() const; + const_iterator end() const; + iterator begin(); + iterator end(); + const_iterator constBegin() const; + const_iterator constEnd() const; + +public: + QJsonValueRef operator[](int i); + QJsonValue operator[](int i) const; + QJsonValue at(int i) const; + QJsonValue first() const; + QJsonValue last() const; + +public: + int size() const; + int count() const; + bool empty() const; + bool isEmpty() const; + +public: + void pop_back(); + void pop_front(); + void push_back(const QJsonValue &value); + void push_front(const QJsonValue &value); + +public: + void append(const QJsonValue &value); + bool contains(const QJsonValue &value) const; + iterator erase(iterator it); + void insert(int i, const QJsonValue &value); + iterator insert(iterator before, const QJsonValue &value); + void prepend(const QJsonValue &value); + void removeAt(int i); + void removeFirst(); + void removeLast(); + void replace(int i, const QJsonValue &value); + QJsonValue takeAt(int i); + +public: + QVariantList toVariantList() const; + +public: + static QJsonArray fromStringList(const QStringList &list); + static QJsonArray fromVariantList(const QVariantList &list); + +private: + virtual QJsonRoot *clone() const; + virtual QJsonArray *toArray(); + virtual QJsonObject *toObject(); + virtual const QJsonArray *toArray() const; + virtual const QJsonObject *toObject() const; + +private: + void swap(QJsonArray &other); + +private: + QList<QJsonValue> values_; +}; + +#endif + +#endif diff --git a/qjson4/QJsonDocument b/qjson4/QJsonDocument index dabae9b..f652bf4 100755 --- a/qjson4/QJsonDocument +++ b/qjson4/QJsonDocument @@ -1 +1 @@ -#include "QJsonDocument.h" +#include "QJsonDocument.h" diff --git a/qjson4/QJsonDocument.cpp b/qjson4/QJsonDocument.cpp index 712a96d..59adf32 100755 --- a/qjson4/QJsonDocument.cpp +++ b/qjson4/QJsonDocument.cpp @@ -1,417 +1,417 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "QJsonDocument.h" -#include "QJsonObject.h" -#include "QJsonArray.h" -#include "QJsonParser.h" - -#include <QtCore/QStringList> -#include <QtCore/QByteArray> -#include <QtCore/QTextStream> -#include <QtCore/QTextCodec> -#include <QtCore/QtCore> - -#if QT_VERSION < 0x050000 - -//------------------------------------------------------------------------------ -// Name: QJsonDocument -//------------------------------------------------------------------------------ -QJsonDocument::QJsonDocument() : root_(0) { -} - -//------------------------------------------------------------------------------ -// Name: QJsonDocument -//------------------------------------------------------------------------------ -QJsonDocument::QJsonDocument(const QJsonObject &object) : root_(0) { - setObject(object); -} - -//------------------------------------------------------------------------------ -// Name: QJsonDocument -//------------------------------------------------------------------------------ -QJsonDocument::QJsonDocument(const QJsonArray &array) : root_(0) { - setArray(array); -} - -//------------------------------------------------------------------------------ -// Name: QJsonDocument -//------------------------------------------------------------------------------ -QJsonDocument::QJsonDocument(const QJsonDocument &other) : root_(0) { - if(other.root_) { - root_ = other.root_->clone(); - } -} - -//------------------------------------------------------------------------------ -// Name: ~QJsonDocument -//------------------------------------------------------------------------------ -QJsonDocument::~QJsonDocument() { - delete root_; -} - -//------------------------------------------------------------------------------ -// Name: operator= -//------------------------------------------------------------------------------ -QJsonDocument &QJsonDocument::operator=(const QJsonDocument &other) { - QJsonDocument(other).swap(*this); - return *this; -} - -//------------------------------------------------------------------------------ -// Name: operator!= -//------------------------------------------------------------------------------ -bool QJsonDocument::operator!=(const QJsonDocument &other) const { - return !(*this == other); -} - -//------------------------------------------------------------------------------ -// Name: operator== -//------------------------------------------------------------------------------ -bool QJsonDocument::operator==(const QJsonDocument &other) const { - - if(isArray() && other.isArray()) { - return array() == other.array(); - } - - if(isObject() && other.isObject()) { - return object() == other.object(); - } - - if(isEmpty() && other.isEmpty()) { - return true; - } - - if(isNull() && other.isNull()) { - return true; - } - - return false; -} - -//------------------------------------------------------------------------------ -// Name: isArray -//------------------------------------------------------------------------------ -bool QJsonDocument::isArray() const { - return root_ && root_->toArray(); -} - -//------------------------------------------------------------------------------ -// Name: isEmpty -//------------------------------------------------------------------------------ -bool QJsonDocument::isEmpty() const { - - // TODO(eteran): figure out the rules here that Qt5 uses - // it *looks* like they define empty as being NULL - // which is obviously different than this - - return !root_; -} - -//------------------------------------------------------------------------------ -// Name: isNull -//------------------------------------------------------------------------------ -bool QJsonDocument::isNull() const { - return !root_; -} - -//------------------------------------------------------------------------------ -// Name: isObject -//------------------------------------------------------------------------------ -bool QJsonDocument::isObject() const { - return root_ && root_->toObject(); -} - -//------------------------------------------------------------------------------ -// Name: setArray -//------------------------------------------------------------------------------ -void QJsonDocument::setArray(const QJsonArray &array) { - setRoot(array); -} - -//------------------------------------------------------------------------------ -// Name: setObject -//------------------------------------------------------------------------------ -void QJsonDocument::setObject(const QJsonObject &object) { - setRoot(object); -} - -//------------------------------------------------------------------------------ -// Name: setRoot -//------------------------------------------------------------------------------ -void QJsonDocument::setRoot(const QJsonRoot &root) { - delete root_; - root_ = root.clone(); -} - -//------------------------------------------------------------------------------ -// Name: toBinaryData -//------------------------------------------------------------------------------ -QByteArray QJsonDocument::toBinaryData() const { - QByteArray r; - // TODO(eteran): implement this - return r; -} - -//------------------------------------------------------------------------------ -// Name: escapeString -//------------------------------------------------------------------------------ -QString QJsonDocument::escapeString(const QString &s) const { - - QString r; - - Q_FOREACH(QChar ch, s) { - switch(ch.toLatin1()) { - case '\"': r.append("\\\""); break; - case '\\': r.append("\\\\"); break; - #if 0 - case '/': r.append("\\/"); break; - #endif - case '\b': r.append("\\b"); break; - case '\f': r.append("\\f"); break; - case '\n': r.append("\\n"); break; - case '\r': r.append("\\r"); break; - case '\t': r.append("\\t"); break; - default: - r += ch; - break; - } - } - - return r; -} - -//------------------------------------------------------------------------------ -// Name: toJson -//------------------------------------------------------------------------------ -QString QJsonDocument::toJson(const QJsonValue &v, JsonFormat format) const { - - QString b; - QTextStream ss(&b, QIODevice::WriteOnly | QIODevice::Text); - - switch(v.type()) { - case QJsonValue::Null: - ss << "null"; - break; - case QJsonValue::Bool: - ss << (v.toBool() ? "true" : "false"); - break; - case QJsonValue::Double: - { - double d = v.toDouble (); - if (qIsFinite(d)) { - // +2 to format to ensure the expected precision - ss << QByteArray::number(d, 'g', 15 + 2); // ::digits10 is 15 - } else { - ss << "null"; // +INF || -INF || NaN (see RFC4627#section2.4) - } - } - break; - case QJsonValue::String: - ss << '"' << escapeString(v.toString()) << '"'; - break; - case QJsonValue::Array: - { - const QJsonArray a = v.toArray(); - ss << "["; - if(!a.empty()) { - QJsonArray::const_iterator it = a.begin(); - QJsonArray::const_iterator e = a.end(); - - ss << toJson(*it++, format); - - for(;it != e; ++it) { - ss << ','; - ss << toJson(*it, format); - } - } - ss << "]"; - } - break; - case QJsonValue::Object: - { - const QJsonObject o = v.toObject(); - ss << "{"; - if(!o.empty()) { - QJsonObject::const_iterator it = o.begin(); - QJsonObject::const_iterator e = o.end(); - - ss << '"' << escapeString(it.key()) << "\": " << toJson(it.value(), format); - ++it; - for(;it != e; ++it) { - ss << ','; - ss << '"' << escapeString(it.key()) << "\": " << toJson(it.value(), format); - } - } - ss << "}"; - } - break; - case QJsonValue::Undefined: - Q_ASSERT(0); - break; - } - - return b; -} - -//------------------------------------------------------------------------------ -// Name: toJson -//------------------------------------------------------------------------------ -QByteArray QJsonDocument::toJson(JsonFormat format) const { - - Q_UNUSED(format); - - if(isArray()) { - QString s = toJson(array(), format); - return s.toUtf8(); - } - - if(isObject()) { - QString s = toJson(object(), format); - return s.toUtf8(); - } - - return QByteArray(); -} - -//------------------------------------------------------------------------------ -// Name: toVariant -//------------------------------------------------------------------------------ -QVariant QJsonDocument::toVariant() const { - - if(!isEmpty()) { - if(QJsonObject *const object = root_->toObject()) { - return object->toVariantMap(); - } - - if(QJsonArray *const array = root_->toArray()) { - return array->toVariantList(); - } - } - - return QVariant(); -} - -//------------------------------------------------------------------------------ -// Name: array -//------------------------------------------------------------------------------ -QJsonArray QJsonDocument::array() const { - - if(!isEmpty()) { - if(QJsonArray *const array = root_->toArray()) { - return *array; - } - } - - return QJsonArray(); -} - -//------------------------------------------------------------------------------ -// Name: object -//------------------------------------------------------------------------------ -QJsonObject QJsonDocument::object() const { - - if(!isEmpty()) { - if(QJsonObject *const object = root_->toObject()) { - return *object; - } - } - - return QJsonObject(); -} - -//------------------------------------------------------------------------------ -// Name: rawData -//------------------------------------------------------------------------------ -const char *QJsonDocument::rawData(int *size) const { - Q_UNUSED(size); - // TODO(eteran): implement this - return 0; -} - -//------------------------------------------------------------------------------ -// Name: fromBinaryData -//------------------------------------------------------------------------------ -QJsonDocument QJsonDocument::fromBinaryData(const QByteArray &data, DataValidation validation) { - Q_UNUSED(data); - Q_UNUSED(validation); - - QJsonDocument doc; - // TODO(eteran): implement this - return doc; -} - -//------------------------------------------------------------------------------ -// Name: fromJson -//------------------------------------------------------------------------------ -QJsonDocument QJsonDocument::fromJson(const QByteArray &json, QJsonParseError *error) { - QJsonDocument doc; - - const char *const begin = json.constData(); - const char *const end = begin + json.size(); - - QJsonParser parser(begin, end); - - doc.root_ = parser.parse(); - - if(error) { - *error = parser.state(); - } - - return doc; -} - -//------------------------------------------------------------------------------ -// Name: fromRawData -//------------------------------------------------------------------------------ -QJsonDocument QJsonDocument::fromRawData(const char *data, int size, DataValidation validation) { - - // data has to be aligned to a 4 byte boundary. - Q_ASSERT(!(reinterpret_cast<quintptr>(data) % 3)); - - return fromBinaryData(QByteArray::fromRawData(data, size), validation); -} - -//------------------------------------------------------------------------------ -// Name: fromVariant -//------------------------------------------------------------------------------ -QJsonDocument QJsonDocument::fromVariant(const QVariant &variant) { - - QJsonDocument doc; - - if (variant.type() == QVariant::Map) { - doc.setObject(QJsonObject::fromVariantMap(variant.toMap())); - } else if (variant.type() == QVariant::Hash) { - doc.setObject(QJsonObject::fromVariantHash(variant.toHash())); - } else if (variant.type() == QVariant::List) { - doc.setArray(QJsonArray::fromVariantList(variant.toList())); - } else if (variant.type() == QVariant::StringList) { - doc.setArray(QJsonArray::fromStringList(variant.toStringList())); - } - - return doc; -} - -//------------------------------------------------------------------------------ -// Name: swap -//------------------------------------------------------------------------------ -void QJsonDocument::swap(QJsonDocument &other) { - qSwap(root_, other.root_); -} - -#endif +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "QJsonDocument.h" +#include "QJsonObject.h" +#include "QJsonArray.h" +#include "QJsonParser.h" + +#include <QtCore/QStringList> +#include <QtCore/QByteArray> +#include <QtCore/QTextStream> +#include <QtCore/QTextCodec> +#include <QtCore/QtCore> + +#if QT_VERSION < 0x050000 + +//------------------------------------------------------------------------------ +// Name: QJsonDocument +//------------------------------------------------------------------------------ +QJsonDocument::QJsonDocument() : root_(0) { +} + +//------------------------------------------------------------------------------ +// Name: QJsonDocument +//------------------------------------------------------------------------------ +QJsonDocument::QJsonDocument(const QJsonObject &object) : root_(0) { + setObject(object); +} + +//------------------------------------------------------------------------------ +// Name: QJsonDocument +//------------------------------------------------------------------------------ +QJsonDocument::QJsonDocument(const QJsonArray &array) : root_(0) { + setArray(array); +} + +//------------------------------------------------------------------------------ +// Name: QJsonDocument +//------------------------------------------------------------------------------ +QJsonDocument::QJsonDocument(const QJsonDocument &other) : root_(0) { + if(other.root_) { + root_ = other.root_->clone(); + } +} + +//------------------------------------------------------------------------------ +// Name: ~QJsonDocument +//------------------------------------------------------------------------------ +QJsonDocument::~QJsonDocument() { + delete root_; +} + +//------------------------------------------------------------------------------ +// Name: operator= +//------------------------------------------------------------------------------ +QJsonDocument &QJsonDocument::operator=(const QJsonDocument &other) { + QJsonDocument(other).swap(*this); + return *this; +} + +//------------------------------------------------------------------------------ +// Name: operator!= +//------------------------------------------------------------------------------ +bool QJsonDocument::operator!=(const QJsonDocument &other) const { + return !(*this == other); +} + +//------------------------------------------------------------------------------ +// Name: operator== +//------------------------------------------------------------------------------ +bool QJsonDocument::operator==(const QJsonDocument &other) const { + + if(isArray() && other.isArray()) { + return array() == other.array(); + } + + if(isObject() && other.isObject()) { + return object() == other.object(); + } + + if(isEmpty() && other.isEmpty()) { + return true; + } + + if(isNull() && other.isNull()) { + return true; + } + + return false; +} + +//------------------------------------------------------------------------------ +// Name: isArray +//------------------------------------------------------------------------------ +bool QJsonDocument::isArray() const { + return root_ && root_->toArray(); +} + +//------------------------------------------------------------------------------ +// Name: isEmpty +//------------------------------------------------------------------------------ +bool QJsonDocument::isEmpty() const { + + // TODO(eteran): figure out the rules here that Qt5 uses + // it *looks* like they define empty as being NULL + // which is obviously different than this + + return !root_; +} + +//------------------------------------------------------------------------------ +// Name: isNull +//------------------------------------------------------------------------------ +bool QJsonDocument::isNull() const { + return !root_; +} + +//------------------------------------------------------------------------------ +// Name: isObject +//------------------------------------------------------------------------------ +bool QJsonDocument::isObject() const { + return root_ && root_->toObject(); +} + +//------------------------------------------------------------------------------ +// Name: setArray +//------------------------------------------------------------------------------ +void QJsonDocument::setArray(const QJsonArray &array) { + setRoot(array); +} + +//------------------------------------------------------------------------------ +// Name: setObject +//------------------------------------------------------------------------------ +void QJsonDocument::setObject(const QJsonObject &object) { + setRoot(object); +} + +//------------------------------------------------------------------------------ +// Name: setRoot +//------------------------------------------------------------------------------ +void QJsonDocument::setRoot(const QJsonRoot &root) { + delete root_; + root_ = root.clone(); +} + +//------------------------------------------------------------------------------ +// Name: toBinaryData +//------------------------------------------------------------------------------ +QByteArray QJsonDocument::toBinaryData() const { + QByteArray r; + // TODO(eteran): implement this + return r; +} + +//------------------------------------------------------------------------------ +// Name: escapeString +//------------------------------------------------------------------------------ +QString QJsonDocument::escapeString(const QString &s) const { + + QString r; + + Q_FOREACH(QChar ch, s) { + switch(ch.toLatin1()) { + case '\"': r.append("\\\""); break; + case '\\': r.append("\\\\"); break; + #if 0 + case '/': r.append("\\/"); break; + #endif + case '\b': r.append("\\b"); break; + case '\f': r.append("\\f"); break; + case '\n': r.append("\\n"); break; + case '\r': r.append("\\r"); break; + case '\t': r.append("\\t"); break; + default: + r += ch; + break; + } + } + + return r; +} + +//------------------------------------------------------------------------------ +// Name: toJson +//------------------------------------------------------------------------------ +QString QJsonDocument::toJson(const QJsonValue &v, JsonFormat format) const { + + QString b; + QTextStream ss(&b, QIODevice::WriteOnly | QIODevice::Text); + + switch(v.type()) { + case QJsonValue::Null: + ss << "null"; + break; + case QJsonValue::Bool: + ss << (v.toBool() ? "true" : "false"); + break; + case QJsonValue::Double: + { + double d = v.toDouble (); + if (qIsFinite(d)) { + // +2 to format to ensure the expected precision + ss << QByteArray::number(d, 'g', 15 + 2); // ::digits10 is 15 + } else { + ss << "null"; // +INF || -INF || NaN (see RFC4627#section2.4) + } + } + break; + case QJsonValue::String: + ss << '"' << escapeString(v.toString()) << '"'; + break; + case QJsonValue::Array: + { + const QJsonArray a = v.toArray(); + ss << "["; + if(!a.empty()) { + QJsonArray::const_iterator it = a.begin(); + QJsonArray::const_iterator e = a.end(); + + ss << toJson(*it++, format); + + for(;it != e; ++it) { + ss << ','; + ss << toJson(*it, format); + } + } + ss << "]"; + } + break; + case QJsonValue::Object: + { + const QJsonObject o = v.toObject(); + ss << "{"; + if(!o.empty()) { + QJsonObject::const_iterator it = o.begin(); + QJsonObject::const_iterator e = o.end(); + + ss << '"' << escapeString(it.key()) << "\": " << toJson(it.value(), format); + ++it; + for(;it != e; ++it) { + ss << ','; + ss << '"' << escapeString(it.key()) << "\": " << toJson(it.value(), format); + } + } + ss << "}"; + } + break; + case QJsonValue::Undefined: + Q_ASSERT(0); + break; + } + + return b; +} + +//------------------------------------------------------------------------------ +// Name: toJson +//------------------------------------------------------------------------------ +QByteArray QJsonDocument::toJson(JsonFormat format) const { + + Q_UNUSED(format); + + if(isArray()) { + QString s = toJson(array(), format); + return s.toUtf8(); + } + + if(isObject()) { + QString s = toJson(object(), format); + return s.toUtf8(); + } + + return QByteArray(); +} + +//------------------------------------------------------------------------------ +// Name: toVariant +//------------------------------------------------------------------------------ +QVariant QJsonDocument::toVariant() const { + + if(!isEmpty()) { + if(QJsonObject *const object = root_->toObject()) { + return object->toVariantMap(); + } + + if(QJsonArray *const array = root_->toArray()) { + return array->toVariantList(); + } + } + + return QVariant(); +} + +//------------------------------------------------------------------------------ +// Name: array +//------------------------------------------------------------------------------ +QJsonArray QJsonDocument::array() const { + + if(!isEmpty()) { + if(QJsonArray *const array = root_->toArray()) { + return *array; + } + } + + return QJsonArray(); +} + +//------------------------------------------------------------------------------ +// Name: object +//------------------------------------------------------------------------------ +QJsonObject QJsonDocument::object() const { + + if(!isEmpty()) { + if(QJsonObject *const object = root_->toObject()) { + return *object; + } + } + + return QJsonObject(); +} + +//------------------------------------------------------------------------------ +// Name: rawData +//------------------------------------------------------------------------------ +const char *QJsonDocument::rawData(int *size) const { + Q_UNUSED(size); + // TODO(eteran): implement this + return 0; +} + +//------------------------------------------------------------------------------ +// Name: fromBinaryData +//------------------------------------------------------------------------------ +QJsonDocument QJsonDocument::fromBinaryData(const QByteArray &data, DataValidation validation) { + Q_UNUSED(data); + Q_UNUSED(validation); + + QJsonDocument doc; + // TODO(eteran): implement this + return doc; +} + +//------------------------------------------------------------------------------ +// Name: fromJson +//------------------------------------------------------------------------------ +QJsonDocument QJsonDocument::fromJson(const QByteArray &json, QJsonParseError *error) { + QJsonDocument doc; + + const char *const begin = json.constData(); + const char *const end = begin + json.size(); + + QJsonParser parser(begin, end); + + doc.root_ = parser.parse(); + + if(error) { + *error = parser.state(); + } + + return doc; +} + +//------------------------------------------------------------------------------ +// Name: fromRawData +//------------------------------------------------------------------------------ +QJsonDocument QJsonDocument::fromRawData(const char *data, int size, DataValidation validation) { + + // data has to be aligned to a 4 byte boundary. + Q_ASSERT(!(reinterpret_cast<quintptr>(data) % 3)); + + return fromBinaryData(QByteArray::fromRawData(data, size), validation); +} + +//------------------------------------------------------------------------------ +// Name: fromVariant +//------------------------------------------------------------------------------ +QJsonDocument QJsonDocument::fromVariant(const QVariant &variant) { + + QJsonDocument doc; + + if (variant.type() == QVariant::Map) { + doc.setObject(QJsonObject::fromVariantMap(variant.toMap())); + } else if (variant.type() == QVariant::Hash) { + doc.setObject(QJsonObject::fromVariantHash(variant.toHash())); + } else if (variant.type() == QVariant::List) { + doc.setArray(QJsonArray::fromVariantList(variant.toList())); + } else if (variant.type() == QVariant::StringList) { + doc.setArray(QJsonArray::fromStringList(variant.toStringList())); + } + + return doc; +} + +//------------------------------------------------------------------------------ +// Name: swap +//------------------------------------------------------------------------------ +void QJsonDocument::swap(QJsonDocument &other) { + qSwap(root_, other.root_); +} + +#endif diff --git a/qjson4/QJsonDocument.h b/qjson4/QJsonDocument.h index 32ae72f..12e8fc7 100755 --- a/qjson4/QJsonDocument.h +++ b/qjson4/QJsonDocument.h @@ -1,103 +1,103 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef QJSON_DOCUMENT_H_ -#define QJSON_DOCUMENT_H_ - -#include <QtCore/QtGlobal> - -#if QT_VERSION >= 0x050000 -#include <QtCore/QJsonDocument> -#else - -class QVariant; -class QByteArray; -class QTextStream; -class QJsonObject; -class QJsonValue; -class QJsonArray; -class QJsonParseError; -class QJsonRoot; - -class QJsonDocument { -public: - enum DataValidation { - Validate = 0, - BypassValidation = 1 - }; - - enum JsonFormat { - Indented, - Compact - }; - -public: - QJsonDocument(); - QJsonDocument(const QJsonObject &object); - QJsonDocument(const QJsonArray &array); - QJsonDocument(const QJsonDocument &other); - ~QJsonDocument(); - -public: - QJsonDocument &operator=(const QJsonDocument &other); - -public: - bool operator!=(const QJsonDocument &other) const; - bool operator==(const QJsonDocument &other) const; - -public: - bool isArray() const; - bool isEmpty() const; - bool isNull() const; - bool isObject() const; - -public: - QByteArray toBinaryData() const; - QByteArray toJson(JsonFormat format = Indented) const; - QVariant toVariant() const; - -public: - QJsonArray array() const; - QJsonObject object() const; - const char *rawData(int *size) const; - -public: - void setArray(const QJsonArray &array); - void setObject(const QJsonObject &object); - -public: - static QJsonDocument fromBinaryData(const QByteArray &data, DataValidation validation = Validate); - static QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error = 0); - static QJsonDocument fromRawData(const char *data, int size, DataValidation validation = Validate); - static QJsonDocument fromVariant(const QVariant &variant); - -private: - void setRoot(const QJsonRoot &root); - QString toJson(const QJsonValue &v, JsonFormat format) const; - QString escapeString(const QString &s) const; - -private: - void swap(QJsonDocument &other); - -private: - QJsonRoot *root_; -}; - -#endif - -#endif +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef QJSON_DOCUMENT_H_ +#define QJSON_DOCUMENT_H_ + +#include <QtCore/QtGlobal> + +#if QT_VERSION >= 0x050000 +#include <QtCore/QJsonDocument> +#else + +class QVariant; +class QByteArray; +class QTextStream; +class QJsonObject; +class QJsonValue; +class QJsonArray; +class QJsonParseError; +class QJsonRoot; + +class QJsonDocument { +public: + enum DataValidation { + Validate = 0, + BypassValidation = 1 + }; + + enum JsonFormat { + Indented, + Compact + }; + +public: + QJsonDocument(); + QJsonDocument(const QJsonObject &object); + QJsonDocument(const QJsonArray &array); + QJsonDocument(const QJsonDocument &other); + ~QJsonDocument(); + +public: + QJsonDocument &operator=(const QJsonDocument &other); + +public: + bool operator!=(const QJsonDocument &other) const; + bool operator==(const QJsonDocument &other) const; + +public: + bool isArray() const; + bool isEmpty() const; + bool isNull() const; + bool isObject() const; + +public: + QByteArray toBinaryData() const; + QByteArray toJson(JsonFormat format = Indented) const; + QVariant toVariant() const; + +public: + QJsonArray array() const; + QJsonObject object() const; + const char *rawData(int *size) const; + +public: + void setArray(const QJsonArray &array); + void setObject(const QJsonObject &object); + +public: + static QJsonDocument fromBinaryData(const QByteArray &data, DataValidation validation = Validate); + static QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error = 0); + static QJsonDocument fromRawData(const char *data, int size, DataValidation validation = Validate); + static QJsonDocument fromVariant(const QVariant &variant); + +private: + void setRoot(const QJsonRoot &root); + QString toJson(const QJsonValue &v, JsonFormat format) const; + QString escapeString(const QString &s) const; + +private: + void swap(QJsonDocument &other); + +private: + QJsonRoot *root_; +}; + +#endif + +#endif diff --git a/qjson4/QJsonObject b/qjson4/QJsonObject index 2009be3..fb2126e 100755 --- a/qjson4/QJsonObject +++ b/qjson4/QJsonObject @@ -1 +1 @@ -#include "QJsonObject.h" +#include "QJsonObject.h" diff --git a/qjson4/QJsonObject.cpp b/qjson4/QJsonObject.cpp index 4a9e15a..55f8cf1 100755 --- a/qjson4/QJsonObject.cpp +++ b/qjson4/QJsonObject.cpp @@ -1,322 +1,322 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "QJsonObject.h" - -#if QT_VERSION < 0x050000 - -//------------------------------------------------------------------------------ -// Name: QJsonObject -//------------------------------------------------------------------------------ -QJsonObject::QJsonObject() { -} - -//------------------------------------------------------------------------------ -// Name: QJsonObject -//------------------------------------------------------------------------------ -QJsonObject::QJsonObject(const QJsonObject &other) : values_(other.values_) { -} - -#if __cplusplus >= 201103L -//------------------------------------------------------------------------------ -// Name: QJsonObject -//------------------------------------------------------------------------------ -QJsonObject::QJsonObject(std::initializer_list<QPair<QString, QJsonValue> > args) { - for(const QPair<QString, QJsonValue> &arg : args) { - values_.insert(arg.first, arg.second); - - } -} -#endif - -//------------------------------------------------------------------------------ -// Name: ~QJsonObject -//------------------------------------------------------------------------------ -QJsonObject::~QJsonObject() { -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonObject &QJsonObject::operator=(const QJsonObject &other) { - QJsonObject(other).swap(*this); - return *this; -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonObject::iterator QJsonObject::begin() { - return values_.begin(); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonObject::const_iterator QJsonObject::begin() const { - return values_.begin(); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonObject::iterator QJsonObject::end() { - return values_.end(); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonObject::const_iterator QJsonObject::end() const { - return values_.end(); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonObject::const_iterator QJsonObject::constBegin() const { - return begin(); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonObject::const_iterator QJsonObject::constEnd() const { - return end(); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -int QJsonObject::count() const { - return size(); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -int QJsonObject::length() const { - return size(); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -int QJsonObject::size() const { - return values_.size(); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -bool QJsonObject::empty() const { - return values_.empty(); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -bool QJsonObject::isEmpty() const { - return empty(); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonObject::const_iterator QJsonObject::constFind(const QString &key) const { - return values_.find(key); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -bool QJsonObject::contains(const QString &key) const { - return values_.contains(key); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonObject::iterator QJsonObject::find(const QString &key) { - return values_.find(key); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonObject::const_iterator QJsonObject::find(const QString &key) const { - return values_.find(key); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonObject::iterator QJsonObject::erase(iterator it) { - return values_.erase(it); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonObject::iterator QJsonObject::insert(const QString &key, const QJsonValue &value) { - return values_.insert(key, value); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QStringList QJsonObject::keys() const { - return values_.keys(); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -void QJsonObject::remove(const QString &key) { - values_.remove(key); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonValue QJsonObject::take(const QString &key) { - return values_.take(key); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonValue QJsonObject::value(const QString &key) const { - return values_.value(key); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -bool QJsonObject::operator!=(const QJsonObject &other) const { - return values_ != other.values_; -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -bool QJsonObject::operator==(const QJsonObject &other) const { - return values_ != other.values_; -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonValue QJsonObject::operator[](const QString &key) const { - return values_[key]; -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonValueRef QJsonObject::operator[](const QString &key) { - return QJsonValueRef(this, key); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QVariantMap QJsonObject::toVariantMap() const { - QVariantMap a; - for(const_iterator it = begin(); it != end(); ++it) { - a.insert(it.key(), it.value().toVariant()); - } - return a; -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QVariantHash QJsonObject::toVariantHash() const { - QVariantHash a; - for(const_iterator it = begin(); it != end(); ++it) { - a.insert(it.key(), it.value().toVariant()); - } - return a; -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonObject QJsonObject::fromVariantMap(const QVariantMap &map) { - QJsonObject o; - for(QVariantMap::const_iterator it = map.begin(); it != map.end(); ++it) { - o.insert(it.key(), QJsonValue::fromVariant(it.value())); - } - return o; -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonObject QJsonObject::fromVariantHash(const QVariantHash &hash) { - QJsonObject o; - for(QVariantHash::const_iterator it = hash.begin(); it != hash.end(); ++it) { - o.insert(it.key(), QJsonValue::fromVariant(it.value())); - } - return o; -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonRoot *QJsonObject::clone() const { - return new QJsonObject(*this); -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -const QJsonObject *QJsonObject::toObject() const { - return this; -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonObject *QJsonObject::toObject() { - return this; -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -QJsonArray *QJsonObject::toArray() { - return 0; -} - -//------------------------------------------------------------------------------ -// Name: -//------------------------------------------------------------------------------ -const QJsonArray *QJsonObject::toArray() const { - return 0; -} - -//------------------------------------------------------------------------------ -// Name: swap -//------------------------------------------------------------------------------ -void QJsonObject::swap(QJsonObject &other) { - qSwap(values_, other.values_); -} - -#endif +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "QJsonObject.h" + +#if QT_VERSION < 0x050000 + +//------------------------------------------------------------------------------ +// Name: QJsonObject +//------------------------------------------------------------------------------ +QJsonObject::QJsonObject() { +} + +//------------------------------------------------------------------------------ +// Name: QJsonObject +//------------------------------------------------------------------------------ +QJsonObject::QJsonObject(const QJsonObject &other) : values_(other.values_) { +} + +#if __cplusplus >= 201103L +//------------------------------------------------------------------------------ +// Name: QJsonObject +//------------------------------------------------------------------------------ +QJsonObject::QJsonObject(std::initializer_list<QPair<QString, QJsonValue> > args) { + for(const QPair<QString, QJsonValue> &arg : args) { + values_.insert(arg.first, arg.second); + + } +} +#endif + +//------------------------------------------------------------------------------ +// Name: ~QJsonObject +//------------------------------------------------------------------------------ +QJsonObject::~QJsonObject() { +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonObject &QJsonObject::operator=(const QJsonObject &other) { + QJsonObject(other).swap(*this); + return *this; +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonObject::iterator QJsonObject::begin() { + return values_.begin(); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonObject::const_iterator QJsonObject::begin() const { + return values_.begin(); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonObject::iterator QJsonObject::end() { + return values_.end(); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonObject::const_iterator QJsonObject::end() const { + return values_.end(); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonObject::const_iterator QJsonObject::constBegin() const { + return begin(); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonObject::const_iterator QJsonObject::constEnd() const { + return end(); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +int QJsonObject::count() const { + return size(); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +int QJsonObject::length() const { + return size(); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +int QJsonObject::size() const { + return values_.size(); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +bool QJsonObject::empty() const { + return values_.empty(); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +bool QJsonObject::isEmpty() const { + return empty(); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonObject::const_iterator QJsonObject::constFind(const QString &key) const { + return values_.find(key); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +bool QJsonObject::contains(const QString &key) const { + return values_.contains(key); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonObject::iterator QJsonObject::find(const QString &key) { + return values_.find(key); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonObject::const_iterator QJsonObject::find(const QString &key) const { + return values_.find(key); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonObject::iterator QJsonObject::erase(iterator it) { + return values_.erase(it); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonObject::iterator QJsonObject::insert(const QString &key, const QJsonValue &value) { + return values_.insert(key, value); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QStringList QJsonObject::keys() const { + return values_.keys(); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +void QJsonObject::remove(const QString &key) { + values_.remove(key); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonValue QJsonObject::take(const QString &key) { + return values_.take(key); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonValue QJsonObject::value(const QString &key) const { + return values_.value(key); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +bool QJsonObject::operator!=(const QJsonObject &other) const { + return values_ != other.values_; +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +bool QJsonObject::operator==(const QJsonObject &other) const { + return values_ != other.values_; +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonValue QJsonObject::operator[](const QString &key) const { + return values_[key]; +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonValueRef QJsonObject::operator[](const QString &key) { + return QJsonValueRef(this, key); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QVariantMap QJsonObject::toVariantMap() const { + QVariantMap a; + for(const_iterator it = begin(); it != end(); ++it) { + a.insert(it.key(), it.value().toVariant()); + } + return a; +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QVariantHash QJsonObject::toVariantHash() const { + QVariantHash a; + for(const_iterator it = begin(); it != end(); ++it) { + a.insert(it.key(), it.value().toVariant()); + } + return a; +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonObject QJsonObject::fromVariantMap(const QVariantMap &map) { + QJsonObject o; + for(QVariantMap::const_iterator it = map.begin(); it != map.end(); ++it) { + o.insert(it.key(), QJsonValue::fromVariant(it.value())); + } + return o; +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonObject QJsonObject::fromVariantHash(const QVariantHash &hash) { + QJsonObject o; + for(QVariantHash::const_iterator it = hash.begin(); it != hash.end(); ++it) { + o.insert(it.key(), QJsonValue::fromVariant(it.value())); + } + return o; +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonRoot *QJsonObject::clone() const { + return new QJsonObject(*this); +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +const QJsonObject *QJsonObject::toObject() const { + return this; +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonObject *QJsonObject::toObject() { + return this; +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +QJsonArray *QJsonObject::toArray() { + return 0; +} + +//------------------------------------------------------------------------------ +// Name: +//------------------------------------------------------------------------------ +const QJsonArray *QJsonObject::toArray() const { + return 0; +} + +//------------------------------------------------------------------------------ +// Name: swap +//------------------------------------------------------------------------------ +void QJsonObject::swap(QJsonObject &other) { + qSwap(values_, other.values_); +} + +#endif diff --git a/qjson4/QJsonObject.h b/qjson4/QJsonObject.h index 50a6ee5..ad657bc 100755 --- a/qjson4/QJsonObject.h +++ b/qjson4/QJsonObject.h @@ -1,121 +1,121 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef QJSON_OBJECT_H_ -#define QJSON_OBJECT_H_ - -#include <QtCore/QtGlobal> - -#if QT_VERSION >= 0x050000 -#include <QtCore/QJsonObject> -#else - -#include "QJsonRoot.h" -#include "QJsonValueRef.h" -#include "QJsonValue.h" -#include <QtCore/QString> -#include <QtCore/QStringList> -#include <QtCore/QVariantMap> -#include <QtCore/QMap> - -class QJsonObject : public QJsonRoot { - friend class QJsonDocument; - friend class QJsonValue; - friend class QJsonValueRef; - friend class QJsonParser; -public: - // TODO(eteran): manually implement the map, for now we use QMap - // but the real thing has a custom implementation - // I guess for the purposes of less interdependancies? - // maybe so it's easier to forward declare the iterators? - - typedef QMap<QString, QJsonValue>::const_iterator const_iterator; - typedef QMap<QString, QJsonValue>::iterator iterator; - typedef const_iterator ConstIterator; - typedef iterator Iterator; - typedef QMap<QString, QJsonValue>::key_type key_type; - typedef QMap<QString, QJsonValue>::mapped_type mapped_type; - typedef QMap<QString, QJsonValue>::size_type size_type; - -public: - QJsonObject(); -#if __cplusplus >= 201103L - QJsonObject(std::initializer_list<QPair<QString, QJsonValue> > args); -#endif - QJsonObject(const QJsonObject &other); - ~QJsonObject(); - QJsonObject &operator=(const QJsonObject &other); - -public: - iterator begin(); - const_iterator begin() const; - iterator end(); - const_iterator end() const; - const_iterator constBegin() const; - const_iterator constEnd() const; - -public: - int count() const; - int length() const; - int size() const; - bool empty() const; - bool isEmpty() const; - -public: - const_iterator constFind(const QString &key) const; - bool contains(const QString &key) const; - iterator find(const QString &key); - const_iterator find(const QString &key) const; - -public: - iterator erase(iterator it); - iterator insert(const QString &key, const QJsonValue &value); - QStringList keys() const; - void remove(const QString &key); - QJsonValue take(const QString &key); - QJsonValue value(const QString &key) const; - bool operator!=(const QJsonObject &other) const; - bool operator==(const QJsonObject &other) const; - QJsonValue operator[](const QString &key) const; - QJsonValueRef operator[](const QString &key); - -public: - QVariantMap toVariantMap() const; - QVariantHash toVariantHash() const; - -public: - static QJsonObject fromVariantMap(const QVariantMap &map); - static QJsonObject fromVariantHash(const QVariantHash &hash); - -private: - virtual QJsonRoot *clone() const; - virtual QJsonArray *toArray(); - virtual QJsonObject *toObject(); - virtual const QJsonArray *toArray() const; - virtual const QJsonObject *toObject() const; - -private: - void swap(QJsonObject &other); - -private: - QMap<QString, QJsonValue> values_; -}; - -#endif - -#endif +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef QJSON_OBJECT_H_ +#define QJSON_OBJECT_H_ + +#include <QtCore/QtGlobal> + +#if QT_VERSION >= 0x050000 +#include <QtCore/QJsonObject> +#else + +#include "QJsonRoot.h" +#include "QJsonValueRef.h" +#include "QJsonValue.h" +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QVariantMap> +#include <QtCore/QMap> + +class QJsonObject : public QJsonRoot { + friend class QJsonDocument; + friend class QJsonValue; + friend class QJsonValueRef; + friend class QJsonParser; +public: + // TODO(eteran): manually implement the map, for now we use QMap + // but the real thing has a custom implementation + // I guess for the purposes of less interdependancies? + // maybe so it's easier to forward declare the iterators? + + typedef QMap<QString, QJsonValue>::const_iterator const_iterator; + typedef QMap<QString, QJsonValue>::iterator iterator; + typedef const_iterator ConstIterator; + typedef iterator Iterator; + typedef QMap<QString, QJsonValue>::key_type key_type; + typedef QMap<QString, QJsonValue>::mapped_type mapped_type; + typedef QMap<QString, QJsonValue>::size_type size_type; + +public: + QJsonObject(); +#if __cplusplus >= 201103L + QJsonObject(std::initializer_list<QPair<QString, QJsonValue> > args); +#endif + QJsonObject(const QJsonObject &other); + ~QJsonObject(); + QJsonObject &operator=(const QJsonObject &other); + +public: + iterator begin(); + const_iterator begin() const; + iterator end(); + const_iterator end() const; + const_iterator constBegin() const; + const_iterator constEnd() const; + +public: + int count() const; + int length() const; + int size() const; + bool empty() const; + bool isEmpty() const; + +public: + const_iterator constFind(const QString &key) const; + bool contains(const QString &key) const; + iterator find(const QString &key); + const_iterator find(const QString &key) const; + +public: + iterator erase(iterator it); + iterator insert(const QString &key, const QJsonValue &value); + QStringList keys() const; + void remove(const QString &key); + QJsonValue take(const QString &key); + QJsonValue value(const QString &key) const; + bool operator!=(const QJsonObject &other) const; + bool operator==(const QJsonObject &other) const; + QJsonValue operator[](const QString &key) const; + QJsonValueRef operator[](const QString &key); + +public: + QVariantMap toVariantMap() const; + QVariantHash toVariantHash() const; + +public: + static QJsonObject fromVariantMap(const QVariantMap &map); + static QJsonObject fromVariantHash(const QVariantHash &hash); + +private: + virtual QJsonRoot *clone() const; + virtual QJsonArray *toArray(); + virtual QJsonObject *toObject(); + virtual const QJsonArray *toArray() const; + virtual const QJsonObject *toObject() const; + +private: + void swap(QJsonObject &other); + +private: + QMap<QString, QJsonValue> values_; +}; + +#endif + +#endif diff --git a/qjson4/QJsonParseError b/qjson4/QJsonParseError index de177e3..7d30db8 100755 --- a/qjson4/QJsonParseError +++ b/qjson4/QJsonParseError @@ -1 +1 @@ -#include "QJsonParseError.h" +#include "QJsonParseError.h" diff --git a/qjson4/QJsonParseError.cpp b/qjson4/QJsonParseError.cpp index fa19f15..6bcfd98 100755 --- a/qjson4/QJsonParseError.cpp +++ b/qjson4/QJsonParseError.cpp @@ -1,64 +1,64 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "QJsonParseError.h" - -#if QT_VERSION < 0x050000 - -//------------------------------------------------------------------------------ -// Name: errorString -// Desc: The QJsonParseError class is used to report errors during JSON parsing. -//------------------------------------------------------------------------------ -QString QJsonParseError::errorString() const { - switch(error) { - case NoError: - return "No error occurred"; - case UnterminatedObject: - return "unterminated object"; - case MissingNameSeparator: - return "missing name separator"; - case UnterminatedArray: - return "unterminated array"; - case MissingValueSeparator: - return "missing value separator"; - case IllegalValue: - return "illegal value"; - case TerminationByNumber: - return "invalid termination by number"; - case IllegalNumber: - return "illegal number"; - case IllegalEscapeSequence: - return "illegal escape sequence"; - case IllegalUTF8String: - return "invalid UTF8 string"; - case UnterminatedString: - return "unterminated string"; - case MissingObject: - return "object is missing after a comma"; - case DeepNesting: - return "too deeply nested document"; - case DocumentTooLarge: - return "too large document"; - case GarbageAtEnd: - return "garbage at the end of the document"; - } - - return QString(); -} - -#endif +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "QJsonParseError.h" + +#if QT_VERSION < 0x050000 + +//------------------------------------------------------------------------------ +// Name: errorString +// Desc: The QJsonParseError class is used to report errors during JSON parsing. +//------------------------------------------------------------------------------ +QString QJsonParseError::errorString() const { + switch(error) { + case NoError: + return "No error occurred"; + case UnterminatedObject: + return "unterminated object"; + case MissingNameSeparator: + return "missing name separator"; + case UnterminatedArray: + return "unterminated array"; + case MissingValueSeparator: + return "missing value separator"; + case IllegalValue: + return "illegal value"; + case TerminationByNumber: + return "invalid termination by number"; + case IllegalNumber: + return "illegal number"; + case IllegalEscapeSequence: + return "illegal escape sequence"; + case IllegalUTF8String: + return "invalid UTF8 string"; + case UnterminatedString: + return "unterminated string"; + case MissingObject: + return "object is missing after a comma"; + case DeepNesting: + return "too deeply nested document"; + case DocumentTooLarge: + return "too large document"; + case GarbageAtEnd: + return "garbage at the end of the document"; + } + + return QString(); +} + +#endif diff --git a/qjson4/QJsonParseError.h b/qjson4/QJsonParseError.h index d2eda8b..b87d7aa 100755 --- a/qjson4/QJsonParseError.h +++ b/qjson4/QJsonParseError.h @@ -1,60 +1,60 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef QJSON_PARSE_ERROR_H_ -#define QJSON_PARSE_ERROR_H_ - -#include <QtCore/QtGlobal> - -#if QT_VERSION >= 0x050000 -#include <QtCore/QJsonParseError> -#else - -#include <QtCore/QString> - -class QJsonParseError { -public: - enum ParseError { - NoError = 0, - UnterminatedObject = 1, - MissingNameSeparator = 2, - UnterminatedArray = 3, - MissingValueSeparator = 4, - IllegalValue = 5, - TerminationByNumber = 6, - IllegalNumber = 7, - IllegalEscapeSequence = 8, - IllegalUTF8String = 9, - UnterminatedString = 10, - MissingObject = 11, - DeepNesting = 12, - DocumentTooLarge = 13, - GarbageAtEnd = 14 - }; - -public: - QString errorString() const; - -public: - ParseError error; - int offset; -}; - -#endif - -#endif +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef QJSON_PARSE_ERROR_H_ +#define QJSON_PARSE_ERROR_H_ + +#include <QtCore/QtGlobal> + +#if QT_VERSION >= 0x050000 +#include <QtCore/QJsonParseError> +#else + +#include <QtCore/QString> + +class QJsonParseError { +public: + enum ParseError { + NoError = 0, + UnterminatedObject = 1, + MissingNameSeparator = 2, + UnterminatedArray = 3, + MissingValueSeparator = 4, + IllegalValue = 5, + TerminationByNumber = 6, + IllegalNumber = 7, + IllegalEscapeSequence = 8, + IllegalUTF8String = 9, + UnterminatedString = 10, + MissingObject = 11, + DeepNesting = 12, + DocumentTooLarge = 13, + GarbageAtEnd = 14 + }; + +public: + QString errorString() const; + +public: + ParseError error; + int offset; +}; + +#endif + +#endif diff --git a/qjson4/QJsonParser.cpp b/qjson4/QJsonParser.cpp index 08c3c62..9b084f7 100755 --- a/qjson4/QJsonParser.cpp +++ b/qjson4/QJsonParser.cpp @@ -1,455 +1,455 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "QJsonParser.h" -#include "QJsonArray.h" -#include "QJsonObject.h" -#include "QJsonValue.h" - - -#if QT_VERSION < 0x050000 - -#include <cctype> -#include <QScopedPointer> -#include <QVector> - -namespace { - -unsigned int to_hex(int ch) { - - static const int hexval[256] = { - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 - }; - - if(static_cast<unsigned int>(ch) < 256) { - return hexval[static_cast<unsigned int>(ch)]; - } else { - return 0; - } -} - -} - -//------------------------------------------------------------------------------ -// Name: QJsonParser -//------------------------------------------------------------------------------ -QJsonParser::QJsonParser(const char *begin, const char *end) : begin_(begin), end_(end), p_(begin) { - state_.error = QJsonParseError::NoError; - state_.offset = 0; -} - -//------------------------------------------------------------------------------ -// Name: parse -//------------------------------------------------------------------------------ -QJsonRoot *QJsonParser::parse() { - if(begin_ == end_) { - return 0; - } - - QJsonRoot *ret = 0; - - try { - const char ch = peek(); - switch(ch) { - case ArrayBegin: - ret = getArray(); - break; - case ObjectBegin: - ret = getObject(); - break; - default: - state_.error = QJsonParseError::IllegalValue; - state_.offset = p_ - begin_; - break; - } - } catch(const QJsonParseError &e) { - state_ = e; - } - - if(ret) { - // eat up trailing white space... - while(p_ != end_ && std::isspace(*p_)) { - ++p_; - } - - //detect trailing garbage - if(p_ != end_) { - state_.error = QJsonParseError::GarbageAtEnd; - state_.offset = p_ - begin_; - } - } - - return ret; -} - -//------------------------------------------------------------------------------ -// Name: peek -//------------------------------------------------------------------------------ -char QJsonParser::peek() { - // first eat up some whitespace - while(p_ != end_ && std::isspace(*p_)) { - ++p_; - } - - return *p_; -} - -//------------------------------------------------------------------------------ -// Name: getValue -//------------------------------------------------------------------------------ -QJsonValue QJsonParser::getValue() { - - switch(peek()) { - case ObjectBegin: - { - QScopedPointer<QJsonObject> obj(getObject()); - return QJsonValue(*obj); - } - case ArrayBegin: - { - QScopedPointer<QJsonArray> arr(getArray()); - return QJsonValue(*arr); - } - case Quote: - return QJsonValue(getString()); - case 't': - return getTrue(); - case 'f': - return getFalse(); - case 'n': - return getNull(); - default: - return getNumber(); - } - - throwError(QJsonParseError::MissingObject); - return QJsonValue(); -} - -//------------------------------------------------------------------------------ -// Name: getObject -//------------------------------------------------------------------------------ -QJsonObject *QJsonParser::getObject() { - - QScopedPointer<QJsonObject> obj(new QJsonObject); - - char tok = peek(); - if(tok != ObjectBegin) { - throwError(QJsonParseError::IllegalValue); - } - - ++p_; - - // handle empty object - tok = peek(); - if(peek() == ObjectEnd) { - ++p_; - } else { - - do { - QPair<QString, QJsonValue> p = getPair(); - obj->values_.insert(p.first, p.second); - - tok = peek(); - ++p_; - - } while(tok == ValueSeparator); - } - - if(tok != ObjectEnd) { - throwError(QJsonParseError::UnterminatedObject); - } - - return obj.take(); -} - -//------------------------------------------------------------------------------ -// Name: getArray -//------------------------------------------------------------------------------ -QJsonArray *QJsonParser::getArray() { - - QScopedPointer<QJsonArray> arr(new QJsonArray); - - char tok = peek(); - - if(tok != ArrayBegin) { - throwError(QJsonParseError::IllegalValue); - } - - ++p_; - - // handle empty object - tok = peek(); - if(tok == ArrayEnd) { - ++p_; - } else { - do { - arr->values_.push_back(getValue()); - - tok = peek(); - ++p_; - - } while(tok == ValueSeparator); - } - - if(tok != ArrayEnd) { - throwError(QJsonParseError::MissingValueSeparator); - } - - return arr.take(); -} - -//------------------------------------------------------------------------------ -// Name: getPair -//------------------------------------------------------------------------------ -QPair<QString, QJsonValue> QJsonParser::getPair() { - - QString key = getString(); - - if(peek() != NameSeparator) { - throwError(QJsonParseError::MissingNameSeparator); - } - ++p_; - - return qMakePair(key, getValue()); -} - -//------------------------------------------------------------------------------ -// Name: getString -//------------------------------------------------------------------------------ -QString QJsonParser::getString() { - - if(peek() != Quote) { - throwError(QJsonParseError::IllegalUTF8String); - } - ++p_; - - QByteArray s; - - while(p_ != end_ && *p_ != Quote && *p_ != '\n') { - if(*p_ == '\\') { - ++p_; - if(p_ != end_) { - switch(*p_) { - case '"': s.append('"'); break; - case '\\': s.append('\\'); break; - case '/': s.append('/'); break; - case 'b': s.append('\b'); break; - case 'f': s.append('\f'); break; - case 'n': s.append('\n'); break; - case 'r': s.append('\r'); break; - case 't': s.append('\t'); break; - case 'u': - { - - QString hexChar; - - // convert \uXXXX escape sequences to UTF-8 - char hex[4]; - if(p_ == end_) { throwError(QJsonParseError::IllegalEscapeSequence); } hex[0] = *++p_; - if(p_ == end_) { throwError(QJsonParseError::IllegalEscapeSequence); } hex[1] = *++p_; - if(p_ == end_) { throwError(QJsonParseError::IllegalEscapeSequence); } hex[2] = *++p_; - if(p_ == end_) { throwError(QJsonParseError::IllegalEscapeSequence); } hex[3] = *++p_; - - if(!std::isxdigit(hex[0])) throwError(QJsonParseError::IllegalUTF8String); - if(!std::isxdigit(hex[1])) throwError(QJsonParseError::IllegalUTF8String); - if(!std::isxdigit(hex[2])) throwError(QJsonParseError::IllegalUTF8String); - if(!std::isxdigit(hex[3])) throwError(QJsonParseError::IllegalUTF8String); - - quint16 w1 = 0; - quint16 w2 = 0; - - w1 |= (to_hex(hex[0]) << 12); - w1 |= (to_hex(hex[1]) << 8); - w1 |= (to_hex(hex[2]) << 4); - w1 |= (to_hex(hex[3])); - - hexChar.append(QChar(w1)); - - if((w1 & 0xfc00) == 0xdc00) { - throwError(QJsonParseError::IllegalUTF8String); - } - - if((w1 & 0xfc00) == 0xd800) { - // part of a surrogate pair - if(p_ == end_ || *++p_ != '\\') { throwError(QJsonParseError::IllegalEscapeSequence); } - if(p_ == end_ || *++p_ != 'u') { throwError(QJsonParseError::IllegalEscapeSequence); } - - // convert \uXXXX escape sequences to UTF-8 - if(p_ == end_) { throwError(QJsonParseError::IllegalEscapeSequence); } hex[0] = *++p_; - if(p_ == end_) { throwError(QJsonParseError::IllegalEscapeSequence); } hex[1] = *++p_; - if(p_ == end_) { throwError(QJsonParseError::IllegalEscapeSequence); } hex[2] = *++p_; - if(p_ == end_) { throwError(QJsonParseError::IllegalEscapeSequence); } hex[3] = *++p_; - - if(!std::isxdigit(hex[0])) throwError(QJsonParseError::IllegalUTF8String); - if(!std::isxdigit(hex[1])) throwError(QJsonParseError::IllegalUTF8String); - if(!std::isxdigit(hex[2])) throwError(QJsonParseError::IllegalUTF8String); - if(!std::isxdigit(hex[3])) throwError(QJsonParseError::IllegalUTF8String); - - w2 |= (to_hex(hex[0]) << 12); - w2 |= (to_hex(hex[1]) << 8); - w2 |= (to_hex(hex[2]) << 4); - w2 |= (to_hex(hex[3])); - - hexChar.append(QChar(w2)); - } - - s.append(hexChar.toUtf8()); - } - break; - - default: - s.append('\\'); - break; - } - } - } else { - s.append(*p_); - } - ++p_; - } - - if(*p_ != Quote || p_ == end_) { - throwError(QJsonParseError::UnterminatedString); - } - - ++p_; - - return QString::fromUtf8(s, s.size()); -} - -//------------------------------------------------------------------------------ -// Name: getNull -//------------------------------------------------------------------------------ -QJsonValue QJsonParser::getNull() { - if(p_ == end_ || *p_++ != 'n') { throwError(QJsonParseError::IllegalValue); } - if(p_ == end_ || *p_++ != 'u') { throwError(QJsonParseError::IllegalValue); } - if(p_ == end_ || *p_++ != 'l') { throwError(QJsonParseError::IllegalValue); } - if(p_ == end_ || *p_++ != 'l') { throwError(QJsonParseError::IllegalValue); } - - return QJsonValue(); -} - -//------------------------------------------------------------------------------ -// Name: getTrue -//------------------------------------------------------------------------------ -QJsonValue QJsonParser::getTrue() { - if(p_ == end_ || *p_++ != 't') { throwError(QJsonParseError::IllegalValue); } - if(p_ == end_ || *p_++ != 'r') { throwError(QJsonParseError::IllegalValue); } - if(p_ == end_ || *p_++ != 'u') { throwError(QJsonParseError::IllegalValue); } - if(p_ == end_ || *p_++ != 'e') { throwError(QJsonParseError::IllegalValue); } - - return QJsonValue(true); -} - -//------------------------------------------------------------------------------ -// Name: getFalse -//------------------------------------------------------------------------------ -QJsonValue QJsonParser::getFalse() { - if(p_ == end_ || *p_++ != 'f') { throwError(QJsonParseError::IllegalValue); } - if(p_ == end_ || *p_++ != 'a') { throwError(QJsonParseError::IllegalValue); } - if(p_ == end_ || *p_++ != 'l') { throwError(QJsonParseError::IllegalValue); } - if(p_ == end_ || *p_++ != 's') { throwError(QJsonParseError::IllegalValue); } - if(p_ == end_ || *p_++ != 'e') { throwError(QJsonParseError::IllegalValue); } - - return QJsonValue(false); -} - -//------------------------------------------------------------------------------ -// Name: getNumber -//------------------------------------------------------------------------------ -QJsonValue QJsonParser::getNumber() { - // JSON numbers fit the regex: -?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)? - - const char *const first = p_; - - // -? - if(p_ != end_ && *p_ == '-') { - ++p_; - } - - // (0|[1-9][0-9]*) - if(p_ != end_) { - if(*p_ >= '1' && *p_ <= '9') { - while(p_ != end_ && std::isdigit(*p_)) { - ++p_; - } - } else if(*p_ == '0') { - ++p_; - } else { - throwError(QJsonParseError::IllegalNumber); - } - } - - // (\.[0-9]+)? - if(p_ != end_ && *p_ == '.') { - ++p_; - if(!std::isdigit(*p_)) { - throwError(QJsonParseError::IllegalNumber); - } - - while(p_ != end_ && std::isdigit(*p_)) { - ++p_; - } - } - - // ([eE][+-]?[0-9]+)? - if(p_ != end_ && (*p_ == 'e' || *p_ == 'E')) { - ++p_; - if(p_ != end_ && (*p_ == '+' || *p_ == '-')) { - ++p_; - } - if(!std::isdigit(*p_)) { - throwError(QJsonParseError::IllegalNumber); - } - while(p_ != end_ && std::isdigit(*p_)) { - ++p_; - } - } - - if(p_ == end_) { - throwError(QJsonParseError::TerminationByNumber); - } - - return QJsonValue(QByteArray::fromRawData(first, p_ - first).toDouble()); -} - -//------------------------------------------------------------------------------ -// Name: state -//------------------------------------------------------------------------------ -QJsonParseError QJsonParser::state() const { - return state_; -} - -//------------------------------------------------------------------------------ -// Name: throwError -//------------------------------------------------------------------------------ -void QJsonParser::throwError(QJsonParseError::ParseError e) { - QJsonParseError err; - err.error = e; - err.offset = p_ - begin_; - throw err; -} - -#endif +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "QJsonParser.h" +#include "QJsonArray.h" +#include "QJsonObject.h" +#include "QJsonValue.h" + + +#if QT_VERSION < 0x050000 + +#include <cctype> +#include <QScopedPointer> +#include <QVector> + +namespace { + +unsigned int to_hex(int ch) { + + static const int hexval[256] = { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 + }; + + if(static_cast<unsigned int>(ch) < 256) { + return hexval[static_cast<unsigned int>(ch)]; + } else { + return 0; + } +} + +} + +//------------------------------------------------------------------------------ +// Name: QJsonParser +//------------------------------------------------------------------------------ +QJsonParser::QJsonParser(const char *begin, const char *end) : begin_(begin), end_(end), p_(begin) { + state_.error = QJsonParseError::NoError; + state_.offset = 0; +} + +//------------------------------------------------------------------------------ +// Name: parse +//------------------------------------------------------------------------------ +QJsonRoot *QJsonParser::parse() { + if(begin_ == end_) { + return 0; + } + + QJsonRoot *ret = 0; + + try { + const char ch = peek(); + switch(ch) { + case ArrayBegin: + ret = getArray(); + break; + case ObjectBegin: + ret = getObject(); + break; + default: + state_.error = QJsonParseError::IllegalValue; + state_.offset = p_ - begin_; + break; + } + } catch(const QJsonParseError &e) { + state_ = e; + } + + if(ret) { + // eat up trailing white space... + while(p_ != end_ && std::isspace(*p_)) { + ++p_; + } + + //detect trailing garbage + if(p_ != end_) { + state_.error = QJsonParseError::GarbageAtEnd; + state_.offset = p_ - begin_; + } + } + + return ret; +} + +//------------------------------------------------------------------------------ +// Name: peek +//------------------------------------------------------------------------------ +char QJsonParser::peek() { + // first eat up some whitespace + while(p_ != end_ && std::isspace(*p_)) { + ++p_; + } + + return *p_; +} + +//------------------------------------------------------------------------------ +// Name: getValue +//------------------------------------------------------------------------------ +QJsonValue QJsonParser::getValue() { + + switch(peek()) { + case ObjectBegin: + { + QScopedPointer<QJsonObject> obj(getObject()); + return QJsonValue(*obj); + } + case ArrayBegin: + { + QScopedPointer<QJsonArray> arr(getArray()); + return QJsonValue(*arr); + } + case Quote: + return QJsonValue(getString()); + case 't': + return getTrue(); + case 'f': + return getFalse(); + case 'n': + return getNull(); + default: + return getNumber(); + } + + throwError(QJsonParseError::MissingObject); + return QJsonValue(); +} + +//------------------------------------------------------------------------------ +// Name: getObject +//------------------------------------------------------------------------------ +QJsonObject *QJsonParser::getObject() { + + QScopedPointer<QJsonObject> obj(new QJsonObject); + + char tok = peek(); + if(tok != ObjectBegin) { + throwError(QJsonParseError::IllegalValue); + } + + ++p_; + + // handle empty object + tok = peek(); + if(peek() == ObjectEnd) { + ++p_; + } else { + + do { + QPair<QString, QJsonValue> p = getPair(); + obj->values_.insert(p.first, p.second); + + tok = peek(); + ++p_; + + } while(tok == ValueSeparator); + } + + if(tok != ObjectEnd) { + throwError(QJsonParseError::UnterminatedObject); + } + + return obj.take(); +} + +//------------------------------------------------------------------------------ +// Name: getArray +//------------------------------------------------------------------------------ +QJsonArray *QJsonParser::getArray() { + + QScopedPointer<QJsonArray> arr(new QJsonArray); + + char tok = peek(); + + if(tok != ArrayBegin) { + throwError(QJsonParseError::IllegalValue); + } + + ++p_; + + // handle empty object + tok = peek(); + if(tok == ArrayEnd) { + ++p_; + } else { + do { + arr->values_.push_back(getValue()); + + tok = peek(); + ++p_; + + } while(tok == ValueSeparator); + } + + if(tok != ArrayEnd) { + throwError(QJsonParseError::MissingValueSeparator); + } + + return arr.take(); +} + +//------------------------------------------------------------------------------ +// Name: getPair +//------------------------------------------------------------------------------ +QPair<QString, QJsonValue> QJsonParser::getPair() { + + QString key = getString(); + + if(peek() != NameSeparator) { + throwError(QJsonParseError::MissingNameSeparator); + } + ++p_; + + return qMakePair(key, getValue()); +} + +//------------------------------------------------------------------------------ +// Name: getString +//------------------------------------------------------------------------------ +QString QJsonParser::getString() { + + if(peek() != Quote) { + throwError(QJsonParseError::IllegalUTF8String); + } + ++p_; + + QByteArray s; + + while(p_ != end_ && *p_ != Quote && *p_ != '\n') { + if(*p_ == '\\') { + ++p_; + if(p_ != end_) { + switch(*p_) { + case '"': s.append('"'); break; + case '\\': s.append('\\'); break; + case '/': s.append('/'); break; + case 'b': s.append('\b'); break; + case 'f': s.append('\f'); break; + case 'n': s.append('\n'); break; + case 'r': s.append('\r'); break; + case 't': s.append('\t'); break; + case 'u': + { + + QString hexChar; + + // convert \uXXXX escape sequences to UTF-8 + char hex[4]; + if(p_ == end_) { throwError(QJsonParseError::IllegalEscapeSequence); } hex[0] = *++p_; + if(p_ == end_) { throwError(QJsonParseError::IllegalEscapeSequence); } hex[1] = *++p_; + if(p_ == end_) { throwError(QJsonParseError::IllegalEscapeSequence); } hex[2] = *++p_; + if(p_ == end_) { throwError(QJsonParseError::IllegalEscapeSequence); } hex[3] = *++p_; + + if(!std::isxdigit(hex[0])) throwError(QJsonParseError::IllegalUTF8String); + if(!std::isxdigit(hex[1])) throwError(QJsonParseError::IllegalUTF8String); + if(!std::isxdigit(hex[2])) throwError(QJsonParseError::IllegalUTF8String); + if(!std::isxdigit(hex[3])) throwError(QJsonParseError::IllegalUTF8String); + + quint16 w1 = 0; + quint16 w2 = 0; + + w1 |= (to_hex(hex[0]) << 12); + w1 |= (to_hex(hex[1]) << 8); + w1 |= (to_hex(hex[2]) << 4); + w1 |= (to_hex(hex[3])); + + hexChar.append(QChar(w1)); + + if((w1 & 0xfc00) == 0xdc00) { + throwError(QJsonParseError::IllegalUTF8String); + } + + if((w1 & 0xfc00) == 0xd800) { + // part of a surrogate pair + if(p_ == end_ || *++p_ != '\\') { throwError(QJsonParseError::IllegalEscapeSequence); } + if(p_ == end_ || *++p_ != 'u') { throwError(QJsonParseError::IllegalEscapeSequence); } + + // convert \uXXXX escape sequences to UTF-8 + if(p_ == end_) { throwError(QJsonParseError::IllegalEscapeSequence); } hex[0] = *++p_; + if(p_ == end_) { throwError(QJsonParseError::IllegalEscapeSequence); } hex[1] = *++p_; + if(p_ == end_) { throwError(QJsonParseError::IllegalEscapeSequence); } hex[2] = *++p_; + if(p_ == end_) { throwError(QJsonParseError::IllegalEscapeSequence); } hex[3] = *++p_; + + if(!std::isxdigit(hex[0])) throwError(QJsonParseError::IllegalUTF8String); + if(!std::isxdigit(hex[1])) throwError(QJsonParseError::IllegalUTF8String); + if(!std::isxdigit(hex[2])) throwError(QJsonParseError::IllegalUTF8String); + if(!std::isxdigit(hex[3])) throwError(QJsonParseError::IllegalUTF8String); + + w2 |= (to_hex(hex[0]) << 12); + w2 |= (to_hex(hex[1]) << 8); + w2 |= (to_hex(hex[2]) << 4); + w2 |= (to_hex(hex[3])); + + hexChar.append(QChar(w2)); + } + + s.append(hexChar.toUtf8()); + } + break; + + default: + s.append('\\'); + break; + } + } + } else { + s.append(*p_); + } + ++p_; + } + + if(*p_ != Quote || p_ == end_) { + throwError(QJsonParseError::UnterminatedString); + } + + ++p_; + + return QString::fromUtf8(s, s.size()); +} + +//------------------------------------------------------------------------------ +// Name: getNull +//------------------------------------------------------------------------------ +QJsonValue QJsonParser::getNull() { + if(p_ == end_ || *p_++ != 'n') { throwError(QJsonParseError::IllegalValue); } + if(p_ == end_ || *p_++ != 'u') { throwError(QJsonParseError::IllegalValue); } + if(p_ == end_ || *p_++ != 'l') { throwError(QJsonParseError::IllegalValue); } + if(p_ == end_ || *p_++ != 'l') { throwError(QJsonParseError::IllegalValue); } + + return QJsonValue(); +} + +//------------------------------------------------------------------------------ +// Name: getTrue +//------------------------------------------------------------------------------ +QJsonValue QJsonParser::getTrue() { + if(p_ == end_ || *p_++ != 't') { throwError(QJsonParseError::IllegalValue); } + if(p_ == end_ || *p_++ != 'r') { throwError(QJsonParseError::IllegalValue); } + if(p_ == end_ || *p_++ != 'u') { throwError(QJsonParseError::IllegalValue); } + if(p_ == end_ || *p_++ != 'e') { throwError(QJsonParseError::IllegalValue); } + + return QJsonValue(true); +} + +//------------------------------------------------------------------------------ +// Name: getFalse +//------------------------------------------------------------------------------ +QJsonValue QJsonParser::getFalse() { + if(p_ == end_ || *p_++ != 'f') { throwError(QJsonParseError::IllegalValue); } + if(p_ == end_ || *p_++ != 'a') { throwError(QJsonParseError::IllegalValue); } + if(p_ == end_ || *p_++ != 'l') { throwError(QJsonParseError::IllegalValue); } + if(p_ == end_ || *p_++ != 's') { throwError(QJsonParseError::IllegalValue); } + if(p_ == end_ || *p_++ != 'e') { throwError(QJsonParseError::IllegalValue); } + + return QJsonValue(false); +} + +//------------------------------------------------------------------------------ +// Name: getNumber +//------------------------------------------------------------------------------ +QJsonValue QJsonParser::getNumber() { + // JSON numbers fit the regex: -?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)? + + const char *const first = p_; + + // -? + if(p_ != end_ && *p_ == '-') { + ++p_; + } + + // (0|[1-9][0-9]*) + if(p_ != end_) { + if(*p_ >= '1' && *p_ <= '9') { + while(p_ != end_ && std::isdigit(*p_)) { + ++p_; + } + } else if(*p_ == '0') { + ++p_; + } else { + throwError(QJsonParseError::IllegalNumber); + } + } + + // (\.[0-9]+)? + if(p_ != end_ && *p_ == '.') { + ++p_; + if(!std::isdigit(*p_)) { + throwError(QJsonParseError::IllegalNumber); + } + + while(p_ != end_ && std::isdigit(*p_)) { + ++p_; + } + } + + // ([eE][+-]?[0-9]+)? + if(p_ != end_ && (*p_ == 'e' || *p_ == 'E')) { + ++p_; + if(p_ != end_ && (*p_ == '+' || *p_ == '-')) { + ++p_; + } + if(!std::isdigit(*p_)) { + throwError(QJsonParseError::IllegalNumber); + } + while(p_ != end_ && std::isdigit(*p_)) { + ++p_; + } + } + + if(p_ == end_) { + throwError(QJsonParseError::TerminationByNumber); + } + + return QJsonValue(QByteArray::fromRawData(first, p_ - first).toDouble()); +} + +//------------------------------------------------------------------------------ +// Name: state +//------------------------------------------------------------------------------ +QJsonParseError QJsonParser::state() const { + return state_; +} + +//------------------------------------------------------------------------------ +// Name: throwError +//------------------------------------------------------------------------------ +void QJsonParser::throwError(QJsonParseError::ParseError e) { + QJsonParseError err; + err.error = e; + err.offset = p_ - begin_; + throw err; +} + +#endif diff --git a/qjson4/QJsonParser.h b/qjson4/QJsonParser.h index 0686838..d54a0d9 100755 --- a/qjson4/QJsonParser.h +++ b/qjson4/QJsonParser.h @@ -1,81 +1,81 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -// NOTE: this is not part of the "public" Qt API, so using this class directly -// is not recomended - -#ifndef QJSON_PARSER_H_ -#define QJSON_PARSER_H_ - -#include <QtCore/QtGlobal> - -#if QT_VERSION < 0x050000 - -#include "QJsonParseError.h" -#include <QPair> -class QJsonRoot; -class QJsonObject; -class QJsonArray; -class QJsonValue; - -class QJsonParser { - friend class QJsonDocument; - -public: - QJsonParser(const char *begin, const char *end); - -public: - QJsonRoot *parse(); - -public: - QJsonParseError state() const; - -private: - static const char ArrayBegin = '['; - static const char ArrayEnd = ']'; - static const char NameSeparator = ':'; - static const char ValueSeparator = ','; - static const char ObjectBegin = '{'; - static const char ObjectEnd = '}'; - static const char Quote = '"'; - -private: - char peek(); - QJsonObject *getObject(); - QJsonArray *getArray(); - QJsonValue getValue(); - QString getString(); - QJsonValue getTrue(); - QJsonValue getFalse(); - QJsonValue getNull(); - QJsonValue getNumber(); - QPair<QString, QJsonValue> getPair(); - -private: - void throwError(QJsonParseError::ParseError e); - -private: - QJsonParseError state_; - const char *const begin_; - const char *const end_; - const char * p_; -}; - -#endif - -#endif +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +// NOTE: this is not part of the "public" Qt API, so using this class directly +// is not recomended + +#ifndef QJSON_PARSER_H_ +#define QJSON_PARSER_H_ + +#include <QtCore/QtGlobal> + +#if QT_VERSION < 0x050000 + +#include "QJsonParseError.h" +#include <QPair> +class QJsonRoot; +class QJsonObject; +class QJsonArray; +class QJsonValue; + +class QJsonParser { + friend class QJsonDocument; + +public: + QJsonParser(const char *begin, const char *end); + +public: + QJsonRoot *parse(); + +public: + QJsonParseError state() const; + +private: + static const char ArrayBegin = '['; + static const char ArrayEnd = ']'; + static const char NameSeparator = ':'; + static const char ValueSeparator = ','; + static const char ObjectBegin = '{'; + static const char ObjectEnd = '}'; + static const char Quote = '"'; + +private: + char peek(); + QJsonObject *getObject(); + QJsonArray *getArray(); + QJsonValue getValue(); + QString getString(); + QJsonValue getTrue(); + QJsonValue getFalse(); + QJsonValue getNull(); + QJsonValue getNumber(); + QPair<QString, QJsonValue> getPair(); + +private: + void throwError(QJsonParseError::ParseError e); + +private: + QJsonParseError state_; + const char *const begin_; + const char *const end_; + const char * p_; +}; + +#endif + +#endif diff --git a/qjson4/QJsonRoot b/qjson4/QJsonRoot index 32bf3f0..fbcaca1 100755 --- a/qjson4/QJsonRoot +++ b/qjson4/QJsonRoot @@ -1 +1 @@ -#include "QJsonRoot.h" +#include "QJsonRoot.h" diff --git a/qjson4/QJsonRoot.h b/qjson4/QJsonRoot.h index a7e0729..77b9751 100755 --- a/qjson4/QJsonRoot.h +++ b/qjson4/QJsonRoot.h @@ -1,45 +1,45 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef QJSON_ROOT_H_ -#define QJSON_ROOT_H_ - -#include <QtCore/QtGlobal> - -#if QT_VERSION < 0x050000 - -class QJsonObject; -class QJsonArray; - -class QJsonRoot { -public: - virtual ~QJsonRoot() {}; - -public: - virtual QJsonRoot *clone() const = 0; - -public: - virtual QJsonArray *toArray() = 0; - virtual QJsonObject *toObject() = 0; - virtual const QJsonArray *toArray() const = 0; - virtual const QJsonObject *toObject() const = 0; -}; - -#endif - -#endif +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef QJSON_ROOT_H_ +#define QJSON_ROOT_H_ + +#include <QtCore/QtGlobal> + +#if QT_VERSION < 0x050000 + +class QJsonObject; +class QJsonArray; + +class QJsonRoot { +public: + virtual ~QJsonRoot() {}; + +public: + virtual QJsonRoot *clone() const = 0; + +public: + virtual QJsonArray *toArray() = 0; + virtual QJsonObject *toObject() = 0; + virtual const QJsonArray *toArray() const = 0; + virtual const QJsonObject *toObject() const = 0; +}; + +#endif + +#endif diff --git a/qjson4/QJsonValue b/qjson4/QJsonValue index d4ca2b1..eb1b6fe 100755 --- a/qjson4/QJsonValue +++ b/qjson4/QJsonValue @@ -1 +1 @@ -#include "QJsonValue.h" +#include "QJsonValue.h" diff --git a/qjson4/QJsonValue.cpp b/qjson4/QJsonValue.cpp index 8365571..68bf87f 100755 --- a/qjson4/QJsonValue.cpp +++ b/qjson4/QJsonValue.cpp @@ -1,391 +1,391 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "QJsonValue.h" -#include "QJsonArray.h" -#include "QJsonObject.h" - -#if QT_VERSION < 0x050000 -#include <QtCore/QtAlgorithms> -#include <QtCore/qmath.h> - -//------------------------------------------------------------------------------ -// Name: QJsonValue -//------------------------------------------------------------------------------ -QJsonValue::QJsonValue(Type type) : type_(type) { -} - -//------------------------------------------------------------------------------ -// Name: QJsonValue -//------------------------------------------------------------------------------ -QJsonValue::QJsonValue(bool b) : type_(Bool) { - value_.b = b; -} - -//------------------------------------------------------------------------------ -// Name: QJsonValue -//------------------------------------------------------------------------------ -QJsonValue::QJsonValue(double n) : type_(Double) { - value_.n = n; -} - -//------------------------------------------------------------------------------ -// Name: QJsonValue -//------------------------------------------------------------------------------ -QJsonValue::QJsonValue(const QString &s) : type_(String) { - value_.s = new QString(s); -} - -//------------------------------------------------------------------------------ -// Name: QJsonValue -//------------------------------------------------------------------------------ -QJsonValue::QJsonValue(QLatin1String s) : type_(String) { - value_.s = new QString(s); -} - -#ifndef QT_NO_CAST_FROM_ASCII -//------------------------------------------------------------------------------ -// Name: QJsonValue -//------------------------------------------------------------------------------ -QJsonValue::QJsonValue(const char *s) : type_(String) { - value_.s = new QString(QString::fromUtf8(s)); -} -#endif - -//------------------------------------------------------------------------------ -// Name: QJsonValue -//------------------------------------------------------------------------------ -QJsonValue::QJsonValue(const QJsonArray &a) : type_(Array) { - value_.r = a.clone(); -} - -//------------------------------------------------------------------------------ -// Name: QJsonValue -//------------------------------------------------------------------------------ -QJsonValue::QJsonValue(const QJsonObject &o) : type_(Object) { - value_.r = o.clone(); -} - -//------------------------------------------------------------------------------ -// Name: QJsonValue -//------------------------------------------------------------------------------ -QJsonValue::QJsonValue(int n) : type_(Double) { - value_.n = n; -} - -//------------------------------------------------------------------------------ -// Name: QJsonValue -//------------------------------------------------------------------------------ -QJsonValue::QJsonValue(qint64 n) : type_(Double) { - value_.n = n; -} - -//------------------------------------------------------------------------------ -// Name: QJsonValue -//------------------------------------------------------------------------------ -QJsonValue::QJsonValue(const QJsonValue &other) : type_(other.type_) { - - switch(other.type_) { - case Bool: - value_.b = other.value_.b; - break; - case Double: - value_.n = other.value_.n; - break; - case String: - value_.s = new QString(*other.value_.s); - break; - case Array: - case Object: - value_.r = other.value_.r->clone(); - break; - case Undefined: - case Null: - value_ = other.value_; - break; - } -} - -//------------------------------------------------------------------------------ -// Name: ~QJsonValue -//------------------------------------------------------------------------------ -QJsonValue::~QJsonValue() { - switch(type_) { - case Null: - case Bool: - case Double: - case Undefined: - break; - case String: - delete value_.s; - break; - case Object: - case Array: - delete value_.r; - break; - } -} - -//------------------------------------------------------------------------------ -// Name: operator= -//------------------------------------------------------------------------------ -QJsonValue &QJsonValue::operator=(const QJsonValue &other) { - QJsonValue(other).swap(*this); - return *this; -} - -//------------------------------------------------------------------------------ -// Name: operator!= -//------------------------------------------------------------------------------ -bool QJsonValue::operator!=(const QJsonValue &other) const { - return !(*this == other); -} - -//------------------------------------------------------------------------------ -// Name: operator== -//------------------------------------------------------------------------------ -bool QJsonValue::operator==(const QJsonValue &other) const { - if(type_ == other.type_) { - switch(type_) { - case Null: - return true; - case Bool: - return value_.b == other.value_.b; - case Double: - return value_.n == other.value_.n; - case Undefined: - return true; - case String: - return *value_.s == *other.value_.s; - case Array: - return *(value_.r->toArray()) == *(other.value_.r->toArray()); - case Object: - return *(value_.r->toObject()) == *(other.value_.r->toObject()); - } - } - return false; -} - -//------------------------------------------------------------------------------ -// Name: isArray -//------------------------------------------------------------------------------ -bool QJsonValue::isArray() const { - return type_ == Array; -} - -//------------------------------------------------------------------------------ -// Name: isBool -//------------------------------------------------------------------------------ -bool QJsonValue::isBool() const { - return type_ == Bool; -} - -//------------------------------------------------------------------------------ -// Name: isDouble -//------------------------------------------------------------------------------ -bool QJsonValue::isDouble() const { - return type_ == Double; -} - -//------------------------------------------------------------------------------ -// Name: isNull -//------------------------------------------------------------------------------ -bool QJsonValue::isNull() const { - return type_ == Null; -} - -//------------------------------------------------------------------------------ -// Name: isObject -//------------------------------------------------------------------------------ -bool QJsonValue::isObject() const { - return type_ == Object; -} - -//------------------------------------------------------------------------------ -// Name: isString -//------------------------------------------------------------------------------ -bool QJsonValue::isString() const { - return type_ == String; -} - -//------------------------------------------------------------------------------ -// Name: isUndefined -//------------------------------------------------------------------------------ -bool QJsonValue::isUndefined() const { - return type_ == Undefined; -} - -//------------------------------------------------------------------------------ -// Name: type -//------------------------------------------------------------------------------ -QJsonValue::Type QJsonValue::type() const { - return type_; -} - -//------------------------------------------------------------------------------ -// Name: toArray -//------------------------------------------------------------------------------ -QJsonArray QJsonValue::toArray(const QJsonArray &defaultValue) const { - if(isArray()) { - return *(value_.r->toArray()); - } - - return defaultValue; -} - -//------------------------------------------------------------------------------ -// Name: toArray -//------------------------------------------------------------------------------ -QJsonArray QJsonValue::toArray() const { - return toArray(QJsonArray()); -} - -//------------------------------------------------------------------------------ -// Name: toBool -//------------------------------------------------------------------------------ -bool QJsonValue::toBool(bool defaultValue) const { - if(isBool()) { - return value_.b; - } - - return defaultValue; -} - -//------------------------------------------------------------------------------ -// Name: toDouble -//------------------------------------------------------------------------------ -double QJsonValue::toDouble(double defaultValue) const { - if(isDouble()) { - return value_.n; - } - - return defaultValue; -} - -//------------------------------------------------------------------------------ -// Name: toInt -//------------------------------------------------------------------------------ -int QJsonValue::toInt(int defaultValue) const { - if(isDouble() && qFloor(value_.n) == value_.n) { - return value_.n; - } - - return defaultValue; -} - -//------------------------------------------------------------------------------ -// Name: toObject -//------------------------------------------------------------------------------ -QJsonObject QJsonValue::toObject(const QJsonObject &defaultValue) const { - if(isObject()) { - return *(value_.r->toObject()); - } - - return defaultValue; -} - -//------------------------------------------------------------------------------ -// Name: toObject -//------------------------------------------------------------------------------ -QJsonObject QJsonValue::toObject() const { - return toObject(QJsonObject()); -} - -//------------------------------------------------------------------------------ -// Name: toString -//------------------------------------------------------------------------------ -QString QJsonValue::toString(const QString &defaultValue) const { - - if(isString()) { - return *value_.s; - } - - return defaultValue; -} - -//------------------------------------------------------------------------------ -// Name: toVariant -//------------------------------------------------------------------------------ -QVariant QJsonValue::toVariant() const { - switch(type_) { - case Null: - return QVariant(); - case Bool: - return QVariant::fromValue(value_.b); - case Double: - return QVariant::fromValue(value_.n); - case String: - return QVariant::fromValue(*value_.s); - case Array: - return value_.r->toArray()->toVariantList(); - case Object: - return value_.r->toObject()->toVariantMap(); - case Undefined: - return QVariant(); - } - - return QVariant(); -} - -//------------------------------------------------------------------------------ -// Name: fromVariant -//------------------------------------------------------------------------------ -QJsonValue QJsonValue::fromVariant(const QVariant &variant) { - if(variant.isNull()) { - return QJsonValue(Null); - } - - switch(variant.type()) { - case QVariant::Bool: - return QJsonValue(variant.toBool()); - case QVariant::Int: - return QJsonValue(variant.toInt()); - case QVariant::Double: - case QVariant::LongLong: - case QVariant::ULongLong: - case QVariant::UInt: - return QJsonValue(variant.toDouble()); - case QVariant::String: - return QJsonValue(variant.toString()); - case QVariant::List: - return QJsonArray::fromVariantList(variant.toList()); - case QVariant::StringList: - return QJsonArray::fromStringList(variant.toStringList()); - case QVariant::Map: - return QJsonObject::fromVariantMap(variant.toMap()); - default: - const QString s = variant.toString(); - if(!s.isEmpty()) { - return QJsonValue(s); - } - break; - } - - return QJsonValue(Null); - -} - -//------------------------------------------------------------------------------ -// Name: swap -//------------------------------------------------------------------------------ -void QJsonValue::swap(QJsonValue &other) { - qSwap(type_, other.type_); - qSwap(value_, other.value_); -} - -#endif +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "QJsonValue.h" +#include "QJsonArray.h" +#include "QJsonObject.h" + +#if QT_VERSION < 0x050000 +#include <QtCore/QtAlgorithms> +#include <QtCore/qmath.h> + +//------------------------------------------------------------------------------ +// Name: QJsonValue +//------------------------------------------------------------------------------ +QJsonValue::QJsonValue(Type type) : type_(type) { +} + +//------------------------------------------------------------------------------ +// Name: QJsonValue +//------------------------------------------------------------------------------ +QJsonValue::QJsonValue(bool b) : type_(Bool) { + value_.b = b; +} + +//------------------------------------------------------------------------------ +// Name: QJsonValue +//------------------------------------------------------------------------------ +QJsonValue::QJsonValue(double n) : type_(Double) { + value_.n = n; +} + +//------------------------------------------------------------------------------ +// Name: QJsonValue +//------------------------------------------------------------------------------ +QJsonValue::QJsonValue(const QString &s) : type_(String) { + value_.s = new QString(s); +} + +//------------------------------------------------------------------------------ +// Name: QJsonValue +//------------------------------------------------------------------------------ +QJsonValue::QJsonValue(QLatin1String s) : type_(String) { + value_.s = new QString(s); +} + +#ifndef QT_NO_CAST_FROM_ASCII +//------------------------------------------------------------------------------ +// Name: QJsonValue +//------------------------------------------------------------------------------ +QJsonValue::QJsonValue(const char *s) : type_(String) { + value_.s = new QString(QString::fromUtf8(s)); +} +#endif + +//------------------------------------------------------------------------------ +// Name: QJsonValue +//------------------------------------------------------------------------------ +QJsonValue::QJsonValue(const QJsonArray &a) : type_(Array) { + value_.r = a.clone(); +} + +//------------------------------------------------------------------------------ +// Name: QJsonValue +//------------------------------------------------------------------------------ +QJsonValue::QJsonValue(const QJsonObject &o) : type_(Object) { + value_.r = o.clone(); +} + +//------------------------------------------------------------------------------ +// Name: QJsonValue +//------------------------------------------------------------------------------ +QJsonValue::QJsonValue(int n) : type_(Double) { + value_.n = n; +} + +//------------------------------------------------------------------------------ +// Name: QJsonValue +//------------------------------------------------------------------------------ +QJsonValue::QJsonValue(qint64 n) : type_(Double) { + value_.n = n; +} + +//------------------------------------------------------------------------------ +// Name: QJsonValue +//------------------------------------------------------------------------------ +QJsonValue::QJsonValue(const QJsonValue &other) : type_(other.type_) { + + switch(other.type_) { + case Bool: + value_.b = other.value_.b; + break; + case Double: + value_.n = other.value_.n; + break; + case String: + value_.s = new QString(*other.value_.s); + break; + case Array: + case Object: + value_.r = other.value_.r->clone(); + break; + case Undefined: + case Null: + value_ = other.value_; + break; + } +} + +//------------------------------------------------------------------------------ +// Name: ~QJsonValue +//------------------------------------------------------------------------------ +QJsonValue::~QJsonValue() { + switch(type_) { + case Null: + case Bool: + case Double: + case Undefined: + break; + case String: + delete value_.s; + break; + case Object: + case Array: + delete value_.r; + break; + } +} + +//------------------------------------------------------------------------------ +// Name: operator= +//------------------------------------------------------------------------------ +QJsonValue &QJsonValue::operator=(const QJsonValue &other) { + QJsonValue(other).swap(*this); + return *this; +} + +//------------------------------------------------------------------------------ +// Name: operator!= +//------------------------------------------------------------------------------ +bool QJsonValue::operator!=(const QJsonValue &other) const { + return !(*this == other); +} + +//------------------------------------------------------------------------------ +// Name: operator== +//------------------------------------------------------------------------------ +bool QJsonValue::operator==(const QJsonValue &other) const { + if(type_ == other.type_) { + switch(type_) { + case Null: + return true; + case Bool: + return value_.b == other.value_.b; + case Double: + return value_.n == other.value_.n; + case Undefined: + return true; + case String: + return *value_.s == *other.value_.s; + case Array: + return *(value_.r->toArray()) == *(other.value_.r->toArray()); + case Object: + return *(value_.r->toObject()) == *(other.value_.r->toObject()); + } + } + return false; +} + +//------------------------------------------------------------------------------ +// Name: isArray +//------------------------------------------------------------------------------ +bool QJsonValue::isArray() const { + return type_ == Array; +} + +//------------------------------------------------------------------------------ +// Name: isBool +//------------------------------------------------------------------------------ +bool QJsonValue::isBool() const { + return type_ == Bool; +} + +//------------------------------------------------------------------------------ +// Name: isDouble +//------------------------------------------------------------------------------ +bool QJsonValue::isDouble() const { + return type_ == Double; +} + +//------------------------------------------------------------------------------ +// Name: isNull +//------------------------------------------------------------------------------ +bool QJsonValue::isNull() const { + return type_ == Null; +} + +//------------------------------------------------------------------------------ +// Name: isObject +//------------------------------------------------------------------------------ +bool QJsonValue::isObject() const { + return type_ == Object; +} + +//------------------------------------------------------------------------------ +// Name: isString +//------------------------------------------------------------------------------ +bool QJsonValue::isString() const { + return type_ == String; +} + +//------------------------------------------------------------------------------ +// Name: isUndefined +//------------------------------------------------------------------------------ +bool QJsonValue::isUndefined() const { + return type_ == Undefined; +} + +//------------------------------------------------------------------------------ +// Name: type +//------------------------------------------------------------------------------ +QJsonValue::Type QJsonValue::type() const { + return type_; +} + +//------------------------------------------------------------------------------ +// Name: toArray +//------------------------------------------------------------------------------ +QJsonArray QJsonValue::toArray(const QJsonArray &defaultValue) const { + if(isArray()) { + return *(value_.r->toArray()); + } + + return defaultValue; +} + +//------------------------------------------------------------------------------ +// Name: toArray +//------------------------------------------------------------------------------ +QJsonArray QJsonValue::toArray() const { + return toArray(QJsonArray()); +} + +//------------------------------------------------------------------------------ +// Name: toBool +//------------------------------------------------------------------------------ +bool QJsonValue::toBool(bool defaultValue) const { + if(isBool()) { + return value_.b; + } + + return defaultValue; +} + +//------------------------------------------------------------------------------ +// Name: toDouble +//------------------------------------------------------------------------------ +double QJsonValue::toDouble(double defaultValue) const { + if(isDouble()) { + return value_.n; + } + + return defaultValue; +} + +//------------------------------------------------------------------------------ +// Name: toInt +//------------------------------------------------------------------------------ +int QJsonValue::toInt(int defaultValue) const { + if(isDouble() && qFloor(value_.n) == value_.n) { + return value_.n; + } + + return defaultValue; +} + +//------------------------------------------------------------------------------ +// Name: toObject +//------------------------------------------------------------------------------ +QJsonObject QJsonValue::toObject(const QJsonObject &defaultValue) const { + if(isObject()) { + return *(value_.r->toObject()); + } + + return defaultValue; +} + +//------------------------------------------------------------------------------ +// Name: toObject +//------------------------------------------------------------------------------ +QJsonObject QJsonValue::toObject() const { + return toObject(QJsonObject()); +} + +//------------------------------------------------------------------------------ +// Name: toString +//------------------------------------------------------------------------------ +QString QJsonValue::toString(const QString &defaultValue) const { + + if(isString()) { + return *value_.s; + } + + return defaultValue; +} + +//------------------------------------------------------------------------------ +// Name: toVariant +//------------------------------------------------------------------------------ +QVariant QJsonValue::toVariant() const { + switch(type_) { + case Null: + return QVariant(); + case Bool: + return QVariant::fromValue(value_.b); + case Double: + return QVariant::fromValue(value_.n); + case String: + return QVariant::fromValue(*value_.s); + case Array: + return value_.r->toArray()->toVariantList(); + case Object: + return value_.r->toObject()->toVariantMap(); + case Undefined: + return QVariant(); + } + + return QVariant(); +} + +//------------------------------------------------------------------------------ +// Name: fromVariant +//------------------------------------------------------------------------------ +QJsonValue QJsonValue::fromVariant(const QVariant &variant) { + if(variant.isNull()) { + return QJsonValue(Null); + } + + switch(variant.type()) { + case QVariant::Bool: + return QJsonValue(variant.toBool()); + case QVariant::Int: + return QJsonValue(variant.toInt()); + case QVariant::Double: + case QVariant::LongLong: + case QVariant::ULongLong: + case QVariant::UInt: + return QJsonValue(variant.toDouble()); + case QVariant::String: + return QJsonValue(variant.toString()); + case QVariant::List: + return QJsonArray::fromVariantList(variant.toList()); + case QVariant::StringList: + return QJsonArray::fromStringList(variant.toStringList()); + case QVariant::Map: + return QJsonObject::fromVariantMap(variant.toMap()); + default: + const QString s = variant.toString(); + if(!s.isEmpty()) { + return QJsonValue(s); + } + break; + } + + return QJsonValue(Null); + +} + +//------------------------------------------------------------------------------ +// Name: swap +//------------------------------------------------------------------------------ +void QJsonValue::swap(QJsonValue &other) { + qSwap(type_, other.type_); + qSwap(value_, other.value_); +} + +#endif diff --git a/qjson4/QJsonValue.h b/qjson4/QJsonValue.h index dec14aa..bf32898 100755 --- a/qjson4/QJsonValue.h +++ b/qjson4/QJsonValue.h @@ -1,120 +1,120 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef QJSON_VALUE_H_ -#define QJSON_VALUE_H_ - -#include <QtCore/QtGlobal> - -#if QT_VERSION >= 0x050000 -#include <QtCore/QJsonValue> -#else - -class QString; - -#include <QtCore/QVariant> - -class QJsonRoot; -class QJsonArray; -class QJsonObject; - -class QJsonValue { -public: - enum Type { - Null = 0x0, - Bool = 0x1, - Double = 0x2, - String = 0x3, - Array = 0x4, - Object = 0x5, - Undefined = 0x80 - }; - -public: - QJsonValue(Type type = Null); - QJsonValue(bool b); - QJsonValue(double n); - QJsonValue(int n); - QJsonValue(qint64 n); - QJsonValue(const QString &s); - QJsonValue(QLatin1String s); -#ifndef QT_NO_CAST_FROM_ASCII - QJsonValue(const char *s); -#endif - QJsonValue(const QJsonArray &a); - QJsonValue(const QJsonObject &o); - QJsonValue(const QJsonValue &other); - - ~QJsonValue(); - -private: - // to protect against incorrect usage due to passing a const char * - QJsonValue(const void *); - -public: - QJsonValue &operator=(const QJsonValue &other); - -public: - bool operator!=(const QJsonValue &other) const; - bool operator==(const QJsonValue &other) const; - -public: - bool isArray() const; - bool isBool() const; - bool isDouble() const; - bool isNull() const; - bool isObject() const; - bool isString() const; - bool isUndefined() const; - -public: - QJsonArray toArray(const QJsonArray &defaultValue) const; - QJsonArray toArray() const; - bool toBool(bool defaultValue = false) const; - double toDouble(double defaultValue = 0) const; - int toInt(int defaultValue = 0) const; - QJsonObject toObject(const QJsonObject &defaultValue) const; - QJsonObject toObject() const; - QString toString(const QString &defaultValue = QString()) const; - QVariant toVariant() const; - -public: - Type type() const; - -public: - static QJsonValue fromVariant(const QVariant &variant); - -private: - void swap(QJsonValue &other); - -private: - Type type_; - - union ValueType { - bool b; - double n; - QString *s; - QJsonRoot *r; // OJsonObject or QJsonArray - }; - - ValueType value_; -}; - -#endif - -#endif +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef QJSON_VALUE_H_ +#define QJSON_VALUE_H_ + +#include <QtCore/QtGlobal> + +#if QT_VERSION >= 0x050000 +#include <QtCore/QJsonValue> +#else + +class QString; + +#include <QtCore/QVariant> + +class QJsonRoot; +class QJsonArray; +class QJsonObject; + +class QJsonValue { +public: + enum Type { + Null = 0x0, + Bool = 0x1, + Double = 0x2, + String = 0x3, + Array = 0x4, + Object = 0x5, + Undefined = 0x80 + }; + +public: + QJsonValue(Type type = Null); + QJsonValue(bool b); + QJsonValue(double n); + QJsonValue(int n); + QJsonValue(qint64 n); + QJsonValue(const QString &s); + QJsonValue(QLatin1String s); +#ifndef QT_NO_CAST_FROM_ASCII + QJsonValue(const char *s); +#endif + QJsonValue(const QJsonArray &a); + QJsonValue(const QJsonObject &o); + QJsonValue(const QJsonValue &other); + + ~QJsonValue(); + +private: + // to protect against incorrect usage due to passing a const char * + QJsonValue(const void *); + +public: + QJsonValue &operator=(const QJsonValue &other); + +public: + bool operator!=(const QJsonValue &other) const; + bool operator==(const QJsonValue &other) const; + +public: + bool isArray() const; + bool isBool() const; + bool isDouble() const; + bool isNull() const; + bool isObject() const; + bool isString() const; + bool isUndefined() const; + +public: + QJsonArray toArray(const QJsonArray &defaultValue) const; + QJsonArray toArray() const; + bool toBool(bool defaultValue = false) const; + double toDouble(double defaultValue = 0) const; + int toInt(int defaultValue = 0) const; + QJsonObject toObject(const QJsonObject &defaultValue) const; + QJsonObject toObject() const; + QString toString(const QString &defaultValue = QString()) const; + QVariant toVariant() const; + +public: + Type type() const; + +public: + static QJsonValue fromVariant(const QVariant &variant); + +private: + void swap(QJsonValue &other); + +private: + Type type_; + + union ValueType { + bool b; + double n; + QString *s; + QJsonRoot *r; // OJsonObject or QJsonArray + }; + + ValueType value_; +}; + +#endif + +#endif diff --git a/qjson4/QJsonValueRef b/qjson4/QJsonValueRef index f106170..f3b6811 100755 --- a/qjson4/QJsonValueRef +++ b/qjson4/QJsonValueRef @@ -1 +1 @@ -#include "QJsonValueRef.h" +#include "QJsonValueRef.h" diff --git a/qjson4/QJsonValueRef.cpp b/qjson4/QJsonValueRef.cpp index 386d056..7d67ef4 100755 --- a/qjson4/QJsonValueRef.cpp +++ b/qjson4/QJsonValueRef.cpp @@ -1,228 +1,228 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "QJsonValueRef.h" - -#if QT_VERSION < 0x050000 - -#include "QJsonArray.h" -#include "QJsonObject.h" - -//------------------------------------------------------------------------------ -// Name: -// Desc: -//------------------------------------------------------------------------------ -QJsonValueRef::QJsonValueRef(QJsonArray *array, int idx) : p_(array), index_(idx) { -} - -//------------------------------------------------------------------------------ -// Name: -// Desc: -//------------------------------------------------------------------------------ -QJsonValueRef::QJsonValueRef(QJsonObject *object, const QString &key) : p_(object), index_(0), key_(key) { -} - -//------------------------------------------------------------------------------ -// Name: -// Desc: -//------------------------------------------------------------------------------ -QJsonValueRef::operator QJsonValue() const { - return toValue(); -} - -//------------------------------------------------------------------------------ -// Name: -// Desc: -//------------------------------------------------------------------------------ -QJsonValueRef &QJsonValueRef::operator=(const QJsonValue &val) { - - if(QJsonObject *const o = p_->toObject()) { - o->values_[key_] = val; - } else if(QJsonArray *const a = p_->toArray()) { - a->values_[index_] = val; - } - return *this; -} - -//------------------------------------------------------------------------------ -// Name: -// Desc: -//------------------------------------------------------------------------------ -QJsonValueRef &QJsonValueRef::operator=(const QJsonValueRef &ref) { - - if(QJsonObject *const o = p_->toObject()) { - o->values_[key_] = ref; - } else if(QJsonArray *const a = p_->toArray()) { - a->values_[index_] = ref; - } - return *this; -} - -//------------------------------------------------------------------------------ -// Name: type -// Desc: -//------------------------------------------------------------------------------ -QJsonValue::Type QJsonValueRef::type() const { - return toValue().type(); -} - -//------------------------------------------------------------------------------ -// Name: isNull -// Desc: -//------------------------------------------------------------------------------ -bool QJsonValueRef::isNull() const { - return toValue().isNull(); -} - -//------------------------------------------------------------------------------ -// Name: isBool -// Desc: -//------------------------------------------------------------------------------ -bool QJsonValueRef::isBool() const { - return toValue().isBool(); -} - -//------------------------------------------------------------------------------ -// Name: isDouble -// Desc: -//------------------------------------------------------------------------------ -bool QJsonValueRef::isDouble() const { - return toValue().isDouble(); -} - -//------------------------------------------------------------------------------ -// Name: isString -// Desc: -//------------------------------------------------------------------------------ -bool QJsonValueRef::isString() const { - return toValue().isString(); -} - -//------------------------------------------------------------------------------ -// Name: isArray -// Desc: -//------------------------------------------------------------------------------ -bool QJsonValueRef::isArray() const { - return toValue().isArray(); -} - -//------------------------------------------------------------------------------ -// Name: isObject -// Desc: -//------------------------------------------------------------------------------ -bool QJsonValueRef::isObject() const { - return toValue().isObject(); -} - -//------------------------------------------------------------------------------ -// Name: isUndefined -// Desc: -//------------------------------------------------------------------------------ -bool QJsonValueRef::isUndefined() const { - return toValue().isUndefined(); -} - -//------------------------------------------------------------------------------ -// Name: toBool -// Desc: -//------------------------------------------------------------------------------ -bool QJsonValueRef::toBool() const { - return toValue().toBool(); -} - -//------------------------------------------------------------------------------ -// Name: toDouble -// Desc: -//------------------------------------------------------------------------------ -double QJsonValueRef::toDouble() const { - return toValue().toDouble(); -} - -//------------------------------------------------------------------------------ -// Name: toInt -// Desc: -//------------------------------------------------------------------------------ -int QJsonValueRef::toInt(int defaultValue) const { - return toValue().toInt(defaultValue); -} - -//------------------------------------------------------------------------------ -// Name: toString -// Desc: -//------------------------------------------------------------------------------ -QString QJsonValueRef::toString() const { - return toValue().toString(); -} - -//------------------------------------------------------------------------------ -// Name: toArray -// Desc: -//------------------------------------------------------------------------------ -QJsonArray QJsonValueRef::toArray() const { - return toValue().toArray(); -} - -//------------------------------------------------------------------------------ -// Name: toObject -// Desc: -//------------------------------------------------------------------------------ -QJsonObject QJsonValueRef::toObject() const { - return toValue().toObject(); -} - -//------------------------------------------------------------------------------ -// Name: operator== -// Desc: -//------------------------------------------------------------------------------ -bool QJsonValueRef::operator==(const QJsonValue &other) const { - return toValue() == other; -} - -//------------------------------------------------------------------------------ -// Name: operator!= -// Desc: -//------------------------------------------------------------------------------ -bool QJsonValueRef::operator!=(const QJsonValue &other) const { - return toValue() != other; -} - -//------------------------------------------------------------------------------ -// Name: toValue -// Desc: -//------------------------------------------------------------------------------ -QJsonValue QJsonValueRef::toValue() const { - if(QJsonObject *const o = p_->toObject()) { - return o->values_[key_]; - } else if(QJsonArray *const a = p_->toArray()) { - return a->values_[index_]; - } - - return QJsonValue(); -} - -//------------------------------------------------------------------------------ -// Name: swap -// Desc: -//------------------------------------------------------------------------------ -void QJsonValueRef::swap(QJsonValueRef &other) { - qSwap(p_, other.p_); - qSwap(key_, other.key_); - qSwap(index_, other.index_); -} - -#endif +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "QJsonValueRef.h" + +#if QT_VERSION < 0x050000 + +#include "QJsonArray.h" +#include "QJsonObject.h" + +//------------------------------------------------------------------------------ +// Name: +// Desc: +//------------------------------------------------------------------------------ +QJsonValueRef::QJsonValueRef(QJsonArray *array, int idx) : p_(array), index_(idx) { +} + +//------------------------------------------------------------------------------ +// Name: +// Desc: +//------------------------------------------------------------------------------ +QJsonValueRef::QJsonValueRef(QJsonObject *object, const QString &key) : p_(object), index_(0), key_(key) { +} + +//------------------------------------------------------------------------------ +// Name: +// Desc: +//------------------------------------------------------------------------------ +QJsonValueRef::operator QJsonValue() const { + return toValue(); +} + +//------------------------------------------------------------------------------ +// Name: +// Desc: +//------------------------------------------------------------------------------ +QJsonValueRef &QJsonValueRef::operator=(const QJsonValue &val) { + + if(QJsonObject *const o = p_->toObject()) { + o->values_[key_] = val; + } else if(QJsonArray *const a = p_->toArray()) { + a->values_[index_] = val; + } + return *this; +} + +//------------------------------------------------------------------------------ +// Name: +// Desc: +//------------------------------------------------------------------------------ +QJsonValueRef &QJsonValueRef::operator=(const QJsonValueRef &ref) { + + if(QJsonObject *const o = p_->toObject()) { + o->values_[key_] = ref; + } else if(QJsonArray *const a = p_->toArray()) { + a->values_[index_] = ref; + } + return *this; +} + +//------------------------------------------------------------------------------ +// Name: type +// Desc: +//------------------------------------------------------------------------------ +QJsonValue::Type QJsonValueRef::type() const { + return toValue().type(); +} + +//------------------------------------------------------------------------------ +// Name: isNull +// Desc: +//------------------------------------------------------------------------------ +bool QJsonValueRef::isNull() const { + return toValue().isNull(); +} + +//------------------------------------------------------------------------------ +// Name: isBool +// Desc: +//------------------------------------------------------------------------------ +bool QJsonValueRef::isBool() const { + return toValue().isBool(); +} + +//------------------------------------------------------------------------------ +// Name: isDouble +// Desc: +//------------------------------------------------------------------------------ +bool QJsonValueRef::isDouble() const { + return toValue().isDouble(); +} + +//------------------------------------------------------------------------------ +// Name: isString +// Desc: +//------------------------------------------------------------------------------ +bool QJsonValueRef::isString() const { + return toValue().isString(); +} + +//------------------------------------------------------------------------------ +// Name: isArray +// Desc: +//------------------------------------------------------------------------------ +bool QJsonValueRef::isArray() const { + return toValue().isArray(); +} + +//------------------------------------------------------------------------------ +// Name: isObject +// Desc: +//------------------------------------------------------------------------------ +bool QJsonValueRef::isObject() const { + return toValue().isObject(); +} + +//------------------------------------------------------------------------------ +// Name: isUndefined +// Desc: +//------------------------------------------------------------------------------ +bool QJsonValueRef::isUndefined() const { + return toValue().isUndefined(); +} + +//------------------------------------------------------------------------------ +// Name: toBool +// Desc: +//------------------------------------------------------------------------------ +bool QJsonValueRef::toBool() const { + return toValue().toBool(); +} + +//------------------------------------------------------------------------------ +// Name: toDouble +// Desc: +//------------------------------------------------------------------------------ +double QJsonValueRef::toDouble() const { + return toValue().toDouble(); +} + +//------------------------------------------------------------------------------ +// Name: toInt +// Desc: +//------------------------------------------------------------------------------ +int QJsonValueRef::toInt(int defaultValue) const { + return toValue().toInt(defaultValue); +} + +//------------------------------------------------------------------------------ +// Name: toString +// Desc: +//------------------------------------------------------------------------------ +QString QJsonValueRef::toString() const { + return toValue().toString(); +} + +//------------------------------------------------------------------------------ +// Name: toArray +// Desc: +//------------------------------------------------------------------------------ +QJsonArray QJsonValueRef::toArray() const { + return toValue().toArray(); +} + +//------------------------------------------------------------------------------ +// Name: toObject +// Desc: +//------------------------------------------------------------------------------ +QJsonObject QJsonValueRef::toObject() const { + return toValue().toObject(); +} + +//------------------------------------------------------------------------------ +// Name: operator== +// Desc: +//------------------------------------------------------------------------------ +bool QJsonValueRef::operator==(const QJsonValue &other) const { + return toValue() == other; +} + +//------------------------------------------------------------------------------ +// Name: operator!= +// Desc: +//------------------------------------------------------------------------------ +bool QJsonValueRef::operator!=(const QJsonValue &other) const { + return toValue() != other; +} + +//------------------------------------------------------------------------------ +// Name: toValue +// Desc: +//------------------------------------------------------------------------------ +QJsonValue QJsonValueRef::toValue() const { + if(QJsonObject *const o = p_->toObject()) { + return o->values_[key_]; + } else if(QJsonArray *const a = p_->toArray()) { + return a->values_[index_]; + } + + return QJsonValue(); +} + +//------------------------------------------------------------------------------ +// Name: swap +// Desc: +//------------------------------------------------------------------------------ +void QJsonValueRef::swap(QJsonValueRef &other) { + qSwap(p_, other.p_); + qSwap(key_, other.key_); + qSwap(index_, other.index_); +} + +#endif diff --git a/qjson4/QJsonValueRef.h b/qjson4/QJsonValueRef.h index 292f37b..567c68a 100755 --- a/qjson4/QJsonValueRef.h +++ b/qjson4/QJsonValueRef.h @@ -1,79 +1,79 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef QJSON_VALUEREF_H_ -#define QJSON_VALUEREF_H_ - -#include <QtCore/QtGlobal> - -#if QT_VERSION >= 0x050000 -#include <QtCore/QJsonValueRef> -#else - -#include "QJsonValue.h" -class QJsonRoot; - -class QJsonValueRef { -public: - QJsonValueRef(QJsonArray *array, int idx); - - // slight variant from official APIs implementation - QJsonValueRef(QJsonObject *object, const QString &key); - -public: - operator QJsonValue() const; - -public: - QJsonValueRef &operator=(const QJsonValue &val); - QJsonValueRef &operator=(const QJsonValueRef &val); - -public: - QJsonValue::Type type() const; - bool isNull() const; - bool isBool() const; - bool isDouble() const; - bool isString() const; - bool isArray() const; - bool isObject() const; - bool isUndefined() const; - -public: - bool toBool() const; - double toDouble() const; - QString toString() const; - QJsonArray toArray() const; - QJsonObject toObject() const; - int toInt(int defaultValue = 0) const; - -public: - bool operator==(const QJsonValue &other) const; - bool operator!=(const QJsonValue &other) const; - -private: - QJsonValue toValue() const; - void swap(QJsonValueRef &other); - -private: - QJsonRoot *p_; - int index_; - QString key_; -}; - -#endif - -#endif +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef QJSON_VALUEREF_H_ +#define QJSON_VALUEREF_H_ + +#include <QtCore/QtGlobal> + +#if QT_VERSION >= 0x050000 +#include <QtCore/QJsonValueRef> +#else + +#include "QJsonValue.h" +class QJsonRoot; + +class QJsonValueRef { +public: + QJsonValueRef(QJsonArray *array, int idx); + + // slight variant from official APIs implementation + QJsonValueRef(QJsonObject *object, const QString &key); + +public: + operator QJsonValue() const; + +public: + QJsonValueRef &operator=(const QJsonValue &val); + QJsonValueRef &operator=(const QJsonValueRef &val); + +public: + QJsonValue::Type type() const; + bool isNull() const; + bool isBool() const; + bool isDouble() const; + bool isString() const; + bool isArray() const; + bool isObject() const; + bool isUndefined() const; + +public: + bool toBool() const; + double toDouble() const; + QString toString() const; + QJsonArray toArray() const; + QJsonObject toObject() const; + int toInt(int defaultValue = 0) const; + +public: + bool operator==(const QJsonValue &other) const; + bool operator!=(const QJsonValue &other) const; + +private: + QJsonValue toValue() const; + void swap(QJsonValueRef &other); + +private: + QJsonRoot *p_; + int index_; + QString key_; +}; + +#endif + +#endif diff --git a/res/960x536.png b/res/960x536.png index 0feac2dc3f360a6262056aca768a6491a083e00e..6196065a0e29eba946336f809392fd55a7e93c17 100644 GIT binary patch literal 19532 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 literal 48000 zcmeFZd035Y`!>9igi@wbNrgok6h-r33M&n0q){|#p3_K(LaZiZC7S1XE+i?GN}5YE z&4cFY+pqiip5OP!vwiROzT5Nf+wI=4)LPedp2v9{`@SFhaos<!a%R&;j*TP|X%pq_ zsf#2MZ4QaFhHd>iymIM<Z3cc@XLRn&DbgzOUu1D?5MJ3}d-jq8iNvst_@9RK{3RP+ zq<5q!E71R9Si5PBApdrMO}w<rTwUAoq>Yu8v9%-qN+O-KH@@O%e2vG&+|i8Z3`P0; zH6deq5{ZXIIdxp!wPm>7&2_uR%F*$l>XKtTn|YFU-z1&f8oGY{mP>0dT-$b@#(2vG z$F=MVTa34}xwJX49ao?+W<P&P_t=FkH`B(>@sJ;{UB6*7&+c<BQhEc+SNAVJn%Zfq zTR<KCJ1<i+JHb4yIjHG0E31)fJx}5}^{+3PU<Ey%J^y@d%=y>vd;a4OQHBEl`ltWJ zAO7Qq{*T_~zx(O`xvc;0ZT`ET{=XOTA5rq(E$Dyu)BhXW5oMStw0X-vUvxVE`hClP z{NX|x%fJ5VfANR^_@V!!xB2gW`hPC#zk8ei?x+9nMf^vU{C5lb-~IIe#&%pt)7WwE zUthP9|Ns8r%3eB{C3@82$FZsYZ?#2k4yVqXkzQqIXTSgW@#foi@9rU!KVB*+DLHWP z;GG5w1#@#g|A2reFJ1(^e98Gz+J(uqCcHfTYK86Z@4H{hx@(#SENRiu(3t&9V&@RI z9!@&_kmI$=E2%h*#L!HOpGo(9d`NSPi)Edi-1x3EZNWo~v`l`qeSLjt&6fBG;{7)= zFkCo)-bX+y<=4{u)aNf>PFh<FWn^SLe)jDCg9nUFmSVd|+e)>%dwRBP+t#zB5^qo{ zH~1sox4>y=kBkiG&6_vZuU~)c*fA1gna?*9-)|--DU=P9Q&V;m-3l+|y}6z}dnVyF zNfr?iv7H;gqFdy8VVB^Zi<=Zqor+WlU^VL~lH?Gx{GH_A`SAJC>%=?0fB(LE!l$%U ze%M($NmIa5Y-f^YVy2K@!R@xTwum434g<DJb9UE^jpNG{delgAq~G`HD~-~54j<mq zUf^`HF-5O7Sx5Zi$B$2Qiob*j_l$RyouyFTGs`de9Ms8)jEg%P!7AL_)8i{<)e@-| zt76ugbMSJm^~0aZI&a*j`p2gdm#!;dm10$1edsFlOTXSIG~AR<tCMSu9cg&Ku&GmE zm$dV#KrY$GFJC@z9%*^DP)vRG>S3|_?4Eu5=sG=Tcg>8n(o>~2@7cq(=g5)mBdxh- z7H39kQ}m?C`}gk=5@O1}-k6eA`Z_LdeSCbp#EriP9&t+EYA<xT+L~j<L2u?U=+vVY zxG@J=l1<9-z+GnUN4>q*Zr`~><Kw`it*w0zSKZZH8T9$<SI3`s7<Qb$c=1+uw^49# zu*8=xTOJ7sw&TZ-uV-R9ZDw|W<A|Bh-Az09@bhnc$Z_<<(9h&2k01Mddbm?sm4lSl zI?`0^F0Pq;`A&#{)*ew&wTL(i{sRZr<66#)brjb|pW8v+x9_#dx98Q~26ijWmSR}< zuD^fkB^>%0t6xg`A}o6c270PO1giN31y5bN#ExCVud1plL$-B-tPCEWo?Qb2e(&BL zTT4&BS3;u6O(Ped7pIlVHQ1OMxNZ|i<fTlLdygKSwzL$yb?cUwz1QVr&80u8-X9Q- zPNY@8%h?uJ-uck5iCkO1Ff%eFle4-|Y>!a7cJ11)AMt9RtEx`u>xWONSROx4gJ8iY zpV!n}7f^nS_{??dh!f>znyX)YgZL07B}SvGSGRC;2Y&wiIf65HX~`qWpp*;I|8Ze@ z$cb0KcgJ8$w!p=U7k_NopEp`Cl;$*~>GV-v;q>V!m$8nsDk`V#?M1e3+vdHMgWpRU zasDJc{813Es+8%P{@z{*Z*l%n=aA4)sR~->!d)vXE9*CIJYi_agFAbPs&^CjyA)y3 zUT_q_-oLafelGT#Nm=zP>2&k@{gy3R8+39kFMMy9%W4T!ZI^4(yxrVtUAU?E#<abc zn*=8lr;O`n#9=w&>j{-=WRaJok;saZS(|-b>+f*$wnjadT^2v$x@5GaT}D4<7=KB# z?K+{GZ?6y`#@txoblvp(pP$J)iEA;~eD?~^(W5NH_tm~RV>jG%m{Z!B5ix)33R}oZ z?qxyNBQ_nJR;@V-c<nn82fVyj`>I0nR#z6MPtI`9Ei810>R7*@o9L-6^<IteNF8o3 z+#$a-PK&j({q>GUtyJsz5%XJ*c1cGe+Vi^Z?)?7xB)zuas`diT;Cf=ki`=HtaJqIK zd9rHsJ@UAArpZI86YqZpcQzs1|BiKXi+8y0ZOOG^4k+*D+_s&C<;v>Ha#OAiHxrl4 zJzsj}JqHhNqNAe=nGwHx_imK(3o*0$m`yD?Rsq*j^4IAVIxE=Pra8R4F+He}bSZNk zazTZ7rw46edrFW_PrZetT(q=iqGs~kXyI5!R#x!cE8h<>>gU<soEoSx?JV(R-@5f; zw0A^A1b1rj%;l1~?trhKKijT6R8Uaxm~D4?_Vnplml2%?@01*?R{Nhxmt;KV4pF26 z&F$<CH>MiYnAgXop9$n*WMFVu^xVM6*eg9&R907aQRSt?g^Jk-7A~%8-f-7jl9H0u zJuf06YLE;ke(KmHPhQ=*Wy|{uZ%$8S*2rC@Q0`CJv}KwypLxVd2`G>1iMzOb&S|72 zgq)ASoc5z+yG@x;ui4vYG!AE$8+APt@Ay1FH6SW1JjQ$VR$H4c@@6oz+#FA9uFY6Z z=NFWLB1H9EZ;<NbP->}(o!x}0*KCLTn5^?~(}jV&Pq7VF9)tSQFJHd=+K{M~SyZ&d zdnHFTLhkSMv{Nf>L%bSq$xO@juQfF;;kHAKsRKtFb>A>Y@6^)PW*aM>)gNukpW-!O z#npB>)W}wZ%ess3@VwhQYt{et8M*SAsOgPmyA-`bF@qa__OWi?juj6L39)NP(BPD? zjcoNwMUtDqe)J>4Uk&t4^i)Wid}UjhoBKVLc#($lh}mX}{q$hNATwQSr{3YihdpMR zP2KvxvJcFrv|A4##lIt#-E(n<OSU6_s#-eVdE_$E$-s(LTi%o0Hv52Tr-!PEU*>+u zI*Z83h3^!%cI3)?b0*OK!|e@RF5gd_I3aQ6!`ji-+?ssh2+tXI<l{u<gq<2+LJvyX zbjToyG`PJ)^nH$v@Op05k`>Ro7-zT`DDV>*xi9)$m>JtTVZDNn1L5wEriU75<CcGa ze@z=Ec<Dr8yGq%iJOq1cfqT@&W!;C|^5Nw9mBq0{`R$h8Q@h?i*?VTPaID0kLp{B9 zL^s!Z7q8OOcc`(NUjm9}+Z>o(Mq2tfX`^FeCQ}MW>m*Yr;%|+N#UqPMV#{rrn!J`K z&M<KtiM!01x6`KR3C^{n7o}ujFp+W7rUv?4|FNW0-TXSY5|-`TZC94&l@t{doEHa2 z-sd2nC@CvPUtue9o!G<eK72TEbt&7jnaZ$3$dRdpRY><U67ZkQ<jI!jVpbfK$?_cr z>fQ&MRuU}Q@(vq#FHc8&&62k3UK`;tNja^c;P!1|r1lNH{OXc}6eknM-S@%4+nq<- zE)A4?irtt~n)B%adl}wZBK7p&-?eWphbNu9%h>h$q#st!!QNiNb==VNUgEF$+com5 zZSy@&$V(kAot_#iNjbNYCAB&Ss$ZS+D|?S~RI)Vrg^`&#RdcZ^{puO(j-qFGuZ*K) zJU<;X*>YpPFN{LPrf3kC8f5{LF;EjRrdt;M_U&zM@1?`;GsAxxD)KcFHGxPD?_#3I zuN^|VzwI(#9Far*RlH^O?fKFC8`BoJ1!Rt?*M3|HGXYUZdy`#$+$LA9?A}!NtAg7* zsW3O>JSuB9J-5fNqBS|5i_T0t#l8xJU-<jUur)zLASODx_7J0WbH<%yo!pe4i_!?_ zfg?l6MD@vyyU)jejYHTzCQCXGYft;#8d+WP)Xp;7VkNe7Q<<TrCTpzHv#3kLtD1TR zj&>;{kC7-=mKPHZj>u`GE$3TwmdMt;k{)<@S}RpwHdX2g0{ScN2_G0P=lOi3CA*%! z?RJK?phxeMGurCvr^*hw0y(A@CiYpqpUG*pe)G))DP{w=$N2G7$?6LiE>tHL`!VgB zEErP{acLZg@K&Kd&yF-)G#L9XWKhz^&Qn)k?}l?;*V$=MF>6{?QQ?Qv<6Lswu%pOr zQ23!Li{)x@jM6j2do?mVVCrjqPa{C3=eWS=cI(C=ZCzaog(747i-h}gb{4C6xN{&R z@$(I}G|!3h9e->ko<4tGb^G?(RGBdp9!0zlR$uD{-G23iRShIDUW)8C964{GlzW*b z-|S1IMi57wvNy6!a+drPbaI7C=eilNX<1oE#LVkXEl1&`93%-{%D8>^iY+kBgNF|r zHZUC$5~|L>F^LNFgI6eTqnJa#Qp<=lew9pC2{bIQ)6uoAdRKfp#OSr~Cstp+c(q_C z<tl*jm#V5Go=SZzA>rXF)Cc$PUqF0GT_6AT{%cj0eaGwK<(by$=UJU@SF21i)6>!( z-@ku<aN9%GV(}(aR3Zovq_12$t{56ds!V#v1EL6Nr@fn3ij29jlw;A7#Wy?JKIFlo zh)pOeQ7zitWZhm6f(r-M;>cRcjC%9t8P;cV(jJKMqGwdXPp7^r7V0&`Y6JJi9Lwg6 zeW*REWrwiLUy-9O_o(d9z<WIn2`LArx0ssQO6-xh#{A-<^bY%HGHw|v<Et0FSEeE; zRC9Cljk%>63$tT2RO(i&1wJ&hMfg+<GMp4Pj51i*C$Em6$~XSPio@OEy}CTOO(R>- z+uNJ^_M3?s*1~?Ww=(N;@)1T~R8}KL$E-&Y0f{JPL~;D`<%=5%XQJv6x#@7jo!hs6 z93Hj|4GVK<%d?YuTpEeGB-COlW@2o7SVBVEbCO}O*)$@$tjo~E#3b9(t?1T>w^vH_ zA;vp7s~4|axw14-!HswUd^VfDpU|SAuD+czIozB%$Slm1<23ZMZ?@ALE8z;VFf-Js zTJf!yA(oGi&ryQ22$i9Mmm@-R)o^HRtR^W*5Fg9LEvHLAp{3uR-fa1`vhvFL^N$yL zOJ82?^jbWKqaJ49b!ntSEx~YcD*H;=I%+R1vrJ^q5<{7lo13H`BYTwG1&u_-vuAlI zToSg&mb;?g=h$?X6nV^NOof;}ch;3;*}C<^rk!GGMMW=N+U)!mPW99e?zE&`v*u}N z=;_3UsuwmTm*~gEe?%Vl)z;Mf1V~v|Q={rRX~V+F`Sr&Sb%b=7{tb$nbkTt(0LC!# z{8!PM-)yTN5-w%#XXcVQi=*=PEtyyf^;G@hvs4g~R|{odZY6_C;U=uGW8w1N`T>0! z#~b1<_%6<l#iC|rH|i(K)y`$zSl5b7jStzf_w?^y%a1rfJVu<QXGdCNqyMZ%gYlIW z70F<oI-DBy2Db@s%)#=?Q|xP_6r@T@yYl1eV^uTb;_e|8UW|xKP-ypB93fZseF;mH zFA{9(aI9C(YPMWj7)ou9JWjhSmOlZcL_}Kp1<;gbTVDF7SZv4q+z)1<EI?MrkrozJ z+3D?}!Ujw({XIRj1_lPfVPS=RowEpuD~K`IfmbeR$j*$M5}P|xj{B~Y@LG~sT3R|} z`|Fs;)HiXi2^Sqf)*p#l%vkeN*RGL2l$CAa;(Ek!)Z$%dXXhnjW8<{T$@1|C^xppd zJ-od1`T6-E#rkf;K~(DaOsmaRoW#7bl0}}<>gG&SyDtZG4S@!lN<5{zySvX{zMSxA zOQ2@1wI1nRdBBbacKr_^*(h2v`<0*H=8f>!np(18k=-JXugAB`y2kI7isM6;7iTNL zGt&XuKn1%88xlDpEIckdMeNo(dc>~#)Pr5ptN}ZOKLPsb^hvXB+vbb&{~FNn-u?T> z3B@4p!d^h6-C&iVcqAVrg5c25J;K7w5C#;GPMLN|-KM2yGDMv`ASjrW;rUeDhKpdg zd}=X<z+g{h-E$gOo?_LzP&Oe404pgdD*CrBKis{0_gN*SQx%VP)y63A{8(PT8%*`# zPVu{`si{-9s%(yLCE3nT8WSo6zNhTHFTEXD7(q!OUsSKg6x_dek3cNvp(cPgYt4t5 zB3IM`^b_wTCdLXxbOsE43n%9T<UO{#G>HxViCU?|)dK}f07G0<Q?o<K;NO`>yzMq# zm5*n*J#Qn3t|G&7><hS+?E12!*uBgs{nz4H>FmA87LXb+{Ybl>Pt_JpX}bxw`|Fn> zK{d(bwYa0|^b<IrkP!$OB`nO(VW7IJE#HCoFdX;?Wq!<iMMdim&P+fhcq-#2!g}!X zZNOpXy{8|1pHuIt=ieDoKyGp#>)7SJJY+D@6DZ#eu$)ZwW#!=T-+l6~;jec$e|Hp1 zM@2=g4BZs@M_vKOCL|G8R|!Olm;GZ-CVHp@cT!7NI0y~`P%GeB8l&>cKQB*0X8CV@ zQ@#T)f?~i)-U!&X4D!w|TZ!+9TEf7@?+&h{0Drv(lR%lH2bZ}sH#fIBN7rR5@ffmD zrfE(0hdT@h4jecJ`kSI(ys@x-GzqfLS~|Mrx4^UDRkQ<vhNn)gMZe*Dj+G80(1}}0 zD53^p#ZEEHce$Nj0f>UvX=&fDrYx+8;~LN4z<{aVPD)Br>?}e4u+HmR*Jl6a;P3ia zX57@virKK0%}YaeEx2@mOaX#lp?riC2ovC{z<I=9eq|!ib^Ja3VV6<eht%?`Akb?_ zLb`d8)#F>ijIqA&u#@Q?^Y)IzO<T&#%dIDJFA1^|e|aV4bb`=J5IJNrndi`<@g1xB zO(V{@afynUqt}0)LaGNXT=n)+71A%d$L%#o1K{&<hk?gUWFf8Q5@G!!w%m>z0;737 zOoBQ&jMslA)&8@a>=6sUBA8oN!mH1zs``~19ry5%vA4J9pZ+xs`i$blP24u5xPjwe zK7T%@sJIby?Iv<@H{=!x_ZdNi(FI*y#>9rfqUWp#WNgT5ls7X}ZioVe#N#;H#-44_ zV9)guf{+pTkaotk4G<;xt+>m|%Iv_5iL3-Hc-q-Hr*Y}t9f*Dc0u0d6h{YvXSf5ru zA^9Mw5!*gKHRTZQfCU0J=9w98_C+mt8y&qH+}E`F<;^Q>LW>#x{{AOWZy!H>dJoWv z5Seh?pd!lW+l#r+SbF@eJ+q#f+2w^mVd>9ym(GVEgd|`-n$i4$aK(1#0M>(t%<ISx zIF44inSQRQpbrz$`%vP!_>azZ?HUgbD6sJ{h=tHspy@zBIREDKrXQ&W+(dTO)#Yr- zGWW$NLu-@{tS96Q!}n_h^^5ZAMo-bNTW3@gE_*K^;3PKH?(gpl4@1lMLWyG}V&LAE zz2mc`t9rYPsNY_Q_W)&;p}zQGc?ueA%Aynk4q3P5@h?gvZ{G&5*+M7+3xEIkN;wTK zk!27Rgld8O13l_NW_7r104OgqqEzDBw;v^&X0dj6{UGe@h5Q9{OI!qYoX|3N?HXxg zqF8nmv7ZYSd{5nX4kFsceLJ2bD=?zkWPwMv7}(Z<DOSXmN;eTOkkH~Fu--BL5~|Tc zGu)WU9e!hw&vEGICenFb-3Oq{SCR0Virhr)9US!Rr<1`ye&f4NKVZ9w^G!>tj*t%o zj$pSbU3QM9YlFx^NIrmPCoW#3eo;B)!pg>W4|qE2O4;4KzEGV6%a#ieR#7SM9=`f1 z5-hwrQC}-X_kE1=i<eqT%s?#075fOe4!S24i`rOKZpYu>X=-Gq9-L7%u&H~y0U7m4 zL`2~2+qV_n1qs2`6^!|?$DFOUAZu_)NEgy*1#xb0Ni#0(#+#s4p>#me@n+<bVN1T8 zy@rJP*d3y!|Gw3xbW>rw^@5x;K0?}g_}Jyk95{tzIoCJcTM|bmITj)3`5l))s3St= z^+pJSTXZ~^thmSKG<;8Sb0cbr+&edznA*mll%!wG0S)Jqo=f|kedj{eTby5rSq&CN zUbN$FKnOyBb)OwACt}Ha)oZvlml^9MV)arxR%I6<bwLyR;6p?EJ<D8;bj-_3uD|+K z0FFEZLO0>ZRT2B%vx0gB+s}mwl>=_aPsD$U)ew<e{wAQhiCgX^Ip3(<Ur~o5uz&xj zd9MRyhvt@NI~_jW+rr4iB<9(=OUm)rEjkA6%a;|)4n2MLtP&zza-G(e7e}v$Y9&2~ z-XjK}giX?@oY}i~@BH6-RZ(8v3b&G1vhJZaCG-1n<s&~6H6TU5sI9H#@?657&QX!h z4WliEL0p83|8D(<;r&7}nE!r~IUS;Xj8!HA29mklIYmX#Vbzxs?-BCp7iU~Rnr}E! ztKM9P{zb0*`0-R&_9Z|M>f0-9+Y3e(uTRv>Iu7*rXMk{|r>Do1>YL4tcM)I<`1s}3 zTS$ry*oq>M6ZS1zE<`Wa7Q4GtzYq_+bLS3_I+m>aEhUJ5Iz&`XPOc658pv>K_Vrj| z)k5U3YA%+LdIGOjJbG`Dy+=-tYkqz{X1^CCRzGepHk6>#XV0!LneX4Z)F<p6PxZ^f zq8zqrIieIU!;WGIU2oIMT!nl$Hb2I?v9WOnRL<jIchJvu`|7#ALTQvydMU95kWW2Y z_%tiJA*lP?y_b5pw{UQ5eDUpWjocz5veXCEsv#DaFNv425EFf22HjtTOFtqE`1_dp zA$M-xvBU4{S0$wgxm{qNNdXlbul(B!kR>e!{84c=Q1-4L*NydFUS0$;;&SWVGO%}> z$@uJS#Z6lJ?@<a21TF(KlA8GV=B1>=IzlvmbNZp~44XRQ(-!FqeHT_yldtD_X{}vi zXAJi3+jj+ch>#@#e)=cbg`Ea}y#IKA+r%$lW~oN&%IfM*lYL*(Et^Gh-C`yU(D*Q{ zdrNsLV!Y9!G36lv)_%lYIIFCj99r5*puvSPFSR}T=|*%EsN7v4lUsiiT8Nthp+8&O zHM~Y<(#^JD0Vjdb*PLr(P@mh3x&yw(CFhaXQqt)RWrbWxWT`=C@Cym-#J{Ar{=Pmt z2$c}LOGY258-W9g?%nGv_TnLwv=|#3bU6eM9t2AtfWZG}U_i@wk!$D9FUZAphZsj& zvICT#A35ygF6%x+rXVX{7znTGNq}%lW@lsjogoH%bA#FoF(XoL=J9hmPbtbI(uUoi z!qQIHo=vPQEKnt&#ieMc-|}4eJMq+O12gjgLgJFXesxsTo=04=1$8;apqA8Yxz_Ff zs4y8rjjO7!q+Rw?tUF7JFUD|jOWNON^7Cb26^sk!t0>J`$ISKh)~z+5Hq}oLm;D_n z274!0p5bzP+w$u1h7B781q6Dqul&>6ATnWp{`^6>qm=zZ7<@vN_dKqCT=wtxljKU& zm9oE9vh%$`<Vy53K9!f}D|5@N%=HKg3lIFMk8K7dR?E%4R=Jhh`}xUUr<Hh_m=7O5 zoTcIj30b)`rClLcqJ@$WAsYu4egd?!URiuO#TmV=&!x*FHq~dUk^O5-BRoSlaU2<M zDlu<N*)=se$v=G|hlY0DV=^*CB5~eExh=)5+s;ylYv1_Ad+Q?Tp9Te$0q1wP4ZN~$ ze?k!3f5~M#1howZ^&-;J4w;ym{zJWXil>P2UbVG7gi7%Z4WS&6hl@FAuPB!Q)8f{# z)xsrnd&)k1_*;HnfrW#k3Y-q2X2_E#PhzZxo|%U4ri^wJw??~o=xQLtMm1RUf!(lk zbKA5yLu({>D$duswQGONsJopyYSZzO{Ork-t~zI4m6vC!9w22uYPi(#ZbkNe8*zJH zYU`5;wbx@pfpy0Y>4;aJzhC>cO`25M#AEqKo6>#B^GH)KN@T&4!lhjvftNLOr$j-9 zmT2k#kt0_MmoC-)kO#mt`C45a1HB4hLN-d&)59YV;1PKkfbcsgU6$2DPDv^`|5_#0 z!a>9fkcV7}?5b5YL#0xmK6!E+`YVo(;<K3q`#`#fz~72gB?`rEXvGXFTC%19<VPi0 zc>~XB4Qg*0vwYIj`MxcL-c9XA4@0+QG-7qhl-g^sGPz?q(@z7n?zgSP+&A&g?-dmT zJLDHcjH|Zy4-C{pdXsdx3v%q8UHmy0Z5?Vaj+1idPh^v`)Ihm~ID+dIn5IonOmsoZ zLyFcd*w|I71&Cf>UvHk<+MMrT8aVU=3Skgp9SlkAV4LR8^thygk(}1ERPWWrP61<g zu%ovP7SY%t&)N1^;Wgs<dv2^OxnY?zvF$NdreG$}I%IDA{VmM3q;8C+LBqUm@g=S6 zd-v?oK7allcxDFRj1;$qwSkG=HE*zH3KdXSQ{LTBgR>Oc=F$%3Fj=pqJO{citlZ%P z2jW_0YjMfuZ0k^rEe4$d`%Y42?0fJ1zqhpO-vWJ1$28<wVcZ-4^l=xh#_OrYr>VMm zwy(`w31D-U8sWW?e<tEKQe_wDom<xjy874%NMt1|3q#e7M-f@N25YP@2JKhgLn)d5 zsS_iYX`rqB8TH)lM{qdyHHa)f-@C0oXJTopMyn;nBV=&)=hMSimF6EpDdnTsqnHnx zG7AFAaUo|o7rw&F^MR|%j*drg)P`Pm6LFV`PNaVQ83L}aFg;%$9tWwV)cvS1hrGJn zZ&>KHe1m#qS~h?sAb)8()q8rbI(hCU_Aw@&VZZA_l>^K25sM!O)N;3N-uw<F>H&m0 zK(QO)-yc>PrH`XIiR@ttl~T#Q-xT5j{<hjo6DX}!uK0J`ex*av%b*YGP^6(f=-V}( z=xd(-yf-k<W1lXmE$s>|W%BM$>+|yNW(sG{WFpV<s)iFnpSQ?}D*!?DfEgjOBiqyo zESiBIlPjV8YE<oVRDDJBdcyoDQx32I5dn7Hx6SKkaSF7NX?rRHwFViYza@d4Agwd8 z9eNi$17LoRO5lZ~uZF#q9P~=PWB~zIXL3vb_>SF?&j^%Xk)TXAXc<g5mCH{~PC`ol z2n=emIcjoH<oezBhzUx@W#H;>M~yz-izo_>2G6dhlgrG^RNfinc5!*GCy;DDC?yuc z5_uF$J7{=)=HxHdfIEPZkr4QR1rn6$3Ahv{Y+&N$RbuX2i^BMrylv}NnFO0PYu309 z{@_FLP>a=FyLPQ@+1*XJF^|Fc*uSq`${=s-qGTA9dd29y7Zwughg>6jBjj8rH+}pA zhNt`?0)xe~9eXJqXh;cJ%|an0SH{I1z#(n~rFMg)VQL2D$D{w5>5;vC5e>jb)Lz`3 z(k@zQP9_{__a8R?NJuhG$a~`;+t4?Y)M6j;d4I<Ho}&_QH&KswcCaA;$CXgs__&8b z;;CeGLr(?{hWSgI2^WpuidWMmLYAmi;j%j1uHvu6`fVj#CwnRNUUQ)bbxu=@dLBv3 zl$7EOT&FIzk6mBNU+4}HK1+pa)Hok+-wGjsg<_Ab7P4wI$$auQ-sb3e4gG&9ZRpgd z<Nv`R??mW$)L!U%*IUG7>{xIAbLr2QKTP^JoCmU0(%Y2HKZFEFrl@I3Fsxs1sG`D@ zteIF*bgBrYKu}QdnzeOGd}7)^$4>a{+Xc^~;E>cKBNoONFKz|wKvOS4!5bciN4Q^v zj%eSBW2IipXQ?n3)Dzd)0t!SCk(6vUwz})*7ep2|C`pn_IqlT*P~2i&Rm~4br^l$! zky6ZCwM#rCDU*=f8o|%iX4mJS;O(K*Yx1Q$XgHr(fM)i4wCDj}(r|4;HmiSPBlc6O zpCA3Qci}49Sma9gvEs%ot2XQ{xe{dbx9{jDr|yp%sMjnlllVqb^$J7Di4CF}CQREs zJUocS#`>Q=b7qKBBi|U^G%8sq+oCT+Oef3iI92J~IW_LYq9`aOW|_^dFtF5{@X1Vl z6(v`)i<+2uButn$(CY-0e?S8ZI&NFA`DftBuV24jyL9Q9c}--&Igo2lawS|O`9&iL zp}H>HLy(t7QkBF|DpA|eL5@U6nXmPCTfQh5fa)u$Xg*_W-9~-)gA|c{`^tl7dU|@0 zUm@sfCod#Jmmyc;q&}}(K?OWZRh3`Ps#Xip`H8Abp~4>`bUhQ@b#f&@T0)@4^GCx` zB0~+j91#g#YH7+UDgaI$Ma{wTkw$$5XisV`R_AC7q9h!E7C-MNzx2Lu#J%eJMpi-X zW7ML>(L&`y>G1Gy6_oj>PuV;_x99Q4bSphSQW-qc>AmVn?M1ggQLobzrGi{3=edwq zG=lF#4gUMr@l`B;?$W`7NO*2;`R6(#4QIM7`9q|CG6)wPqk2HBS2phq5@Iv=7^HhY zgC-)GqVhuQTd@4E#MBZIr`_9K5~U&6@Sgi#NK_>S>JoBB@q$GY4xI9`(Z&3fjLb|5 z6?&wzTPqT_5!&o%wf5Eu>|WK~#4d81JP&Eu?W^bm9QXuOKyoGe_%B3c$8kv2<P(cx z)-kdjqv{qqC-aSnU;p`l?1q$*TB-xowR3IjNk671Z}}1{Ayd^^=c0Wc2>C?6whM%a zST1Bk^hrnRa(sP#FQIk<T&Z!puF6iMS4}0ORcolYDBkY4jbh*P>EVKHp&J^PPssW1 zv(~bOt2@Uo8v~&c0mDGskv4O)N;DB>1#;!yGmrAJ+JP>E$f$>I)0tJ*6OhBnm5_MU zT2j?wnJAOEed~5+j))t_(~>W|S%(W@*tk*2&AMKPUIn?Fmr?>lhLDYWC3PRU5>4cS zK8+c4N1^nGLsAm5kw0=I80pmr;tl9)40G;_u;#?wV+8U_Y;aFsEe^*g{{vC<I-Egt z2;vzbmprA>r)m6iQT+ddLtdJ0%5-bj68#I!#D-|KMFFA(N4|9NV)xI?V@KqY_wQJq zFo0X=J%~Rr8qWr;of5V@q+e4t@_yo%P?TYoIgD}%mvmm%2-Ff<(p^UOZs*12ceKnr zP%*}erkE_nUVLedIDB;-I$dbeTEcF0ysZ@sk3<59yz`|MJ+ysNE~5|7-WzVoPHdU! z0#IQj<qf42>UPW^^`rame8jqq4M!?jMcZyC05cs4P2Sq*k<<UyAXQjXFKBAs#W9Au z_<f$;c3)z{M!&L~kdC2?<POuqBoG#%Tnw~!fMSm}Sd8v&ej%Zl28-m-n$qRe|7kBf znHQoHg@Qn&&11)WT8C4imI6s4e<-;%S_8j8MW_-rt$u2st=zYe_y#ExooI1mvCrF7 zWsXxlAi*Vg8jN<9Mv&ns`8}EQZE4f_c(3cvrtjXwr9UArP7lRm?KPe)w-kfaJ|;uV z{NucsG7%rvo=)cjHkK!&?DD6M4r(`eE4|{mbH$?;A0VBPNMP)^LWup~C$z|=HzDd3 zd|T;2Z|0uA{|A2-0cglWlQR+SqmmGeuRvLg(Y4yvSOB+<VY>D>(%CbSo!3xtNIrns z>Wd`=^CbO(PsPct73rRq)CQ0qvota>F#$gz9Yrl6GLi(4GPO{nQy-%YXQAO``3MQS zHLqX44#|-(xGK<n8CoXEuw@{xTP67ln|1COIzRFn_H?HIV-XqApvxT1f+FyQJYOw6 zmiMg$bn^+h`OO(-HC8!WKpN-ar>&)BTGN3y(2PDyg+U?^q47PE22EuZl}B2Cjg5@< zQ0$=+#AJCd{57XuLuf0RucCDy^9(1(J$1Fnb8#d$W;(Uq+7to^zmvDV`^ZshZ^X)9 z-msh(At4G>%euGsOJX(jHDIP7Q}i9a9gWGd$!(?79o*sHF!$peYaqOndnv4}tj{yL zP!6eNdPcTi*{^JVZhQcJlT6`~_iD2WJ?|pHiM)TP&$rlh!id@n!7G|M%TN8r4Jpd= zNiK2K8|+2Aw^c=jPJFDWAaEW%GuII(3r#2w1nLP54tDLkwF?Qu7@c}iQBh?*K6x>* zP&Cy0?r-B|<KVDZ@On1=%HZO~6I8~H8|!AXsuBl*Y{-8mbDc;iH{6trq@=GSGdewL zXxjlK?4xi=Iere_WP0t|WAY1en^9b|3HJ-nu)fA01i!&5fa`?i?%KAEV4g9tu`e>7 zM^sH~lzO2Cz<`OBd=n_QheB{t{rXr!N~YMOiz{Tah*Hi=A-n>?(%EQ%CB%EyXPT;_ zMBsDX+D)wxG$5iVX<}A8kz(7>k%;cdKiYGt>HGKd)Lx{8Y1!n-0+Fd#lZZGhd%k`7 zzb~C-Ob3RRRHaKZEr%GFeMmC!l~P2cqzYQ}_d#Kgy22KtG<IWox)Iio7^Paj=97bn z)O{2}yp73<2nsq$jS*bal>(5up4wX%eNOpVi*j9Xd^_60xG1O+hqJx;OL%o<of=*Z zy{G3UQ%azj#aPF7r$>Rh=hV$u0i=>E(Ps_IX5Y0-nTktzOT>s4fa`t=(9R2yH@;*@ zcU{hl$rJHA=vo0#!pM@|D;{AsS<v^$l`xO~zH~Au{3xfmH78}#msu{ZZu#85YjvNM zA1qMtQzD}{ehHaTU(Nq|c}r3EMm`Gm!CfQbIlCOqIO;ID5}2_ds~zfa2Kuh(1zb6G z>bCjvHnfXz?rTjl4+{yUv_vq21t39z1*|=J;)GJG3ZmUCx77`OHbqb8QIHh!pSnMN z9AR-q*%0<YYPBz3G^%oJ<C4Acm<%oAw<hkyd^#yYk0l>8kmQ4|ecom8C=!pT=(dhg z<lnU<T^NC&gJ5?_KE1uY{OzTLagmf}-=`RsD~lHWZ9l&r#LNj8XFiHLB3+Tvu2wLG z<$AU|HPVp4V!AavpQE7#BymbX0qw${S4(2int}c=0g|;I%}>!}ZzQ+F@XrwD!yr{T zyH*#zf?I)s%tW6UCWJOH;RAephmEC?ZRUU<&?Gx_?ek^{&PR%^XGArHfBJv!PDcL< zx$SXis7aO1MpzWrkR&`8vUEmr0hEKH`Bgrm1tdX#bz@FHBO3@gVU9*uFcKbEjT~>_ z1Ud@gIz!1_nwuc`pp|kg;u>>ZiKqMHkKjS5qEN3$B!rZHV=4~UI+Ej9M|+>u3%A$9 zxaRjry0)!WxgeCLs}|7OUAyk=cnnJ}5T<(T)UPLJxZcB4=i6xD-Ts3?hES6)XPMok z1nu9wcki3J8OX=$ad$|zPUdD>X)HGI&Iyp-fe`~=>G>w(CK|nqLJI%!C~OjM`!(76 zk!VX(?2+6HteD0T_T)-1iTtc~bhjUon;|gpH>bjsM<wIR2PboYKq*utp&ydH$Bk$F z;RPPsPeEg<c4%SdCOsDq1)_Z88`gp{`B<yIe^lr1KhSMlUe34al!FYJ14P>LiWbd- zD9AMy776hJi<&aLpa=_!ofWVi2a!Px^;$*|4~o>6qNa~Z5|L$1O1&KZ)J2mk;Xugy zCU@Oq@Q&J(>p$XXNO?D=6TSpFqU%Tc1;MZ&i3DwfmgIx3D((W;M@ve{?|+WFKu4BD z(oEGKnartpz)nljE^<v*;bE>rE0OdL#ZR}x84Z=KTeli!HWMED)FB;F`7xNV4+sgJ zhQ7Ob>(=hcnE-$PLyo`CqiOOBmv{^PZ$8g!xvfOxvE99?DmT9t#@>ehIXDcKmdCvP zQd5O-SM-Su7FEt@1djt0c0=;bgUv+1Q~p~)W`cB1ck+#y;SHoYR3IhuQXEi{50YR3 zai5nxmo3vaF)^(h4>S$ZO-3t#<O9;Pi-zRK%)O3;s!*8Kjyg{wfx{<UE440}Hz5(7 zcHNGgXEmqqxe*pwQjF3`YdG1#m2G=JZ$W1)b*L2_Ix;DV5nU+<H$zcIqN8#LcjNH5 z+XC_F+83flSlD4h{gCA)<@kGZxYvStmRao@1dK<v<O=!*X9}H14w+VSs)ZZSuS_hB zLh#3E!}<qohocm|%5dBnNO`UkQMZymk8R(&^%kNiDld->T8D$%A~EHF-XMzPlhDw9 zv48U6x>o<hNfSYtE!(%RCB^7nm^lJfV=W0id>~=8gVvDHMiuakfNn~(GNHBqWN*{k z$H%t;jTFMG4i}T-8n?$NV{1t8Ky^>%2naFeFL+FC2fdPT9%frZOIr(9Kv=E;yXY~K zuTO8Hp=JbV@%u-7ka?>c?l}$p8=0l?vOE}B6UzrI&{UOxJqZWgxW$>UZy->+&=4Zr z!fN{#6AT5qrI5mo!N!e|f!i4wB4N4S-;OrEtEi}$U+iLnovF_7djBpRy4DEvCAX6z zK>&rAzoLZ&VLhZ|<8Nj0_O&GKQm^7Ktz2T3Y@}cHs`3q$Jy)Qg(f;CA(~;#n;_mOy z*966ytHGHLNEAX;S(mLLQ2qK%n~qvZBVg{pDURgvveYH~b4?91u;5zC19s6*!SDG< zOI^&~?;uPOLmOys#8u5`sXbB9jqSF(h2ENLoA&u0wF_xZYAgcf8cCc3{KQ(}O0iaY zT+dg-aKkhtLUur|Hhf1Sy+cdzbx?&bv=-uCppH}rNN&st-zN9%#<lLw=-Ak+Rl$5_ zfZ_ybs?Tu%<5qehwh0Y__iz=DrdKS*$A+K4ff@%he>ORMqudk_H5$F_vS06guVgkS zSb95EXns5js(r|^=@4cJUa)?I^NgAFPkYd$^r&3&%1TedMYLDQ=2cbx^h}&Ql>KC~ z8J(~XLV;WfrLv%C1nMxA>;^unH7JL%mM3Jip7dI*f%eW)V^t%5=J#ANo>9CBZvwdz zS=`l%o0(JMF*)Dl8wc<W2L~E_t}tCFHi!9#%+qh;xYi;DonUSxw-ekw4ILLQmm;_h zYXE~r+Y7@$_o1wU5RfZT_KK=z=WV<fcTy%{<aIGGL@$6`2|eD^03rg>TB7y}q!t+| zE&{ymqrk;h(BOr%7M-|fac*vD@AUKWjDG(e`7g33qhsUqCUx!hwS@3@oYR~Ly2 z7$%GY$W20}3nP!}FZYI-H)ljosXR+W`|UNcEv+LlZJTDcvv}&%Hm0bf1r2SUa0f|A zwfyyDm$WBu+_-TZm-Ytx+ppWO@37aBE8(JV&M>adrEy(@l9{BP{y{RifZ(Phe+L^F zfKbXIcjL&v<nOc*9c@~-Ze0}kILuN9`1$L?ven%&pYv48iC+;?(u;Hv5IWL3)Rgvr zZJC!?lcv&fv7Y8P{(PTV)TqUJ<;?Nyz6qElA|11|w2U56g|CW+gu)0O4|#)*WZ9H< zocEDmyf$aDQTh=r|3{DR0<(&UioV)WU3B5}>2>hWU}i(vEu}<6I9RX974_l4F*sD@ zAg|Tu1Yz_B=B7yKL+I#*S8xuQhP$l;{{9HXM9IBa19d3PtagufvL++994L5uX(+qe z-J_c>6@3HvsZG0bvIwXW=8mK<t+Nvo?{9C|hS3$68$ENIZ3wp{i=_ai{1$hLm-3nN z9hwL&ek+3%G`mRepo{*#U=@(hA3i14^C;oj>*gRN-fO0&dwF<B*mNhiMf99V1b$Gj zS|J8a#!6S^i2N-x_sbWN)b-(xcA@h@Ebtw)sS1|ufXB9RdH%gH+?HSeqc9Gr=Oj3! zEhNUCug^rS)5lEO(lt=^FT(Hp_32?+H#fH!Pj6!90P~vi?B3`s3tjg}FibSmq42Zz ztY>6&G%tj^inNkm<Yt@?izSJK?yH@7A-*3R@B~;0+zL*0u56-Zgj7vB_GO3`gGFme zYB3C2<&2MU(DuTgf`gXfpkXE2289b5e-Ep${;)@5f%Ha3#*fHKhA5A4FxQ(LXoG(v z4?^ZRq&jrjS*$ZxF?L#714xUckHy{pRBXD$sP8Yj^<R=_^m^3jbkuH*pbJ1l0*U&$ zWiHl#;Gv%E+4y1U9CVT}wety$PCYIW$D>~}HP$Bk|LRj@ap47oC@zT*kaJ<V(iy_P z_~_txAj4~z$!~&yhYDWmp1gFB1yc1m#Dz%6{4pw?E5-VlI>5l)RmkTk6;JtEiNQI- zIRL4s2UXiSahXtE&hC+yH+Zkvt91iF&klT|2W_4sR(&1BTnXV>K$%O!WI=AT3lSg6 z3^^KhJ8Ii8igNSq7lWH{D$<u7IuEimaLdpH=VT2DqH{%`l?$vvq%?;Cl~;$j;$T@L z8CC_KrfaR*ki+8ADll526$+*IDp9L2H4yIB&t9K1RmmG+h|I|bDdqGd&Ogo-Vv>^V z$bFxH{>MM<w0SCeAWeI`_6+xKK|x07;$>h^?Ix?&8xrVnyfOPz9vxuJ*W@qGcF2$v z?%KTpstE()HqX5EnXJ1Qi7*9PXRktFa!X6j<FNP?EC}oK;v0)}ZCi9@!i1|Y=<7ei z`Vd2e$dpsRg&zT-(2xMWqJut_A>X`4_!1C}Pc4Gqg#0vp{oUBZL&Z%dxyz+R;~yA^ zs?CMD0(7OzvPPgLZa_S`BBHmju=I&l9L2aAEN6ZV7Ug+%J%(&|`C8qe77`YPA{1z$ zh?H6PKf4e?-+=kjEgJYa<-ItuPU0haKZvSKI02w$8=~=|zs>TfoD;W~#$lfeY0L5c zaw)$Zv<e;nY=teb^ODrje|rIZfM9z2`koaCgNv;tVQ{H2dIaJ=&+gqcVlTdBu^d~~ zGc!9t3|3_rpF_axm6GBhoK9%bp<ta))I3NGmf?&82O<lDbIem%SXsN#=)=)D1=~K- z*AvuYu$f%#D_I%p9zO--7E?6090PV9nC|3d@iaVrpzy{tKT`B&_)^hajY>;PtD6ZR z-(}k64`uJ_M0fdF_%V+kzxgHC0bL5Er-x`D$FU%|Z^1fOSZ?PzlHK?{&+aOG7R~cX zne4Qs(7$>h0=ahI=WQEp6BF>^Z&Gv;!@(5PP9vcno`y?E&+AIuiSy?-cX-a~VY-tz z(AJHF!dUUo*aKWWBpx9ll}-r~MyVJ`5@_%7jc75hz(FfJ6R;O+gfC)Khn)-gyxmWn zSVJU3keppG_QR(-uaT-WF+Ht-kHBJiT{za1eSHVa(4$F%GI1i(O=4!>Nu(?@-^%x_ za~0~7<Kwo3TnDFH@()jG&xIpU#JB{Py@y}9II3&R&bn-+KHki?`!>_-^=E%8Z+W}^ z;#$5ao{QVJkJI1U!|Hl!%VYiRYvWl9{;ofJ<}p9{n9t@L%(uyJH`kenxX6uhOHH-V z<(rBG<+~@3U9P!tZ?Vmxzs;d^aX7~#-vd)3br6;I^}sl<&|ecFjJP7eP$k?y_J75# zekMJ`7@7g>p9kS`(G<B`T3QM}p%Up&Q~H~Xl04?UcPoBwJ~?V2BP-hn&u$Qb7{LJE zqOd8xd5&|jFN9x%3OB64A1#}4HQxxi;49a^_-6K%|KS6Qi86n#o_tvYKOJ&MJ>Ng> zMzbX#{+>Ohy}a?kFmVD8J^^O`6aLg7`SQ^%TkiY&*D1#W!Dm@CC<3ta)X2`h+>YXM z>Z6w$rVjVR<7SU0@FFqHnoH*6qu}iz$to!A4|@8|1XdJQ8ylO6+1b@ylLIxv=m><O z4bP{OleBD-jAUJhfn@WJqI}s|$vt~cz$&sAR4#kRpUQ(#b#DfHdiFw6HWGO@eCJQw zCG|4^?H|vYnVCIe!(%Q4G?N}9EmpyhBM96_Wf9Okz-|iNaS}H5&!}C-Fv%$ThqsUA z7Z{aqq^PQfp@DFqkOIh@pq`?839S2CsfY89vYF$5*U{6TJA3wCFrV6KND{*bbo0`d zy$8O8sbZRRWPD;`3);G<OMy?7_E%O_Q2~4KTgK`b9Ca9r3vDZMQ$q*9xB`w0vYcE; zS{<VsPrPn^29gy8GmOS4tCMx-g!vME1ozYd01#sdeK<EFPJ`;PI?TQi1v}*XQorNy zlMuMooy*_Ke&KABWM-PKD*i3p`iNVe=@?YbklzOI>5!0m)T9DoGo&R(oZFpL;d}DI zv6_AD)R3$b2J6BTI5UypEV84_IZ)G3xqSh#pMWF^=p|yKpNrd6!-2ekfuRSJZ!@Me zgh3g;*4+yJ+bdbzJqQIBKXlTi9gQFQU;W=+SbK-wTd%LLZ}uEMQZX(ru7aUeG;nEL zryH~!EFaNr+|GjmH!KK%`Wwrapf!=^9N?3h8KKM>9m@;TYGS9s?MQPI72L0G*p$K` zLPBn)XcfarP8WGGTJhd`AU&|bTQFU{fNkU!dM{g9SQL;TBzNc9bee$WDLoUpgLdFW zxIv4GiXKc=zl-=aFi=6T#L8=XVDCpCwENGWc*n1ZF1x9IWw=YuA+f!(*JJb=)Li<T zy80UbLW1i}zw#ZX>}Vqq@7A8{Sq@&_u3Ufb;X{qnFHxarF#t>(Tn+N3PxA|t6194> zFdC7L;SyHsy~nz`2s>F*sdwoz-M7!5c?1O?fb2_^GoUrBw;zLa&@6{*2qzx~#NsbT z`=1+|!qh7*Q8)jj6haLly_9jQ;}I*}1E%SN(?6Kv4wDwC2+JZVb>>BFzG)3t^hZqm znUjd=5vGW%@Y|A_3Y-!%4&U<iy&n+J1Ad_5{UnC>=F&lM*ncvlot>Sxxo%5!Z&Q;t zocSLS6BR(E#PlVbjO!s_DiJ~@K|RF@c!s0sze89BG!qHd)!n@Zw}r7PKJ7Ff?0PI} zIT3%rtbV|ggg+cE;cA>L#MdUsHDocd8JD+p`@!rH=ZDR{^AsMpepf7f1gf;5_z94f zlfLUV1qTj|jC{lD;AsFd(?8Ty3gy<xI|+C#%rbb6b;ur3-fK|eQNRorpaBWPf4_hF zJyBE*-2^?A#t^4jaX<uP3M2v@w>#lG*?pj0(XZG@JN`bVt{%K>3^&Mn$PVf!7N$=C zF0e~GCoS(aPS<YAGT#Qbhh3$o9NIdhm9f<oRhM>P<m{k}zQ2}k0b$UdPd8F%cPd36 zl7x~bSusGg^!TJ5EI+>x7e>0oarg6jhwoHH(ZOv73tqa|ECK8H+DJ_Ms+6W`oMM1a zd%z`p%ZrHu^nqaVsRC+nBc?=$(<?wfzdUiHr>93tw`Lrj1%emgEI(?tTzU20eWc|m zYJe*6_5;!H56?#)qd_UI!qTT-PKI}tz_-XhA%P=*{#3$j`2C1-Wp4Yg*md#^4R}@s z&Mo~hkON2VJjk0fWlgV`qfy&PgFllKEgwLiqdf%MZL|Y1^hx82BIj7TB}-fIsZtF6 z<X1QV2~E7kpa?x5f|7)_a6=t0f*a<goF_+OgCY(&JQdNvWI{&+A>1+fAlnY66yilv zl3w9Y9;wo9LKIV+DXe-iwrVd%%xMHwo`Uuh@=y(I0qs*sr@`Q|6UVGBD5n-p`ez*O zfG_V~w7;nl{#{Ze%2t6skDzYeV+d*AQ4ElMb&U?9R;a@8^HkDdKX~E%t0(S%>h__y zDdgMtJ(xPQ1IWM^BQI3IbO*!`rY%e|pGi9OpU*P8;3r##7G~{{hgbpW<>%~6Ka%JE zbguSbwvg!^J|>va3-h}qeyx<@P``Qzq#NE5DykUc-&`R7b>G_)Cw{*PTw@C({o+g- zdP22cZ+5Y=o`&qHw{mi3IJ0Ie;8TOeK1s=EgwwC)RV@QtB_zV@TrlK?Y^dk|QhE&` z#6}|8@DhT72GJO#_BC5EgdZ`5R%6JGAC?2ZaSu@*DtKH2y&;fv)u%Y!d=c<BUD#nN zWS%hlL;QvG-V?ZUY~DbELEn4X3CO@|Rz@dT6B^P~#7Xid3FgWEZ|9I3o}%YB_Mslb zL{G)6o}Uyxj3Q3}?&mQR@X_RdT=@4&T*a^!2_v6RsP75M@*UiT?URw0@tGu`Q+26o zyg<VyYVx4Y4$sg45AXf<LQAU{sffl9b!>GZ7jiJHRhXtxymsv^)y((h?bujeAQ@gb zb<xSkSwEne^t4`n7C3|^jxc`~U|?;{J8XgV=17Cr8HT#JT^b47Uq1C;8*}I}>dp|| z(FMur$*Wh&NKnBK)#A?YMpC0FDXGs`ySuw@<Kj}m_(Gl8?qWNz1QNe`oMF+xs*inN z7182#cTK>K076JM9*T^34OR67@-v|tAdEg-6KVE72Nwk{%oPZh(~GYUHKQf_dhHSA zKW^6vn8bhB5^K1TNGa6!8av|bO$aY0iBrn)?7TM7ZX&@ybzbZ=rq5_lBpUQ)SC>0i zX%1nm*Lw-Jt%WNh&(5l<4nW1LY0%iqz`{?c0iUa@_X7;w=l!7(B`UY@doSs9AeYtS zD1*Z=ARC7`YIyHh5g>N*Je|xaJt7RmHvl#{5P>(>9)OWEM~iwY1G&aLHd#Hm3+ zGzZQ{`b>m(@}iUQ0X4}`+#e$&L^*npZI|{Mg<XH+_5;UY%8XVF!P7v3QM;$`E{D;V zfM{F+S}ciLj}ZoM{>!1^;nm=EzdK9iQF|prhnCSie`C%8ub<<yY4N%E)`@!W6<-9i zQTFAKka5jt6+>SE(AT3QzkA9H_Dd2LIU(aPLG(zNQ;&Oa`yt!mZX0<HOllw1Obmg( zlkcHj;TwrgPFsN!gL1v2&CS=mMn*=Y0~exhj}~ZXC^{L(=>}mUVvTLjr%kbYg&{$G z{Pc<cTToW^%V%<)1)~MvRBPU0cr8TM8-52IZp2ETHp83MTj+<83}G{MS(1-LS%c)! z!4*@4W<+#yhCM@yZhm)Kj!NnDXZ-@l`{?fxGCRoGv2YnTd&gY_<ppjd=Gf4Svy1Qi z{wvnHLUnbX83q;7JD3P#dTI3GB_(O5=>8FtpFzT-Aw-{(pB!#qS;VT+q`?!~?&OWu zF6r-R`=ZUsL1ZJarjRea{(n3J3P8T`0--)t6}7@<L4scH*eHAbryyw^6Q|kcbOR!O zNl0$dg`)swBn(izvhKh{012o<$vm$C*$Fp{RB=(f7&CZp-@e_<&7GQ5d=hpf<im~F z$>4)JKci<H(~ZhWd4Qu6kL1@TXr)#|u^-ldhp_>6SvwZ?oYJG}XfNSN^#ZKx!i0-m zCVFC_LV8sIo9uEP60nV}K^QumRp?o~gFY8_Poe$@Fx1dv))VXGkIuzkEXyH!30P<S zOZQHrL-IT(zg(H{<6pXTNw>tK`AT1r#?fpS^}MN07Ou(Z>Avpr0JG;YMIlcFdc`~@ zD|yYHe~MR&wO?|c4NP;}pzeB4J&R=L6z4T?kd?tlO+N}_JldDoayGH>tMeQ@_z-@d zrR8O(TC@W9lL+rf-*uwF8`fHXy41px7=XeMn#C+R|N531Z&5S7ku_&+gsm_Le6C^Y z&|Lg`)zyZy>DgIcQPCh+IE-`8ilru3jSH9_1JcR&T9(4{DFy^CZNX$7{rSsOJ!86& z(gc%%fq^r4KFt20`{2(zxw{P}&<8e3*Us}=F0j6>6X?nO_{o#kr%J0dPo(%`aEk9> z%-cHJ)in6}dH3(Xi%%j%HRGNp`$UA&`1gVWmocVyDB{7gHt6VvXkFI45B;BJ90PtF zV|gl{!-Tm3dEQ%!1>t@FUMxRksYegykm)|Hynh>vDv!?9RQxMAmjk`#y6B@7BxPh| znhITnpU2c9J?JjJ;lc=`4^&A>$2R1J%|3v_{5y$9sE~^AERljCm9u9_X|tauVFN}Y zfYD_F#f*dg6E`#yVVt3Sx2c$nHR8;-07ut64i0{Ms?@(DG{1{BDueDK`YJvdkDL7z zfaKG)1v%wBw3|oL{QT%4R-dUqayiFx{`~G7oLn6808Cr%tGS$@&IdM_=P>Z7Y|ots zS^FA~gTagx+Y%2(5V7iIEYmblPttyZ=Lxk49I|Q6QJ$TVkfZ?@+9mJwh*=To3)%*z zBR<7XGW`7jqY?>#z$B$AH}eX{>PZC#O0G9<fZwnN&@nSJV@9_OZ*}O!H^m!{{j4&J z!<l$s4>3U6{-ss^fVw7m`xf}qHy%Ttf6%$2RRq5<2_rk|_gBC<Y0eion#bzV>U3TT zv8qOyHm(Wy79qcS@=gZQu*x%<5<E)dh%)iKCZWREvD}5Yo2z$W`@fBUZ4uyIZCtiw z%SrJAr%c1#1)vWg9PywBEsbiie`V3tH%L{RckT>mwu~{WjjEdZfB}{ly3>18Fv^Ik zi9Vyl+l|qC7w97J5Gx-@oP!DC=)L;P&AFbsO+2e9`?8+M89`nqJe}qP$f(2LbtRAy zNW|lI?ytZ+y~PI+#a_B-W34~~0W$j3D%2U8IQ4j{+Q9Uw)29)>jt3|Io<W}4=>xhf z@yb;16q}f(_9MN7!3}Sc!+IvC4zdQ+tzT1?_RVd(knU3`rU8)tS^{)m!QMqM9KDB3 zz7ZTt>MmuPr{*w*L^Id9x)N&{1wNQ`IeVjWJ!aO-Qu1gX-n&OKgz70d!->L4!eolv zd9hDGoFqhgM9K}~xgR7IObuW>E#8B<UyPAmWUUXdXkU}4dV=}}AIKm4#B+YUNYS4H z5|2AM{rdd*EQxs5(BFI`JmO0i`5fzis#yY)LiCZyNzA<?%Ba9##Z?O#kP@~9RenT3 zjL*zC|B;o&^A<?(_bd18(t3c32$=K%YYM&NFk`E(NGuu(q98En@|iG;=Uh%+g3B8U zlWgPN$el|+M&|x3FJE~kVhj$0#HsP8e|C0u0Q?<^E$eu(#gAm2MlSb=`iDuTU!T&v zL&quPx7H=jIHX<@G1KFND3S75_TSET0@>9ZV{$O3L?gKpa%C2Lt;Ew^h==na$ocnG zGy7uW2FxO~8XAb1JH}%;a}NW{Q_b)gCqhiW5VZ=7Mnboy#&{BhbqyUo{WflHReSqM z&)M(G(7{QrFc$~E`T}|8>9>B}T027&3lf3uKS_@gKNtu{2_CHxfByBYD@_GFV3ckv z^8-Y&eWe9-Np!5|kR8wq{MJzV=Dlh=HKJpc8_1Ev2M_o;P*W+5ZXRoZ0)<611S{N6 zxO2e1(YddK5X9-dzoGb^#>@`Oh6EN8Y}X(Se4diaOG}7+I-(^(JhTiW97yoryb|5y zmj{t42nhmy`#$u-`k_L9o#50G78b^q+>J4>I{R0ikbOyrWByuiOhu6}%w)B>&H#vv zfdsR_>r<;3Qz5xR%GEQHwWQl@;MzrJd{t(3X^MoY$3F(EIo_))q_3}}wdU{i>(~^B z2+U-m#6g?KXzN2b8T$)tDW<0YKhNT+3U~>KgyU{9!~35tL%D4zgFt1?d3JljS-!E{ zdCll$F<$Q{Vu`k>67U0f%7u>ag`i6iZ4I+8UrIN+qo(ds%x&bbyx;@~(ACuyENsxh z7k(YxFv6mtcYmex?$x*|mLo`6MJLgZAk-@e_kNgyE|np}HiCYM5xQ5n{QHQY40v0_ zESuh;T?Xh(0^-9&b)PVE5PDsB{TQTHha`VXAU}jPo}Sg3I4eozq`|<d()|@25E_ZB zJD~!%x2}OA|7HCu>+AEcPawTgpFWKXjugI>vDOC;oTZUY*bvaxB_5>^l6}siAt9uA z_L_BTEAnQ>tiDxK+UtoDX`b%=LPEqt;$o9;S+nJMpGM=w4aSnW@iOL1$a{Dm)9#~3 zr&T$LYDmYx`W<sE?I)dH(SZA(^BOGbItK2RyF<UguIFxjXmtvn@h89hcN+jB9*zM4 z<(K-r((1m|q2uF_F4m+W541aBqDpJlzj}VM?+u=Gfr0&T7kUM>lfb?V@i---$f+l4 zZjzTTrLWTinZ{xIbWXVVBSve9VL1@18N070q7V-8$cuH7n&*FG7}dp9TMm=+c{&5` zQd_~-=nS#oiho-_m_=aLHf+-9`twg%@L-k+0qwNNVn6HqTlcN}Y_$R$W|0=q%{v4O zOE=W<?E;#DjU!es27X$KT}{`<wFtkAiOBHt^ZPO&vfAEv?f+@-&BJ<L-}c`R7S^(a zEEy_O%1|;UV`a!tmNAt^LTHjC5f#f6QKSrol!#Ix6(yOYP^7tp3@H_jn)mCr)_V5w z+sAi5$KKEJJN94u`QusZ+oC?b-}ikD=XqY|#Rr{e|7OQq`(TTlDcu3DE}^dFVizMv z7C3(0w>5I^EvPlNVoPIo|I`}MmXxl_IX-;JU%X%nX8A358RdH7W^#?0wa}**YzPPZ z?pN&(QrJ#9e4;KcC)O_Dm1!hQNxQ2K#dDM_6w&m(Qkr>=Yj;R)q8FFG$$kqma~yN- z>n+l_aOeoirdQNZ6e)M<L(5lJA`BJ!jG*lnJZMR`=PROkH$oU<5ZngVA>k1}A7kzQ zh`-+PF7ogY?KXg@b_}Fno*$7)(<AZiJ?zHEiIut0pBJ^M<FEAb(J$E%CY_Ij=Q%aY z%$zlAG5~+e`zA)gGZr}SYTr>j2<X!ga6r5Q4w2fT(JhjzQ-I7S1JH|kQDQc@GEnBO zOzRlAE)<&uiQ7+LXu#2VL93q|YbQtWutanO>w20XwK&nm>BN}cc6I|DSNGbPz#&ck zvI6x$R-_q2;~UUx!afF*GDm4>QFJJ2xqfR~&q$(V2b!5~0UN15MAz>6vO7Q;=jg+? zvvFk24}>})wy9e;dB=~ddfP{Jlb<9xH_|p7LP0Xp==wt|&(7jI6eKuzr$e^3Rz~&v z>}d0JVi^Vb+N8r7YKPHCEWW+fVgI3lef!R%&V<O&HF0j~&HI(SrA_8p1G`CX-TC$L z?sJU$>*|zHhql{_uF&j7KFS6qWGR=-6XUNt{0mmP)tBQ;_#V8Gp?H;k*`H=CkF`Bz z^3{>rNI>27Q%KOIcM@L%^S}Z4aj2_smJoyU$Q6e{cvq^}mq%%5sQo!K!?i8ZPJThg z%`N4!=<qeDjYAQHEwuWYXWV(=$ualF*g6hIwy+-kkBH>t<GL16pr0t8vhtf=+=tLM zyXruu(zwj~k3B`iB5>-a-%nsAL>KpkQA3{}8%^%lk@p%C+*bHs6i52Rpe<l-l9VnT zZ-0L*ClO@H!in|tXAS^mL{I?%Gi8-xY}0(AN56dYJEF3jSx%$rBmqaOJo26I-T5w& zysLM_?sO)MlWJw-qm#3ak6*7IFd5<Gb<dYO8me-oN`MWB$M-m2Kmh$_Tv;5{o@-xB zUvz7nVMXBL>uYqH9yv38!Ub*mW8Gz3p1?QOkwh_m>J^>a9M{PfTSktfZGP-wke{*J zs@5Qkq`lV=Ditnd2tR|q>^QpUrRS#a(kfSi38DFeTNtCH>wAt#EP-`nv2y_IOQ;U1 z*=D0MKsw?+Zp-tv<58fzMG)=eANEj`SCIJ&GJG$n_uCgy{aQ)zvk)B7l}{;S68^k5 zog+L!tEF;spWNJBLjK6Pn{)@bH#?wI+|a%4n(Jx0B=PL~ja~H%^g%HRHe}i5rESY+ zyi85?M2AkpxDc>pE1j&-&5eV__b$4V_jr<Xg*<|$tlF#9q<N0!V_S8V!N!pJl9Xwi zg@Rr}9pmKR;XLCjg6ieWuU$Kobff=C>1FYpv9QMrGEPo%2)^E|B`1n>pmB=yX^kc4 zQ$8CqTrYvNJ0x$?IS5!;B8D*Lc$KdZ(65BCYBQ@zH!oVD<*bG+Z$E~SN6U%j0@GP_ z?WX+q*Hag%Ko3$q6NnyCX<<6imU>@>^N6PN+J?d@Lm3k#FIr(8CjgGBuiWZjuv-xg zd2soM&GH=sr)?9A+0@%VidOWS#wi;*VZwyutdudf{XNC}EN`CLo2Cbx^4pz!|Bq@= z3CEjjlC<uMQGmPDfsVE>8GJ5zb>Vl=n^v<OKUN&bwf#g~EV$zuK=bc&<j8a)f&ax8 zI}faUWNDh#iKBcwg9|W1GW3|vfmZH{#PX2@(*3u)3>Kb#KU=tKf#@S7A!f~olt0t@ zO{#0x8%2i*Z_Bo+{B9E5N|N(Uiy(?gps7s{xSdz73j9uC-a*j*N{wa_%2g}w_1=&P zwPd*(_N1dw(+U7G#-Q&6>s}Im{^k72mi8UHjIn=nyT~;=`ucUAqL3U3HvDy%{`_t0 zI%|wl5eN^Y&O`Ec`DsPEX&fAmqdxnP6V0TjjF9X1-4`Jzrp4>tI|G)d7|)Y!e*HGI z`_n~jO>dd<5m(3a(M$lGGw(YO*Spx23CVW|(=16eP~s<O!$8qm*VMGCe;9_~98Nl# zS11N&8GgNF6n(L3;8hL@6B9%OY8>5}m+fRSmp!)-!dRmIw7Krv7cE-EB|Q9S)nFy1 zy(Eo<g8ju9Nl?CJMXiXsp&UfZ%GHO(;uiS5xXd+_oSx(`lPBk09%xZ>Eioxrc%luV zZlR5}Y|w+n9y)cZiO$qtrQaPGc6JbDE<Mqd#A~1C!6Tmpp5X$VF<o+b5?~vdh)TRI z;V(ZgkN5@^q(<#_)|Edi4L<s>79d}ar*sbhn|7-8#U#h$VIKsr@@1A>tU}U_-n7fz z_|+C3>s+;HRE6j;6=ok?d}aAqq;rmHeJ=9~(Pz@W{KX(HX-M};K!o9`ux&yjEV<3# z>SULML@+6y5cT!OFK*jo?~gCqQGNK8125|rq2l!Q(u=Xymp~i)mS~|v+?la#zH=w4 zq)t1rL{WL^j+|3s`Pl!waA6hV)(G1}{I$}&ZtuON=l2<HuBf7tIzpvNZn56mP!wz2 zPVUFpQ-3}?Jvrmu<Js_CxC?v)V_0aH!<mrnHFEh8YCx*u1BVYg<&{4DSp+tI>%RE% zQl&qK{(&et^?P%7L!qQ0iz-c>nm-`xkAD5WY_d3~aG%Dw9RQ`fm)Y{aTg>H@)>ZP7 zxp%X+Zxswtw(8KKokUF5m{_Z9-9e~Glo}}(f3hQoqCXl6i;|tl<dhn{;ZfgKMGVs3 z15?}nTZ&55&4TFBrZ>|qTt7-p8Yti;uGX5QzRsJi@3ytpCz;B%x9=NUzd|ws?^@Um z_`fq14L|SyvcUZ!|B<^;A@7fS>o5TdEgGXOU;>V^u8Cugi!#$gvvYR{rK7~$wKh}U zD3u;J$jV<&rgQp`UP9)vAOlU%sp}55x3+~%(^W`XHnJmd&c2>4kfrT6K20BB_&i7x z^J590cuPY}mtTJ!#N7Z%1jzk7F0GK+Z3(rK_1A3^=YVQ%MVj~&*n|`N#i(`ehqS;z zs&uSoPG9s7KRe(l+=viQ(#t?0Hl^L%Ry|Y<cJO6*AAfpmxE1EXhcWbHfrW?QTLF`f zU>T5(BSDx!M9L8FY43a5=tG?eChMY=aQRqRYy0z^h84}KDa-D@AcOa^`?^BE$Zp(6 z@Wq1{tx)i`mwrdl*FjimWxL)sT;VFS6AuUD+|$sDzf7mOl)rP9qbemPuVzQ)tI&ZY zuNfzNy)8AQaLqY@-z=vJ)JIumnq=eW7yXqQ<7{)=Pe&Gfc>JgTf^=SgTU*ds2zvSR zAhx59h8k0BLFmlF_U3x?$_|lxp+1FqPo}jc<Zw#a?wm1<3`l_J&zqjHDO-Q-<C0;+ zKv+ta2$vC&*!dBDbCzp7>-Y{DEM4s|qU?uOXH$XXo-V3&JtDl5tYm3_x17o!I`_?$ zyhC}+%H*}V`?=1hcJ6kU0Sdq8HpFm=0G_&;rSU|E*U$N^2Ibe~E|<@Dzu%?O`6ZQ= z-SN5c@7W^iE{Tv^IJ}rtB5brxBtLtME4f&GwCg*0Q%FY9ar?q}84eIV+O;C7=8E?_ z(C>n;G70J{{X)y!^y0;fo48%3r)+Gh3pBeP?5(QH?Hq0xDbH!T2o3$35onUfOWHFk z=La|@GZxTwg<FG?a8~}O#k7}t1Lt{l^OvQ7D|5-9r&mP?VZ?xx)1$KJQ{p~_HflYg zrQUndithL3pHV7vZ-0w@{K>tm&f-&{<5oZJDq+C%itPq^FUdIu8@rjLQIqD_dv2Qb zDAiqgih$_=%`Pv$7VI;YklgVuWs|S8gJeO*rsu7WTe`}s&HJ*zfr3mzAbF-=X$<mA zp`*4w{jOD@<C7zUMPr|xQ`V`qC($@&ZrbI84;xg6E;`%wE+)4&SCanPSjn&Z5)zv) zJ|i*QLJt?%wUC=S7VKZ%{vKu}kGNA5gd-}|1aREnI_Dr(5EBXbpiu}EWa2bWg3CPy zXGm8oAN{~dlX-YCQyAQoLwDT%?cP4-i`BK}9{Qdv_a0aZD0c>rds9p661%OPI(FoQ zFt(P`MGjz6GF)egP##M#;qsob$L$egJDu-Rv-*}87RpT><|ynlCo#q2W$>(RDn|W2 zf4Ag^jeB=$m4=7wu#y*+lDyQc;mzH^CBfRifiS-yR+dlbZab%fKz<7LixIuapPt~^ zGO)L&QnJm8zRj;y8!qSFzCcI$>eZ`~!h|@J0h)9jZ@E{?M;=d7dZTRbEB~^KB{Z%C zXR+L%M-tPZ$v4g4S&B^ntF8_Ieex81!6b{Oec#iwg<`1__V3G`3+biWuVhN1)4K*4 zoOyqf07zb|h{rWULR*sJXOo@e?rwQ`aQB1?s%8|cdPq1{2g?00v@ML!v?xj`ST>?i zW(k<_8<#TGgc(*pD=u^eA3YqfdwD|Dh=KZ(Yv!p08WXp$Ew2zdDG>N6{)9=7Z`|83 zx33JxNQlzb)}>ne_FuYEDm!ps_j78B1xGv2WjL@Mj%MdfTyJm|yWT~~E*^EPaEOxV zYHpm<_w?%Q5R!)k54aC`wfT2k6JFh}Zu<+ZuSAHN<+c~xbsaot&`#`-AZhsWq4{$U z^xb-O_&w)0+mhdONwJQ(&H(QI`u<T%F9=$O*<aP<E-6$&JoHALrluyIk}R1S1U#)a zbG`sUMeoH|0O}AIR1Iuvg)Wf*6q#p#7My^DQbcb`(ZBq=@@W5_n7UuIqB~5E=;lR* z!Z8sLyU({Y&Ud?w_!lds4ID6_+jQz1r)&*;sU+aAtB?3=?HMd=Nu3K}1UkG0@VvF9 z1-hM81%napaNj=ts1_FNJW$3lY`@xf=)Q-}O>&i#_Hn>0zKoyIVJGLFTeof%&gx)p z^x_m&5Qv}BgWVBf{IZg=aq{&}e}g<XpYq`YP$csE!S*jcZhKl!{7$0erGKZ4qdNZ) zrBtsmZQ7Vqe}biM_u0mzwS@HzA+NUmi%1RcAIc?_2-kxR4M&%rQhERJqkw(5{<_Lm zVTW|D%49SE*Gi2m-dVE`U1NJ;Bllp?MoAY~STscQ=Fe}+p1-t1r`9fHHHTksX@Q<e zkXNc@6+RVyUN`|AggzcTco&+PNw!~sf!cio{hYGn&ELPtkN5Jxu6R-TU~9`A9lkWg zV}9E?X0?H>_fX7J{~$l;il5YL*P>1BbvI1buS;$TKixi4>Z*7Dshy^SDi&0|6%B%f z@uw}5mtMz9R1&}WOK?Jkq4~CsJMHf@JRUSAX%#nHLN=IVbTgCo!LelucD<6Fq!)nk zNh!rE2h|4y$x*(-R9|nuOW{6=rQPX^nV!3}&ZA@kBe94vZomqq|I(N^8azTx57uaW zJF<obaiCUhug<9mOfG;wiy0*duy`Rk+C+zKbamw}Ar3Uv;khZodG7*a*AXG^DUkgk z?0-Su2V=jGFuFf+ML_{$bp67>N+eA((nkR~hMRTvd_*(1t?I)P^*P+P3jk5q(J`^s zqnEQUT^9-bD7oI_#EBCXjkL<j3JR1%nP$#2Xa42k(QCv~ZRbKLBn1T@EqAxEANq`d z>h|ye=rP2z?e{*trH`TjG)?kC5`COA@f5w@hil0L9Dn>^TFDor;3=fOB@p}L$Lb%n zbRYo*PYL8C>_Ji<=c3p0@SteVS-yFgA6U*4upFTf@WG8~mimT*;dCN;Q`Y|Z=ONL0 z>K-3CLNIT$J|hvRFAhCBIp$ZPG-PhH0YXD@!UTOWje<tf2l#3pDAmKXw6qcK(?DFT zfWvm61=$4nduoiuUkp1xMLBf=_+cDF5eOsi*t;rAnaD{`#Yphggs}n76%+*RZ+i%p zqKC&5gq_8)14FRZz~%JF%)MQ7ut)0ppw3W7SGTA1Q7-=Om}X`8VBQ0T(1};&wj53+ ztSoziGZ+E=yc%B-bw`TKbsUtesbQVR;5L1bRW^k&&Hx#Mc;%sWj4leIhxkN_CqiJe zdVT4rP~{0`JU7PXL{;Ty&buP=T+JVEJN(wI+m;+tDYsI$=GWtg^#SoW0ZCNA`O8m; zSTPp3!21+OTW8+9BM8G&!OaxCr&Z1KYF+u}&6_G3(^Rld(YT0E$zSkBCVEQE%4gZ7 z#WNTax0|}ny@x0RJeuD>%`&ka@U5g|{e`k)XU~pO2>zOtmYh6S6zMb@*J%yoS_hRE z+|tw5hJLi_8=G|S`Q7XNO!v`qobB1K-w1v+9}Yw+-L(8ThFL>_=d^)fLI4UkLGG;9 zldDSqyq#kLBeKY-<{pT^M<VOet1D+*23)&VvTzj7>IgKB4nWXH>Q+PRX8zD3YKW0E z!Y6QDDzb2-TG(Et7kV&b19S)1dnl}i`Ne5yIXI}}a6_Yengi<Z*QZSA|M`|eNW-zt zZXHScz=NPS(1+zdGo^kEc*#z>@!@7sjGagXE~M0mSx7qp`xj_xeQNj|*m)&HYJ3@n zdZQ(znfS5_mTX9<trow^V^%)GWKOrtsEEgE3-GNS{xp;`D=R@t<P=^S3~oc5ZEhNp z^y%K^XNKe6p8bK^NzxZP^Xp^(g%S@<aF)(#JR2UVw*(lSFf^BS4-bspNn|ZQF2|p% zZW~U_I{{woiMPlNyL<xznF1BVF)C$Uq&*$4Zr=%BIgHN2kLQsBdGUc40SYpR&+Bva z=wJ{U@ek4f(Oii@%Gn=+3bAM3zQfV{E=9;C5-e22Jnp2Dn%Xkm6QfiWR&~F?O{s!3 zPoZG3<fVuUR`^LyR+d;I=C7Rkd&;N`rAYKe0;#lZi~H>hG7W9pTwOfN>yo#~eR#2n z?nhesGH60YJXnX~;K4KC<rKI{@h%@gL1$}+fMmsM#i?dz9B=wkvGnFfi|;ixzR<8u z+b)OZ+<(GHEnK^RT7MLz$1x87Q+_{R?>@bI3$@x&a>zVtlMgUCA`Ast@~6fz$@%3? zVgin*x=;I({`*KDg=FscdxZjuh`@Pdy$`6g{FoC!vlTlo@+LyTeroHF+{Rz73g1EH zzyL_NV}VmzRCmV3O%(n}_KCH<nPd3OUApAU)fEdFG+S!)kf1KW8RGi3Q_t4|<tD{; zbXk1EHn-<a-j_<7tGQc)rG%C&OuLN}C4m{(>yV&46LiWTT>t5vW%{{ML>mbLuNhDM zNhj?Va~tA{28QK-zhqnZ;gA4sL~R2Nx~;~uImkKi=^BALce`wAeOF^6&6*_T#ONq( zcM!yOVg&Kpn^AiZwuttNA42!A)Hq0Pkg{^h;OcQdE;oJG3$4y+^`jz81%&&ED7mhU znd5l~^hS!nLZ=2Eaun%=?oox=57`62MR|l%IsZ@svO>~M2;o%tAV&vB_wn^r1T+)p z;ubR^NK%a8nN=B#>~_kKpZ+jE-vsF6t6zRiPZRlg)lr3h_781uO`+Er7ir+0C>_Pt z1Sn`7p3cSa3L2kzoa_roEaMI8qZ9SSFK~S*_h=~+wGmj(BFMQ}+j@1|BRlg=i5GB# zBO-IXO_Pp;+KMQ}Y=R#Qk&3rlLj?3?3b=w6#d(;>F_faV@^1U4-N37JI-<5g5H>!% z)w0MoDl`R!r9m@0uD)hAk7E5pZT5;2lwhgkk&i?H!*L6VT!5Z)NO1jo9$rO~`Vjh9 zbyhdw;`@_|xX`$-RhmNQ7cssZUshLL-C>Z1Mq$qQq*dHf$qoA=^Z&DQk1qpI?<V2) z#h1MS0gwpqpZrR1@{!~lhjYYBcVebw|HpYB6@P-1R345a<DBU)*ZZ&iYS$tD+`k0t zfmZTdJC+}4tWGrRfmHYxL1Lsl?u!9|gz)!Mm*ey~bh5EbZsA7+;eDhV&I~gi?GTb| zVA&cn^;30A06LQS+S<Cl!{059w=cLkSYcI~g|px1EfcP7d!(;@7GPrqq5K2Usm}V? zEq(mrhlqF&R;`>mw|Qc_5RfUK)2ByL@{Kh%?pKw*iScV`X)E~4o-J^JJ^S<-M!@N2 zSGLMSQ+Vk~OJ8VNi&LStb_gxxPq9-)ywn5rKC-bQB1M``7HY&-1GA6H<#GzOwNXbN zlBy2RLEt(#$mO8j8N0Gb;=>zp{1Y~q%!uQ=-fU?d&a{JvhmXSC*!jQZE6v^@gYzJ| z`#+*{M>0;d_1v2e$}h4>pE^M^_pTvUJZ`uC$*iZ8JKEYGsIBzX_r3h<xswuNFrX<# z68zGth~CnoDj)>uQWYq=w>JO$xRK4TA!g=5%!JU>i@6EEha7Up4}_Kd&mP&Tr($jS zFgx3@KIO)?s%D=~k<Q(&t9Yg;-=z}qyJe_8<i*<8&<nB;ViA>ajOi3i6ZbiOdUlk< zn94q(AwQwI&qiEp27IQ|aVUX~PwX~hR%<kZA{{)iel#@bAVl*$6cq1#X>jQ;M<_Qv z$-SsfOmh3e3rhnDS*4%bb#IZBn|0sVTQeZ?RUxG|QMGf8<4fJJS<}{D18m<dz&p%D zHb3u@t$fA7huYeT+;{TcvuC}Iu9#*Jxh6+;fJt)S*jTw8GPBp6p3PYLXdyJV#VeE! z|Fc@!1mu2LVcZ6p)Vmz_{7Av**m;pelm}NQd{|V)6qkp`Ja9JO!xo;)Zp<F_6R&pp zu800*u&CfXJesLk;>$K*%;Mo8#<s@T9^U=Hs%t(l|3Qy=ye+3}yXrxC(+*ZBGaG?w zLP3ZkWM^)eXp3``B}reLGxj<8>uH#{xWqG)HVa{{CD(6@{jS0Lrd_(^wQ+1$lkDRh z+!Uk}Ayl!toAhRDGi$D(5L~dD+LKTFaE2Ibp)MpUZO$wsS<<xkIQDdn)+G7CVO7H_ z3loMZC{Ss6T(gp2xg+egD^oer4HusKb$O7r>e@Vnf)BCava3g_=K)TcN^$15XYR)> z54P}<MY;VYKQ4;ScT!<BhOti|Hb&})EjtPsE4M#raGMSt?`&<~j}uWul%;a%9zA$4 z3$1CScG8ediByDVf1bVRz(N<e>Y@~dzDn13CPj-Vjb?h(&|^<69It;2(r5U_F!AZr zr)Wwqph0;5?wy70fQGgPdF5&9%1%W$9cJ;<E&x5oyZ;I*^by)hl*S`(zmR!2r>AYm z4Et+|MK6vxhsEI;y_}A3sHk#*Jf@aAE<8KU2u1A>vg2`$s^lKC252wKTDozM+pO2~ z36~xoqQyDjHaF`LL1_EWSKV$K2aeKx5sLbC&iQ3ZvH39+c~dtp4C~fyL5AYw$wu&2 zL-ux&8K>^u+}5LeV!fAjVVKr&WsUoh3Opq&j$hThp)?f%oZs^7=raLXc0{C2D9y$8 zn$wL&7~Y8+fRs{&h;$T*o$UVL!QB<ZG{T@p>JqIzEJPMuyH<C{j@vM}^GS9>Vxm{L zS#F<Qw|M}7v$fX%KXV%MV<S8~1UY2LAe43Le!0%cm9w218nI9C^k6{h()=%5WJCe$ z;c<G3ldf|i<w#HHXJHBxsc=OU;^>t5qqJaO-z|JG64R9<q6GpDAb%-64qE@D!vSmW zFxAhCEAOA&H)$blJtm&s8g(bHkCoT2dHFW9;?W{vV`ouHD=1vwQf_Qk+go|rJV80q zp}b0*SkWTCm^xwU#XtKMt}Z)#f4bMyNw!I6ls65OkwK{~RHh>e_gOTx*;m+2Y`7&P z2?}C%4f-|(7RBt-EyD<7CH9C!h%^P(wOanrzJfT;uBXTFva~D4NrOwVY0%Nuh8giY z>`-4}CM_)*MiE!S<g_MqHR(K`=omsM<Mc&t&wRz4_8f#4Yp6^nzh8o~;091eNyS(_ zzaN!h@5{<m6oM7m{%5fr5QP#E%SE4-Vejt@Fd<@HHjbg|zWDIR4YR&Eqk3%Gt!9_E zjO;xU1^7`ouMz!N0HH1Fc%^s}-blJZA0UCgpU)4jR}CBDXgl~t?2&b|OcyQd)3>R- z)lqv?ECt>EK<?A-kGRwIl0M3nEQ_2PdjE*sCV*!?0EI}Ti`1fm%12p0^0I!-&+KZl zAR`2obKSI&8d|0RAU$PeOOHn^29{T*Og=`hq_ii7u3JH2)W^)`Vd8P1$e1Ip6X{TQ zR0j=W4~i+VRBQNPO{iuuj`+Q*$_G)_n+TP^<lax)7phu06=%TZwtZkc6xT)@F=1d+ ze>dT}h3JFdh3>N`TPd_YzZ`+{D+!y(^jQ_I3p(iYiM(Uye(EhPJy;=W>xEih_ym3r zmV;i~r5yrqLr!U`vpX@~HiLSGqOl75(Gv3yBUDu8Q<I7ISygLXZ2gP60i~+yqZ6K& zRg_*w3-Vi+E<amzT)BeQ91`sqGc%$TWGMVflckr(6G}%*V(U_-7W-+r-FBERTNM?Y zx7vpMl6;c}z<g5TY)hNIU?8J^o(x@VA44cot|RN*ZhFW3)fJ=hBbfRVbJJ(#-mPEa zG-L}lUgRSlaoE>S>3$Eh#%N#?bfKG40ECz4lhF~EO+OZY?6S&aQGR3T2s8kGJ(YBy zP-OdkojP|uY(@w@*L4h>jc#qa;4>C}eH5&?ADJVCQM|#T(Bn55(a#3$(scw*{nTww zVm$QZM~-Zjckrul1%;lydMPR>FvLB!cm7RDgUPj+C++@@2|q3)B3g{WAl*E*W`<c@ zN{`P?ez=T^@k9WkFD?((jXTBPp2^EAJKo82$l)|{I9I27<pB@0Q;W5=&$2+R&<TB9 znu0>r!#@_?EWERx%{U~wqNEkhh3ey04(a@N4UX#dDW~%zQ|Zgb?eq5b7L7DFN!)&6 zMUl#2=NhClx|{A!Sa6K_JY6UZ0liq6pB@}JI(Ftnmlan%o8K2=CFlds{otyT1y!*O zF^SK+)FArN(adO)h^9y){S{&AU$J5hf+{-hc=~+tgTQZ)udX4ROje%@$|ULta1K#N zM8*R%vfLam5QnD3H7bYgRs5nteU<ffwY5=A`D(Pmv}%7i;r7DC^ZBLde%mS(7*;$2 zibJ<>t<TF>dbTHeP@5UbaLq+wHgMp;FS*g7iPI0h83!vQT1C;fky%D?8N@h%xG<D8 zDz|czwv_v`5@@k#AvsdxG~@R*N6@u;c$ApmU8)_TeV`}lZ7?FSalP~Q&W?%8dbuxx zi|-k@YPyCdei9PYW#I`GXg}Jq`7=vC@H0yP_Ci>2CH##rme>hYcdJ&D)Y3!3axdMQ zVTy{9#WbZCss&e!Vh${*&?))Rqjrl!=1Irp_Mu(ruo9MCw+0PX=be!DH*2Qkz8EI+ z`KlDBZf1s>06h2aPp)jW<IYHgC_m-#3buwwfYH?MBz9`u10UFdLA!I>?gBSw_&Sa@ z?huue1go_xwud<89mKfmPciT!H|yJX!`@X^F50nU8Zia1>r13N#gT+v6{^Xf^Fnm~ zkdTzmhnw?k2}ZnhhS~4h)i32^wnM}oRS}OkRKf&}p{6%Xt%O<Qa|spy!rt-E?||WS zk^rY<nZ?onl319d5=Z;G4a=uA*byQWheRUX$E?B;=r*a8n*EkmOTvj0eg5X~1HfUF zx9ubDII_fy@?DhX-=);Qg?jeciL7(POK4_y3H}T=SK@vbT5k!8mif7T5e!IDUd$wV z4AYu0^JxD;9XfSA0x$oBb#9x}CbMkQ7r0|Sr_F2M;QSAu;{x2E@p>Ke>P)Wfaq7B* zVu;!*<FVa=4?zL{Y60qfQp|(Bew`Kjl)nz}K)*}x1@YkF!N7HjUEN;0$k<zDBRCkM zYnbd(bIIponOB$a-+%x8823mBsesXyibX3)+cBC4)SB8ndqKumzwZ$BS3>gEV~551 z3O$+vMOp|QrM0t64VQ(=hzV$IZGP;!k+HvfMrfRhSQOrcU!<3`!}5D5592#)O}Ml5 z;3KLUv8)roO#oSiwMnp-B306(I?p?MKS@M=5ij`uo6{U|YXrk!n^vY>{jrFU+Yt|M zpIwUBfJt&MF9S_)&hh~dQOig@s2hBN5=O9UqD}8PE*BlIw6wq+QzKu($%syR9Oe71 zjqm>Q84G$ejLUxvR%r=SqCeu?ovE!5Gwl)e99U532P1@dgM^$#XjTN}vBN{k;iN^` zlS+@lk#<5yIaB+gMMDmd{y;bDJ!ZonUbT22VJ*VJo-I&P5=J5)Sbdttn3P0--e$G5 z5GTN2IVVp7wUSIKLa8#_3&}#ElXt)Iopw^GOj$DuAHGh5Nd3-*locI>^T#c>MM8)n z5t0nunl?HJi5PqxbxZTVrh4A2Li7jH%_x1%inceXL4+&80=?Ks!1H&UAKt1crHZ%P z-W@#QSE}E3z9DA)Hp(Mn={}tw<X6%i|E{-GtUo)yH_flN?$RGTe7FZaVNays$SMmi z&YOi~{im5(MLd{O_q)O>X-m^(@GXfLS!Zg1O-4IWSWj7_DL7w={q67jD&n>NnN&Md zR=+pp{zAHB5Eibj-^UAK+EfoZ3l=D;s~e1XY0e<91hS~vwQVA81e>jnkr76urYf(v zbKAAG;&hYc+dfdtayvy^{&GdEt&xN~x#~)s=d9X}Vw9xaBt(=yE4GPR6U<lYpTwkj z-1`a-xtRSkFu#yEmA-zdZx7trj(ux4^UFhNJvxXH3#G=@t5>(HNG%TO4B#bo7ZPf7 zw%I?rmQA&187}(;;W^Vov|CQuG?UvUh@{{8ltnvNn!`wOCk@o+{G5fPIqJ|B$DNi4 z{wn2c6t$9sbuoEAMkP#!qx$tO$S;T%gFEfS^4>$WTP&bfI_{+2`uO=3^yAMN!qVr9 z4xd=wk?gw{;Q^|!t=qPZxOE^~?XVDqUB0kq{B+Ch=b3?MFFZ8j^7LZW5nR_SUNxv4 zw8kV`P2T-r;NR%nD~iGQ`rki_w9-rh)O<y|jebEQW*1G>wYPJ&QyvdDi&sNrg%+so z^SAK<$z~V6mwWl$mul`u<=Os6>cK)6@ykfM;<vuszRw)Y@FZe#?fO{q!7q1Vo7epm z82|m5EwqsNk=%?b%0QRe2@%PeO;SK`UGK6&*L2*v7rA20p3hE*9>y5<t+fmIIbH7J zzHlX>f+rxi6EOdCo~r}!s)Sl6GGPPh6b(Bg6Qi>K_yJAxz*gOnn#xl3pqO03ql3vM z0_gt6^`RFou<LymdK15CHvE6K=*j}o_>MBm`>`-#@P7>#+8&|~X!i}oTGpoGKEv=T z5{R{>>cX4GcSQ*ku67NVzxOOVOxyZ%)_#PiW!kf6AGpcroTrpeVV?8X>Gk)OK;}T= zfDZL!o-aK>%iZoO9uZ27>z?~}ybD&=e@YaMcKfStEiQ#l?C&^9u%)@j3F4{K_L)vv zx_%m8mfg?K4}kVsIqsCurfu^6M)5e%*pQ}5!V0bf*FW1a=;41+T3Y&@?-I>Uuf?)8 z2{<CtI{ze6Taji!U;#h>kdq5n%u9d#juB5J2s$^8Qze`YlpTHjtXN&nQO3M^xJvB5 zVv4V^??!^=bXrNa-*7F8qb->ZH|JN9#7LloMB;Q)8oYhy(>1|x+VN#8*zqc%9ZKQz zUx+i&{z2I%R-Ahv+NK<Bcb8!3>#_&CS8l_>4JSNf-}mMF8`Kq$qC30=aaX^Sy<rca zwZ*mN!n?}HbcgeSBMzOr_Mg&gr)YrW9`v(b*|%BEuv)Kpc9z&L#tZ`QtG{KZnTY29 zo#jf5QMiwUXeKI1uGu3NX*{v~;k}jh87M4IPjz1S+lb$!q&kXC>yyW6`Mp_{sXyJZ z3k4>^Q%7h@r9SIHTG;T%tZ?~KizlFzYLF<X9WBkDiV-XL@kgs(#{8JaLQRbohME41 z4?7}hqekEbjK7n=;V;0o_URZ7SgyY5Vlt*fQb^!wcI>e2I>gdb3eSS}Z#_rf`3X|$ zf72_r%u;C{^i!$j`$_4N?a|=&VnwHf%aCQ}3?9dbG-eLt3@an37}}*rt<X|x6z=5` zLdVG=)p}-i?*Fj5L$kmBmigxOzpVNRqhmnrSar-pj4oDEse45PzCjMZIlB-+jszwr z)Yl_tlZ$?jDIH#P%-lP2_8t-@G7@&KPP|`W)|Yzimz5}(bd$woiiEQ;UMN@o{?r*V zQDKMflz&1i+e1d?!pPI}>={(*vy)VF!D9alW9>2vX?giSF%Lq<Vel!)d0)UIF=VAQ zc|>gR2x!q1neD-3VJazH#-%Lx9_5;KnohNCw$_Z_;g`ESrAxMlQ1ak!I!WlO$8RMK zNJPDnJFT&<{P(+%6Nf9EM<s34!aCRg;u1WnEQ^H{Y$x)Yeq|N+-{etAFfifUyDbGi zi|P@^`ooV${`VF+s*(~)_CJCO?Qj<%Ze3emLiM+>u<dQdMLm3ujQM@nbcJKnC8tz- zEZaC;J0eE^obi5xjvZ$|GX9!rJYO|yN_ueC0p;cG!k0$$F8yWs*e(a#_4;d%<hNO$ zcI`Rx?$60h)lJ23P7hq3Zyj*v^s(D3(yCokGTsEZzR)cD8m-Cj@A2?tqqq%c6u;oW z;d!Y#<La45OhCxB*gKb`&j8*!l3iw3^?6o6ux#DTJ4n{ee%Gn3txZWywaL2Y!zQgI zJ~e=LH>>J}skzQ8%M)h3zuT>%QTGYKJ^Y1VQc;A-#BI|C`1$$mZ7J?1ReOG5%ad9S zX_ip<o;jl$m0f0?9K{V%R#DNjw7d}Rd{)daWCwn^;2$SjvE}CEkK>h<b%6o8blQDo zpZq<ivWU3&I~x9{tbj`_VxrVrGJ5A~ef+(p=r#07udbb9m>@C?eQUbo`y-zans@Dj z$(x#D0-dsqB8z5QMZSF4*yv)pX3fnyv4*=O??#F}yqb!NzMfujit>Tb)0+-X8{o~t zI{C2{5x4U8<Zmxl-vT4CXn^-zHj0$uQB;=pS6aZtwAy+#oNaVop}i_A_3wdyVA$o$ zOPJbh(6G0dfUiZz_U&9Lk0RgngPrtO{32$)ZqHpWMJuHlxCkMGQ_Cppn^NO4wCs+y z=-qkUW|dg;YW^nqxok4?u~8W`adRW4=gSNYKj%Fz-C$^7a9lol38k)zd)qp#rc;Vv z5E|NyEms*oUeBvot#MP0luZBrO!e*P*nZd5k{q@;F8A4-+~4_T-kbq0B|#o%l*NjG zOIYxSp4sAW<GcbVU>?|z_r~-;a<0tAg+)bWGg()W=kNlv(#c*KAtnPSjQmmj$)yY1 z*CXYVU(&esj1Bxw_4dVn#{+EGmM&Ou80`~l3$+ZrGv%9(K7RP{#-$_a1sR!+j*c>2 zJDDZ!Q-9W}OS0;ZlEB!Tts_=^ZBtw?%%k~51^ZIgC#R^T!r3PT1+&Jgv|QY1M(6;# z``PsQEbzK}E61$roz-ZVd3E}8d$(%2Y_E5p23&8`sRd~?k22)3M>dx{!s_(8znz}` z0|Qm~>Li<Fj~mZF%H0`;peE2JxrEX>x*+$@dGi+I{AF!zt%f0IwpTSv;&gl}?le_g zZ9c?kmY&!&9a*7M;1fot#GyD=RGG~~E-SspSe{a{Lk-p`6TWO`wYxrs=w#eb7*oyq zIa?n_jEMCX9ySj)Z9LU#<yjV3^{92|1bzw*X7O+C*<Qk;Z+PFX)}$}##JrUVTf{iu z$}yLOFK?DKR_2Sx^gUGaS;!hM@@4d>>6xb_&&R%Mtt{>C{$sbI70qR2a|<e&%klBX z*m7D^?>)S6V0_v%y?ZMcqup_cS-|Q=BOg{Z_OAOJVlg;W2skqxt3tI}bbK~Hk}*`v z{|pdYkteZ+#K43pa{8ci%!lkRJd?NY(T&owGA>U_?}jVJtGjh$nQ2N{ZRyma2CuT@ z?fCU6>4^6fP_xkP!JXS)#g{@tw5bd>TMn!_ZZ0*o(=>3d$bl+TrWkWgy8O~UGEL!} zdtPZ%=#E=S8wxSBuWH!A1$hb4ThaKP7ZN)9&X1Xzfl;&nOm1W;j;f9^Yb1DAz!IX5 zo<69@(LUb58hnZ{7EfmGT@CX-G}*!5X?Kl#-N-Av8~&?l!g{upoj0l&*F5n|W?r7L zOrJhw%+qZtpM-+_xS}0sokE4KOs`&-cx>pmHkVIg9(P-G(LHkt7{xEcv>FcBB#SD+ z+Q!C-<#1PTb;#NnTK8ISQ6|mo4IFPKdkqOp3q?z_9=oWT`Cj2bbC)9{7Y^_a)rnPi z+&(+k-6^#0xXA`We@hM19pM)*&fy911I5DS^7l5~)+Vx1f)h_7u=fcVx**1{M~hx# z=r8$EOCSmI@R;Os36B=JmkpaV*k9`t0<wDJq+@O`lT@52Rc<`ps(2;=JxdthRYpc8 za#6x|R=+6foG{&_lXIqXoMGP7)>9|YIgP%O|4?VxnUI4AyJTi%S-*dHAaZ~WZHP|@ zYJ)v3&KE4E2Gb<H$!xcGpQ{7RP@Zk&1jH}AwyLeukQAS^Nw!*kYMSYkvqH$Q`Tpt- zhGtHF7+QXu<i)4#JaET3BriAgwd}<Lw?fKn;)bD)&Vd(G%B~EZEbNSj>r5#=G~Qn= zM|Y`#fk8=98M*+%?IkGQ#R+19Z$tc-q4YfmG{2s(2A>Hs+7Gg1eO)~sp-5(Swhe06 znnhm%;|sMudbXx1YigP&{dhF`!}qNpCV2^B9|3~e(`!s3zf>@kmB+}X{Vvhteac(= zU24c`sSHihc<;LYfn2*M#ou`oc`^IH%ZZ2K6N2<@@5fsunc*jR<NAvizb)-@Sjtl$ z1KxzZ-fbDB2zI#pAFCTo14p^x#;@Z;k<zCw`$(m0<#wNtBo;D84!{=V%~8cO?yU{a zThG$0hLcw8P<dv4S@BNoZDtSKq}z*)5m`mDv6`<>=(UCi7(<zA5LfsNRyhXE*krHs z5IPAieLntZyw}}rkd6yukpa!Qd80e$7l*n4T-5K`vc$wBTpT?t$1JuTwl7V%A=P1! zc~o{xvg@5N*}CW5>K`2=vYu=m(XKB1Y)9e0tiOEu@MH%ZGqXd^1aPRruY*BcxDaXU z`l=vvOw0yGydoDFHkYkvll6bqBl67Iz~&FbxUy{H*x<8HuCO33;+i!*uusVLid)H< z#m%24CLLA$_~C<^QRug_*C>F8dncdw_oqbDK-9^;=<vVpt;`u6=7*s|X{oh{d5wP- zV$j@cOaE*8I!-Mp@DC^7DUTfa8p8%(0EgrE>QXc8MXD!REj|f{=(!=GT%Co%(U0nu zEYxgRqssUXac$T1>2#J`obDF?D1CLo6KBU|`uZ1efY`g>YRjhS+rahojg0zP_rZNx zIEy;n>)1yv_g0q^Qya6XT>0~y7!m3~&nM=7$5QJYdlB^w4d*^|_90T21om9x-PT@g z??Cf=jtomeb8ARl5q~Et`+Fu3tx#VPrgTPYE^s~T>FLQ9nz7jrSeNWe=GZ`zZ)kCA zNo#9flrwU?7NejP7kkduZ?0~5x-b6iU%xBrK+_p4k2{L<Hc|UBp+Wet)Gnu9)*IC0 zNOG~&t0iBf!k|2?D4QsAQqt10h1-SJCw)URB^~2in=EryOr;oAOm+|@N4A&nA>(c< zgDqb%Fg@($l?7xV^Xo6B{dca<$)k1D?9#L{e=(On1CVo;^XUG`O9u5wFKTObE@Zoe z>ZiEPnBN)G;_lE~u|DA9Me}cE-tNt8w_tsd#j&KeC^=j2KqqI!eGK3_RW-E)#qy$q z`j~H>0Rd;9mE5)9tix84f(?~2VU6NQ+~2Cj1FaHV(zWcQTlCtOTZNvv$jZ@Wpq59A zC-F`Af!mIG&xu9)2|u`GOyAdRDQ@ZQ`Xa!3ip8um4v+h#ym)cEc+wQ`lF0bdu(c+Z z@k~Lx@Q%5Slq$90OcS5J)qy?~oay(i3ae7g^<s~T9EfRekmnB)bYV#4grP&{P*X~o z?WSi;S3I9Dy1XSzj?(Y;t~>w5xxit+q7@`y<i2E7M$0K^BNyFjT+}D?TT=^}=>#pk zY2_hQse=^$D*rwKeVPVS6G8n9y^81g;D1|#aCVOANd$oDlq;9TR_x8|8nHwWJ6`;o zW7KRrXPJ7>bIn+}eFwPa0wmF|FxcxS+jpb<Tv0whd6F(xR8TN1qMz|Bxs!<|s5WP{ z_hk;J+TCctp9>)&Y7I6zY|k3gcNt4|w989pw5h#s3O(HPejz(u7XXLiW!1H8-*%|o zQXrcwdR*!FyZZY2U!0Sg%#I!UbBDeLS$RQhjmxBE51vE?{C-z{1wSu?Iw~N2d`44! zWp+f|o4hr46I4~p_q?p5)mo23--0c7kZoTZnjaN;trR}QSJ8}WdO^>sv#xbU9e2+l zZV^MRkkUnZof|rIs5Ni~hxSDAq_8VjUh@|U)_kr<@p3}3koD#kMMl*;)?1FD;kzn6 zYqi}{{KCS6U-KPbUhN}xLVnE~%k!>5?W5A;*Yzv{m6oyf9vCtSbCX&msMZA6VS5Uw ziNGf`U~>G~Z9q9DV~}>s35NkJ!Co`4u*}S?ze_n<yLbX%fTgk>)sa3&mbFbzj1s^9 ztNcW$-U`;u7$>^K(7r5MFUO%p`ShBPaD{=8JuP)h8O<eyMc;sqD=$o#SYuA9SOe|H zU{s8exuL)wApO0QGi;-FwOWOj2dY<i2H+>5`1EtN6}Qb_%l!_c60g3Vp8#&<&rZX$ zECJ%y>nts4FT9&eWAiuIWPLVb%_z|xtjqZMnW|#ciy!w!ani+AUqA3RRZN6=qOrJX zuhqqR`2{D(%t&gjjasz)>G+8g4LRC&uSN{}eA;p0`dvroSr38a2@4BbYGDzyaLSjE zp#k^4bFnmPw)venA;xhUUpU{%819+Oky=k_MV)0=GWQ|H9e(mlg?{~O0rpx;IGBxG zum>*R527n1+&?L+jgMDo0p<Hx-xNatzv|Yh^2fU1LeoS?hM%YwM92)^{o96)`J)Zd zPol`F^|P4c6BZusclK-~fJUj<Lf5g6X}V(2MSyWpUEFDFskEV=Z{!lq+-)P3pL50Z z)>2v!n^?DH)TNs2^AjZi1CP(M>f}^%+_qgT5U~Vpjvj1DBw4#H$c`*hV(;D*z`@rv zb9f{pJAUn-(dE0}&~BP-emT1_Gs;Z}b-%E*XIRZTXR2+6cVco4_qajpD(YmLI!cKO zY(bvZVe5HuZ4u1+XY%e=ky;}Y>x=^suTh{dW(H|{h5A9@<zilfgH<U0olJ6st7fzs z4a6~ex^!W61>B9qTDT{k#$z7=Xibv6GmvU5;sFyV(sHO*{|xkOUs(%#jpU!-Z{2B& zh^Kr=)geP3U~sI8uD03D{aF9)xO1u_W@vip?bgdW{N73qLjGDYaZ;Xh?EzJrB@xd6 zgvom93ibe7QbwxNZ<G}!C9#4pj{zz>o}jRzZES0zCM_p4#xN0OJf^Sh_4-^ATk5lC zHvngIFbw=k_>s<>Gb*Wh({@JE%PG=h2R6U$ykJWKHcw68z1?l8GY_z2YHwaL!(mK> z+Z{i1#tzeI15;C5a<74*;X1dZBD_3TqfE>~cV9*!Pm`7}<bSZlF_dD<nQ@(I7kuN! zYlADxEtqz@#={-D-5#bbj###wBXq{4^z!k50J+$}Hg<VgkR+p7VfR3okEaNRM6CRb zrU}XgLShlI%9W%)0JX28WiesJCDdOE$HQ#$3qaSeOtM}DCCsI$2&mCmyJk&J+?`t0 zrmVO-mV6hR*Gc_(ZqP}w;-kUlQX}PhNDmn~Wy+MAq=}azB4P>(OxYQ9gP^Q3YE-QF zhqCf@))rK|B!2q7^;uc%zSi<dUPxm{Efc>rv!rEk$d_E|E9`JhzxMj|>-5?S@8TC5 z7_3Ena3=y!N#Sr99v*I!RTm2!oAAls#uf~_j>H?3Yd)9uUYrqb>1v^7{@9mqt8Q`s z7jdEv57c@C3$%_v)3kq!#aaXQfB}q9+-QmqNf2F30k)h%d|Toh`^{g`%Zj>NY3NX6 z@Y*W~7u7euoi2ysRvcGW*gDKKxf~T0$3nIz3}4%jldqjVeR^$@X5rT2!?BFQZO0q- z>p_*sbMCrrH=dGuTte$EoG|ZlxD&#q*-1@>l{Fv=d*%%E8radMuhR3Blvhm8)dIVg z#U-^wR3u?(!V<~Gr;FTz$$v)d-$@j{)`goh7Km6`al3k<=pT&f#Dtp@R<4Gqt_`iM zF5kKG?j-QsD*?U(BrODq>=v*j2qO_=szSP!gO}Fzkc}n>4bedvZxk(`#PEgx*wy<O z=I!q?>SJp8>(AAfX;M+DEQ7#<IXma$(=+q+Yx;0E%Yf>J9eKC6MPuF{x%SM98=yuy zuc)_VuGy^tLVd2@xc!yRurDl&O$X%)BD_Y~4qTD^Jv&%LwP4Rt*0HL?=|oB!&F>vv zf~}b-XZYpK5;fJQ>A3*AXg_lfw)pr7#N-tvbh*9zF+~xWq+OHiiu6e(PS_WTH7Sk! zr*QB;JsPlK1sZmLCbumFjx1f|-gwN7ZS52DU)wiL%&2}~v3KLdiX68yx_|!pdUhYP z5cY|E79B&3Q<(v`=c`SOCs{H+ev1CGWtXmAUCj5(i(cmq%0nv<%J1G^!)2M1lhcau zL?8ld3W0b~9W~1o->cidR+8rQsS&x{#t(bXuURxC$~|wrvn{Oh2C;H1k#!F0s3hHg z6cPDW!ga-tUHv$R+#vY%EP&>+R~J$Zz4o{kZ*Fxz-;L0S7m*upGmt%v`E*bsz_DuT z!3MSU=%nlD(etQU?MV1-n;%}7uoe8NJkKU7hGlV~b!cYP^2;zQjm=m%^*L>$E!3qt zUawQxCLV$IHw&QTk38!KpJ_^I?w5nd^q;ixZe2y8jfj!108B;eZ)8bvq~bK#S5Sxe zBZp!~_FDN6+^d-=8##9DOTO{Q@#CX&^O6aGcBng!`}<o943I`718+{%!GrIimw)ac z&v7x((_2kcH(0)WJ+CjCawMO&1)I%@Ww&mZhJ|AUrC-PPfE=!fY;52*;=Ub5`fJy! zvl@*Xy7}WIQnnYXGq=ZL1rjjHVU@P)XdJ4_K~RAjF6N5!Gg<g+*rGx0&4O@ndh6>& zOD9(5xcz}boB+Qw{Y(~W?DV7rd{%gc(La9tNH5F<hq57smUN5EE}IaTwvHzxRrp1f zpmqQL%zRD(FTrF`k6%;kCOB7^Zs+OPA<tAN!>x7KSm2Oc7a-;&MdE-Nih#6WL*5$7 ziY)lxboa+FaQT`WX05niR%=X+b&2;_&L2E}?AU7YDA326kd1Q8@wJe*5@S^)@O=J& zoa-F(`p&;gB(j%uv}Y_EDl+bhxyL%@yI%xhJMQDNinJyEG3?A{A9(n{Z?lBk;rQ`9 z?oahi&nxQ#vddz?7ylU59;9yzhsEPZu-cAuq*irCwG8@O%iTG|ux$)5RzA<&njrRD zcy^yZ{#cFk!fy*yC_P1LiiwFKVBfDgO{~o@XJL`Y*Q@S+z$tkgc#-``+c$expU?HB zw6qi_h)U0h@-MpWYKsas5V2+(?{!pnZQR_Hx}ud-gwennKE&~pCq>dfj{agv;5zab zbz`=&va&5eQl#s!QMbR%+zw(r5=FW|M+{_aO~Q#`dE`Io((`+EZ~Q%WMV$Q~efq2; z&<C}$%;kz`h}~m@?8~Yf6k-!YE?zW7Q>&z?m?Pc{d#zhXv}CL;3sf&%_Cc$yA?@pd zCVK-e@U>(bT@I5;dClskVcp9H;$DcyN93r3uVk&M1gOdM*tGM|e#Ocad7npuMREWR z9ystWy0ud#W|J%(3yY04Ai4ZrmOX{XIP_F&=IQO5)D6t2ntej({epB1(%FIP=6U+y zpDk_v3~~H*?;OUqo>xoHt7R`+Q(81y&2aJJbA%wN0n<PvG7DPt{sNWdCd4o#K;J-% za@4U(M)cJbr)7i>|49xCpFe0_VmVXz&6~@K8>PHU&+YC~DjsbV9v`Y(I~9dfJC5k_ z>z<FTSCX@FE&ovK5<@<lW3;z1Fq7Aww>;q9#O(sU^$DqTt51m3EE7qY&K!Ztp_TbF z!!43Z$Par9ZHDCRTfxBOLaOqxhzPqwEpxvFzS2_4ne)mc3p`PDnY>{i$Ewj`Tq03c z^O2%AsP;H8fjLvqMZmp_xpk{I9HdeSRn!5U_~h6oyWIzqCUa5~la7`-Y3uP92nCZO zz?dd(H#0D}n3AGPIjZ_ztC+mZw<I+^%v3!;=TP6lQQ6_APs?Y=?H-h)-r}?hFoc$x zjNdgicg-*P-@;&>!+AA)9DU-+m%yd(#0QQyBOEWWvx}HEV9~Ltk^L?U^aaq5?`=g* zdiq$@65;1Nd-h%`q6r({-tFDy)>ad$rQ;*EC~3C2FJ(~M1%Mooo}f^0)jd)47)m+< z)vcYx2{`(*?^FF0edp`-R7D+;2Evn1k+&7U(8~<Xi9MpLqw^A^jgyCYY`@s3V=Ltb zWC9AdRGmm#M&AmHd8~ZwqBh^w5%*$Gg>zBGCP_lJu+i09IC*b%l~kBue@2WD00lbE zNyFNLUrhci4?-hOheccSn$=lie<p_qFv0h8X3{bwCh1fSp)1GqmCnz>Mf@_HhOnP? z3h=;HaN^VPm!B_@%3pQsR*WGq4G>;`x>kYJ{gVG{lmKrj3+Q&@QLsE{jOl6npm@nq zs-SsZ#U)~~F$ymcsNQ9Xr@RET_}0OL2l*YD%4;xa`e=V>oveT#CV9EFl&uh3hfkjv zoq2fTo8i1jmKalT#m3hsQQh&G`P)WZ?Hj+1R~j~~jCB^Y^RH<D6cqOKk&$8L#cJ6x zD|gx?f1z&YiUQqTLhurIGc6I72>_2F?=QS5W|)%FElt0Gm1P^CI!XlnvqLiwiCbyu zYxlqGQX%Kp3R-~k2M!ZVxu#~?1iJiqz;hRnN<KS?rkUBZ^D)a1h_?c_@167O_S(`% z+ZvL_TxI_YpOlr`y>pke#m6A$<Z%IqhBFQy5pQ;SOP&?&y&*4%fpUfS6NEm>Cj{~^ zEAxvZ8U`>cRTuqKGMJ8!m~S-nc6_RIVxAA+%k-;<?^^9**Q;;wBv22JlkJxLWmml* zkq6hNob0fSXn{M<nd+HsYNvmGVE^M{xzHt!J1+xp#j3Xd*T<14Pe=6a8g}ExGQyBW zxMm;Ry8b4_UJBQ;#+jpzE}mGhaW@o(c!Ip*m=wp2sj6|buuyiZrT_TVzcj8GBIL5- z7fMq*Py5b5@c<N5x{(7yEu`b%wI?(dx&4c&|CZ!_c<cTz^wEiYQ~F=0ww8JkhNLI_ zaRIfazGil=>AN-TnwrAWBVch@V3S(Ol$H#SFM&O6+X4=HdS>)@E(oGq;Nfz=4FjjH zifo-6cIgsS&uhx!P*P89{Fl|g_a3>JYkb?>Ub`~s%bW$M`@uW}_XK!1BrKz@Xc?=Y zXQfp$0Fj+(b?LAX#jpV|CA*)^$}cfQu@pX$JZvM=G!UBGoRw)|k&#=RVqQ@e(3^oy z2n6G0;KxKp?eqbZS%`gW%Iw4m1^SIFxx2*EOm&b4rq<`*yr0w~syMfzrPPq`l7%Yb zjkQ6sU5Yi5d}M=iE~g_eU7A<a@WOf0M9Rbq?z&f77KJfR6c3!`$CfewEjxf-Z^h(} zaWVy=(YP^iBL%%!CTZ~fj@W`ohcnl!c({s6_{*t2s#bZxTl;u|(BBuCtB5J7-wrYo z792d2BS4>g;8H?8w_5;%j4GQ>okNlo>>1=0?AZ<f%6p9Oinz^k*_(}DvyoALsBVB= zE>AgkkK%oBvIGCS20~}{vvUh>{^Be82_Dxm@T#yd*0WSAxCJHRAVbQ3>L3rI3;N<8 zVJQ2>cpC`l{>FZpnVH7;g*jV&37lix=DV_KL72cLalmsz#m?&`<Eb(xmwEWvo>^w@ zEw$ia9C$E8@6B08>tdeN=faOBf=mUyC<JeMCP~S@IqTZScQeUQ{5*~C5C2fzP@2ag zFJGpBxfci)9MY;sW5=j-v6B{i&3r-<D&oU4UAv2|Pdb}i^}p^*s{&)QuSqK0_!-Om z#2}luEXE5KuDKCSeViAr<??duAg_{&qO@ASd+RP-xM6JNScXC43O0GxRThor!A$ZJ zc#CMrYLf3*2!sgWA0j~0qQ_+t&gp@Tp+|FwgKlS*2$ZY@65GJl)wQHs`K<054|l(} z7&D~~Yvny|Imq?~N{3H%J0m;6+SeRo(uN(HJQ{o>=F(%6BlmsY$hju9L0{2zCA`LC z#KYaql6EUdJqbT20n`P*c|Z&P0lW#<ZbQTCnyi%|LDA!68Qkj6KEBg}i2A-&4cTP2 z*B@v;$nbP@rSvaOPA+T6IG4)TtzB!4_4PFS2KNapLe!{9pT%DFU!BxWU?LtI>JSG4 zJ$~)8bQH+))_q`+-CL^zooJ=v{F9fo9;@EMCJAdk7MS(l;5Ku|>E~wbo-~&Oe@h(r zby~rk_)LK3^MccQFb$u7{3XwUFjqa2IzI&luNKkxe$7z4A<WzwK1w&7-vTwUp86`N z-X|a+oVewi){yk0T@n__v-GmTB%K(eiH}`yARw)Klv#oS!Q88OJqU>Ot@z6C7OBra zHw(!y?{wR=vj#2lZv-gzkD9?n<IjZ)vrubpMg?S8c`}B9WsuQn?_4T*l+<3&PmK@F zRLw(@W++~EBkkAB&ksIVe}P<{6`q$-@C?s@Ng8xlK@%3qUfhiY+LTAMn2}NAmSx4i zkG{Q_gd|mX#z}rIW<OaP^#vKqalePS=P8J|y^o@8f8@>gT?9fqWz&ZzznynyDmn{P zw@7(z%aF^AzVvk25M^Q2NGxYS(ZWKjF^032es;Z7+J19N%tMnVE}d}2^v$=vyRyq@ zrNZyK=&mO4#o*pp{w8ti>rq=+^)@#D2dFkT3&FsKgy)&X!UWqVg!~uNNW<AuKi{V! zvEG~%lxulH$43}a4NaKU&{Wi>skWY!O)#&;fV5Nq(WnGpE7Zphfcq8X6X=Y=0PkTn zZ=Bh}CcsAep9nYQIy5a8MP(E;RTt__;5gz<^Q>bJy3Pd^jZlfaITJE_RY_dbyY1KU z<rmmISaOXt#9T<LRdI6=C|WrRV#1i$NvqLd0@p_+d>u#3SdQk$sAS>12OY&?_)L}y z_i%9DGCTuZFbLnoFM9@xIju4@3K_&Tf7hMC0!C&0W5Cw8yVCCu5R8OylUaa?Rocr( zQ{^e>ihdhE7M9`$iTupAPp6)@4$%S`EQI2MXkK0NvU9S-4XjgLoAQgiN*uMIl*spq zY>0_;>nwf`!}{fiANHGv%=S1*h#zZQuyZDL1Me_6^sI|6`NgMK<D0G12DpB^*ZC*X z>NzTYxI*Cga!6GHB62z$IjiZvCG~;*dC3Nn%V?oqW+eq9Pro>@rDU!P(9$v^qir+u zFOg(~_7q-uF_5<*qLPPc3q=qSByj}TumDDG$WUAfl!S)#Q^iPBKlwj_+ryRuJp;DR zCz{yO0*ltV2?WXxV4HqX+NPU87x5CCzhFTOe<ly$(3XCP&UVrG@oXg?H$EC{q=^%< zf%M`PVHEwC!phpime;S&4ugdE2USEnH?+mxG3v^d8(ipo_<FlHw{yi(53oGPS|^Io zT%z|#&|3k~(W?j5)pPjsY4)teye4lyuzTchh+uOlqP_wX+#pi#kL*BhVME0Rj+I+U zBe}UO#m0l75XNS5DO`|O>TH45G!e*YIctD(D73BE=@k9->(|~+tpjo351=Bqad!tw zV&nHX*+vHei8nnO?e;FO$em1Ti<tI#<AC$Q!M5<<@Q7+tAvwe|5D>%K-tnyiHC$eU zJ==jg96xo+iZdMp`e+28N;A54dpVQf>cm?)r05{5%FCG17*?YXhJvq=6UJ;)^07iA zmC4p;_vqi>Zry2zed2J%vS_1-eM%cRvMu{#5i{ETgIDG=4#8_l1C(1yzhd!S6O_e{ z32wY}-!3jvpD-a){5?>uX+aUafOlwt#fuT{=HZc%7YD;JzHG^u(>)e3T`cwM)Q`S; zGuzA_?AJFp-@tj<^7d}K)U>oX%5jwuBd$?|O=YlvA7w<{v@OxRdh0as1=YS?fy33t zM+2=JQ&kW(vlws~2|zT(xxy9%;TrSE%V}Q)<n%9Gar(3^4DK~HvZtT8{Z8xoGt^?X zNG0GkhtihR3-D$~hVfO-TmTdhqJg4lT3VCMn>Syw)4fhIG+w**q5xzdY~ad`VJ7J- zO{f9ICj(lpZWxJo0HeP49He2(ILQ&z8zfjQ9Jc~%%k#6@>f6@6|FP+VR)Vm_iM{5n z&7ZYQHf$I*aPjz3pq%F?$3D0ScE|pU8z)bmT%5mAK3U9ug5ChH+wh14d@O)_9vFpB z(3Y3!BfJhDj)D5|^!AQBws6W*?&?}za5Q}V&!1aaRP+y+FXePaHg67?n|LV#(QcyD znHhCn=@hg{B6T3}oSb26D}a5u&-_tA7VbJA?slA8_9o^Sj6cVc02{n7<G2I)f~o-B z+ag>dzPUR#S59|uxJHlnL_F8ovu7I^88vhlg%($Bd{UA9uIYE%@4EY2n-}OHJctos zFmFt=rc(S5^3@eAIgay^sFGvxBrrk$KC=an*zV7su{K*3C<Zig9luc=S~*$AAy}bb zwRbHuQOC4Kj>rnzHdyWI5B>57#ow2USHy<Z#$Uk;4D|J#W^yK<k>%HF2BwiqW|apA zDH?Hfphj9|J$n4un3s<c!^@xWx`5twbq|Uch8<~J(3xL$&k(E&En_a~F+0N57AE#J z*Efbngt_OH+>4#TJ^y-W{EMql5;?F!Sdm)<9m{?V5;YRbNWly623b$it%;ZyapQ)s zy`D-YyhFgWZP(8rH{1fWmk+OJ%>&$6zLm#U$79{24EQ>2K=*;#eM{4WcGF_y(qx}b zuMM~8b^98pE}!WqZs~I|t|g)yzwP(Il2N4vx1!l~b03t#0&VsUKpGQ>RaHhOp&R_m zov86r*%Ao9p2tI($?bcwKWmTO5H2uBMLrCs#t6(J0w*Jj@3O9%fy6<r&FgLj2?7gv zYKKS7A`_>!*D))b^u=)#Tn;_~M&hZJW~Q><-HP-VCvG7RHiD=WwB&_2qP%-16Tm#5 z|28C;6M<-x+nvijE9bFsWUOFwjt2(Xvp`n-Ly%>Q7vG)OvCROHmWby-y|S_kD#=)Y zx<>Q^vxZdAsSkY$ToMr(S+R%iJB}Zi%P(CHw=dq*R9v<CANy7CZ9ucvF*VKsjr!`V zw~%nKX8xal-T=}zAzsWX$G7eAvuDk2NyJ5>4e|pEQsFh8;&S3@|7ly(Meq}$7AySp zL%k%=M~@isRLlU2;DW#<7ZKMQFe{B9oM%=M2zqm8u=wcx#~+UOlXl-*S<>xba`A61 z`DL|vsA{fUx>T|!!A;7!9Rr9r2kg1V6W&{Ked4lJtAd>>3L5qZo>DNHyttX;yLv}4 zNC`MftZ5D6Q;N`NWORysm#won@Hu44XAbh3JsLx676nYrX)odb(sS}Qb`k#~`Nibt zKYoq<`Hvp9?f!4SIOy-c`oI3kf4(^VYDe++{`u?w55Bl_B~UVhWq*IqfByPEUzFVI zE&kho{G#M9Rq@~c*FX8+eevI4@bB;W&!7DFi~syCe}B*a%NPH<NAVvY+W++V{CAJy zf9v!4_ZR$+kK#Xm@qhk&7XCa({~x@j|JU#CfBKsK<Jtc2-rfIyjQ{JN{%<|TJ6EQT j5HaAtjW!<gZQbWge0M-?)Q7j?&+5!xs2w?T<zN2?a?xkC diff --git a/res/app.qrc b/res/app.qrc index c41d920..26fe7f2 100755 --- a/res/app.qrc +++ b/res/app.qrc @@ -16,6 +16,11 @@ <file>empty1x16.png</file> <file>avatararea.png</file> <file>avatarareaimport.png</file> + <file>mappreview.jpg</file> + <file>pointmaker-8.png</file> + <file>pointmaker-16.png</file> + <file>pointmaker-24.png</file> + <file>pointmaker-32.png</file> </qresource> <qresource prefix="/global"> <file>global.de.ini</file> diff --git a/res/app.rc b/res/app.rc index 4fbbc6e..2a09572 100755 --- a/res/app.rc +++ b/res/app.rc @@ -1,36 +1,36 @@ -IDI_ICON1 ICON DISCARDABLE "5sync.ico" - -#define RT_MANIFEST 24 -#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1 -CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "gta5view.exe.manifest" - -#include <windows.h> - -VS_VERSION_INFO VERSIONINFO -FILEVERSION 1, 4, 4, 0 -PRODUCTVERSION 1, 4, 4, 0 -FILEFLAGSMASK 0x3fL -FILEFLAGS 0 -FILEOS VOS_NT_WINDOWS32 -FILETYPE VFT_APP -FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x0409, 1200 - END - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "CompanyName", "Syping" - VALUE "FileDescription", "gta5view\0" - VALUE "FileVersion", "1.4.4\0" - VALUE "InternalName", "gta5view\0" - VALUE "LegalCopyright", "Copyright � 2016-2017 Syping\0" - VALUE "OriginalFilename", "gta5view.exe\0" - VALUE "ProductName", "gta5view\0" - VALUE "ProductVersion", "1.4.4\0" - END - END -END +IDI_ICON1 ICON DISCARDABLE "5sync.ico" + +#define RT_MANIFEST 24 +#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1 +CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "gta5view.exe.manifest" + +#include <windows.h> + +VS_VERSION_INFO VERSIONINFO +FILEVERSION 1, 5, 0, 0 +PRODUCTVERSION 1, 5, 0, 0 +FILEFLAGSMASK 0x3fL +FILEFLAGS 0 +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_APP +FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1200 + END + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Syping" + VALUE "FileDescription", "gta5view\0" + VALUE "FileVersion", "1.5.0\0" + VALUE "InternalName", "gta5view\0" + VALUE "LegalCopyright", "Copyright � 2016-2017 Syping\0" + VALUE "OriginalFilename", "gta5view.exe\0" + VALUE "ProductName", "gta5view\0" + VALUE "ProductVersion", "1.5.0\0" + END + END +END diff --git a/res/global.de.ini b/res/global.de.ini index 5b2d94f..fea6010 100755 --- a/res/global.de.ini +++ b/res/global.de.ini @@ -1,102 +1,102 @@ -[Global] -AIRP="Internationaler Flughafen von LS" -ALAMO="Alamosee" -ALTA="Alta" -ARMYB="Fort Zancudo" -BANNING="Banning" -BAYTRE="Baytree Canyon" -BEACH="Vespucci Beach" -BHAMCA="Banham Canyon" -BRADP="Braddock-Pass" -BRADT="Braddock-Tunnel" -BURTON="Burton" -CALAFB="Calafia-Brücke" -CANNY="Raton Canyon" -CCREAK="Cassidy Creek" -CHAMH="Chamberlain Hills" -CHIL="Vinewood Hills" -CHU="Chumash" -CMSW="Chiliad-Mountain-Naturschutzgebiet" -COSI="Vorstädte" -CYPRE="Cypress Flats" -DAVIS="Davis" -DELBE="Del Perro Beach" -DELPE="Del Perro" -DELSOL="La Puerta" -DESRT="Grand-Senora-Wüste" -DOWNT="Innenstadt" -DTVINE="Vinewood Mitte" -EAST_V="East Vinewood" -EBURO="El Burro Heights" -ECLIPS="Eclipse" -ELGORL="Leuchtturm El Gordo" -ELSANT="East Los Santos" -ELYSIAN="Elysian Island" -GALFISH="Galilee" -GALLI="Galileo-Park" -GOLF="GWC und Golfclub" -GRAPES="Grapeseed" -GREATC="Great Chaparral" -HARMO="Harmony" -HAWICK="Hawick" -HEART="Heart Attacks Beach" -HORS="Vinewood-Rennbahn" -HUD_MG_TRI_ALA="Alamosee" -HUD_MG_TRI_VES="Vespucci" -HUMLAB="Humane Labs and Research" -JAIL="Bolingbroke-Strafanstalt" -KOREAT="Little Seoul" -LACT="Land-Act-Stausee" -LAGO="Lago Zancudo" -LDAM="Land-Act-Staudamm" -LMESA="La Mesa" -LOSPUER="La Puerta" -LOSSF="Los Santos Freeway" -MGCR_1="South Los Santos" -MGSR_3="Raton Canyon" -MIRR="Mirror Park" -MORN="Morningwood" -MOVIE="Richards Majestic" -MTCHIL="Mount Chiliad" -MTGORDO="Mount Gordo" -MTJOSE="Mount Josiah" -MURRI="Murrieta Heights" -NCHU="North Chumash" -OBSERV="Galileo-Observatorium" -OCEANA="Pazifik" -PALCOV="Paleto Cove" -PALETO="Paleto Bay" -PALFOR="Paleto Forest" -PALHIGH="Palomino-Hochland" -PALMPOW="Palmer-Taylor-Elektrizitätswerk" -PBLUFF="Pacific Bluffs" -PBOX="Pillbox Hill" -PROCOB="Procopio Beach" -PROL="North Yankton" -RANCHO="Rancho" -RGLEN="Richman Glen" -RICHM="Richman" -ROCKF="Rockford Hills" -RTRAK="Redwood-Lights-Rennstrecke" -SANAND="San Andreas" -SANCHIA="San-Chianski-Bergkette" -SANDY="Sandy Shores" -SKID="Mission Row" -SLAB="Stab City" -SLSANT="South Los Santos" -STAD="Maze Bank Arena" -STRAW="Strawberry" -TATAMO="Tataviam-Bergkette" -TERMINA="Terminal" -TEXTI="Textilbezirk" -TONGVAH="Tongva Hills" -TONGVAV="Tongva Valley" -UTOPIAG="Utopia Gardens" -VCANA="Vespucci-Kanäle" -VESP="Vespucci" -VINE="Vinewood" -WINDF="Ron-Alternates-Windpark" -WMIRROR="West Mirror Drive" -WVINE="Vinewood West" -ZANCUDO="Zancudo River" -ZENORA="Senora Freeway" +[Global] +AIRP="Internationaler Flughafen von LS" +ALAMO="Alamosee" +ALTA="Alta" +ARMYB="Fort Zancudo" +BANNING="Banning" +BAYTRE="Baytree Canyon" +BEACH="Vespucci Beach" +BHAMCA="Banham Canyon" +BRADP="Braddock-Pass" +BRADT="Braddock-Tunnel" +BURTON="Burton" +CALAFB="Calafia-Brücke" +CANNY="Raton Canyon" +CCREAK="Cassidy Creek" +CHAMH="Chamberlain Hills" +CHIL="Vinewood Hills" +CHU="Chumash" +CMSW="Chiliad-Mountain-Naturschutzgebiet" +COSI="Vorstädte" +CYPRE="Cypress Flats" +DAVIS="Davis" +DELBE="Del Perro Beach" +DELPE="Del Perro" +DELSOL="La Puerta" +DESRT="Grand-Senora-Wüste" +DOWNT="Innenstadt" +DTVINE="Vinewood Mitte" +EAST_V="East Vinewood" +EBURO="El Burro Heights" +ECLIPS="Eclipse" +ELGORL="Leuchtturm El Gordo" +ELSANT="East Los Santos" +ELYSIAN="Elysian Island" +GALFISH="Galilee" +GALLI="Galileo-Park" +GOLF="GWC und Golfclub" +GRAPES="Grapeseed" +GREATC="Great Chaparral" +HARMO="Harmony" +HAWICK="Hawick" +HEART="Heart Attacks Beach" +HORS="Vinewood-Rennbahn" +HUD_MG_TRI_ALA="Alamosee" +HUD_MG_TRI_VES="Vespucci" +HUMLAB="Humane Labs and Research" +JAIL="Bolingbroke-Strafanstalt" +KOREAT="Little Seoul" +LACT="Land-Act-Stausee" +LAGO="Lago Zancudo" +LDAM="Land-Act-Staudamm" +LMESA="La Mesa" +LOSPUER="La Puerta" +LOSSF="Los Santos Freeway" +MGCR_1="South Los Santos" +MGSR_3="Raton Canyon" +MIRR="Mirror Park" +MORN="Morningwood" +MOVIE="Richards Majestic" +MTCHIL="Mount Chiliad" +MTGORDO="Mount Gordo" +MTJOSE="Mount Josiah" +MURRI="Murrieta Heights" +NCHU="North Chumash" +OBSERV="Galileo-Observatorium" +OCEANA="Pazifik" +PALCOV="Paleto Cove" +PALETO="Paleto Bay" +PALFOR="Paleto Forest" +PALHIGH="Palomino-Hochland" +PALMPOW="Palmer-Taylor-Elektrizitätswerk" +PBLUFF="Pacific Bluffs" +PBOX="Pillbox Hill" +PROCOB="Procopio Beach" +PROL="North Yankton" +RANCHO="Rancho" +RGLEN="Richman Glen" +RICHM="Richman" +ROCKF="Rockford Hills" +RTRAK="Redwood-Lights-Rennstrecke" +SANAND="San Andreas" +SANCHIA="San-Chianski-Bergkette" +SANDY="Sandy Shores" +SKID="Mission Row" +SLAB="Stab City" +SLSANT="South Los Santos" +STAD="Maze Bank Arena" +STRAW="Strawberry" +TATAMO="Tataviam-Bergkette" +TERMINA="Terminal" +TEXTI="Textilbezirk" +TONGVAH="Tongva Hills" +TONGVAV="Tongva Valley" +UTOPIAG="Utopia Gardens" +VCANA="Vespucci-Kanäle" +VESP="Vespucci" +VINE="Vinewood" +WINDF="Ron-Alternates-Windpark" +WMIRROR="West Mirror Drive" +WVINE="Vinewood West" +ZANCUDO="Zancudo River" +ZENORA="Senora Freeway" diff --git a/res/global.en.ini b/res/global.en.ini index 375c91c..4c31ad3 100755 --- a/res/global.en.ini +++ b/res/global.en.ini @@ -1,103 +1,103 @@ -[Global] -AIRP="Los Santos International Airport" -ALAMO="Alamo Sea" -ALTA="Alta" -ARMYB="Fort Zancudo" -BANNING="Banning" -BAYTRE="Baytree Canyon" -BEACH="Vespucci Beach" -BHAMCA="Banham Canyon" -BRADP="Braddock Pass" -BRADT="Braddock Tunnel" -BURTON="Burton" -CALAFB="Calafia Bridge" -CANNY="Raton Canyon" -CCREAK="Cassidy Creek" -CHAMH="Chamberlain Hills" -CHIL="Vinewood Hills" -CHU="Chumash" -CMSW="Chiliad Mountain State Wilderness" -COSI="Countryside" -CYPRE="Cypress Flats" -DAVIS="Davis" -DELBE="Del Perro Beach" -DELPE="Del Perro" -DELSOL="La Puerta" -DESRT="Grand Senora Desert" -DOWNT="Downtown" -DTVINE="Downtown Vinewood" -EAST_V="East Vinewood" -EBURO="El Burro Heights" -ECLIPS="Eclipse" -ELGORL="El Gordo Lighthouse" -ELSANT="East Los Santos" -ELYSIAN="Elysian Island" -GALFISH="Galilee" -GALLI="Galileo Park" -GOLF="GWC and Golfing Society" -GRAPES="Grapeseed" -GREATC="Great Chaparral" -HARMO="Harmony" -HAWICK="Hawick" -HEART="Heart Attacks Beach" -HORS="Vinewood Racetrack" -HUD_MG_TRI_ALA="Alamo Sea" -HUD_MG_TRI_VES="Vespucci" -HUMLAB="Humane Labs and Research" -JAIL="Bolingbroke Penitentiary" -KOREAT="Little Seoul" -LACT="Land Act Reservoir" -LAGO="Lago Zancudo" -LDAM="Land Act Dam" -LMESA="La Mesa" -LOSPUER="La Puerta" -LOSSF="Los Santos Freeway" -MGCR_1="South Los Santos" -MGCR_6="Vespucci Canals" -MGSR_3="Raton Canyon" -MIRR="Mirror Park" -MORN="Morningwood" -MOVIE="Richards Majestic" -MTCHIL="Mount Chiliad" -MTGORDO="Mount Gordo" -MTJOSE="Mount Josiah" -MURRI="Murrieta Heights" -NCHU="North Chumash" -OBSERV="Galileo Observatory" -OCEANA="Pacific Ocean" -PALCOV="Paleto Cove" -PALETO="Paleto Bay" -PALFOR="Paleto Forest" -PALHIGH="Palomino Highlands" -PALMPOW="Palmer-Taylor Power Station" -PBLUFF="Pacific Bluffs" -PBOX="Pillbox Hill" -PROCOB="Procopio Beach" -PROL="North Yankton" -RANCHO="Rancho" -RGLEN="Richman Glen" -RICHM="Richman" -ROCKF="Rockford Hills" -RTRAK="Redwood Lights Track" -SANAND="San Andreas" -SANCHIA="San Chianski Mountain Range" -SANDY="Sandy Shores" -SKID="Mission Row" -SLAB="Stab City" -SLSANT="South Los Santos" -STAD="Maze Bank Arena" -STRAW="Strawberry" -TATAMO="Tataviam Mountains" -TERMINA="Terminal" -TEXTI="Textile City" -TONGVAH="Tongva Hills" -TONGVAV="Tongva Valley" -UTOPIAG="Utopia Gardens" -VCANA="Vespucci Canals" -VESP="Vespucci" -VINE="Vinewood" -WINDF="Ron Alternates Wind Farm" -WMIRROR="West Mirror Drive" -WVINE="West Vinewood" -ZANCUDO="Zancudo River" -ZENORA="Senora Freeway" +[Global] +AIRP="Los Santos International Airport" +ALAMO="Alamo Sea" +ALTA="Alta" +ARMYB="Fort Zancudo" +BANNING="Banning" +BAYTRE="Baytree Canyon" +BEACH="Vespucci Beach" +BHAMCA="Banham Canyon" +BRADP="Braddock Pass" +BRADT="Braddock Tunnel" +BURTON="Burton" +CALAFB="Calafia Bridge" +CANNY="Raton Canyon" +CCREAK="Cassidy Creek" +CHAMH="Chamberlain Hills" +CHIL="Vinewood Hills" +CHU="Chumash" +CMSW="Chiliad Mountain State Wilderness" +COSI="Countryside" +CYPRE="Cypress Flats" +DAVIS="Davis" +DELBE="Del Perro Beach" +DELPE="Del Perro" +DELSOL="La Puerta" +DESRT="Grand Senora Desert" +DOWNT="Downtown" +DTVINE="Downtown Vinewood" +EAST_V="East Vinewood" +EBURO="El Burro Heights" +ECLIPS="Eclipse" +ELGORL="El Gordo Lighthouse" +ELSANT="East Los Santos" +ELYSIAN="Elysian Island" +GALFISH="Galilee" +GALLI="Galileo Park" +GOLF="GWC and Golfing Society" +GRAPES="Grapeseed" +GREATC="Great Chaparral" +HARMO="Harmony" +HAWICK="Hawick" +HEART="Heart Attacks Beach" +HORS="Vinewood Racetrack" +HUD_MG_TRI_ALA="Alamo Sea" +HUD_MG_TRI_VES="Vespucci" +HUMLAB="Humane Labs and Research" +JAIL="Bolingbroke Penitentiary" +KOREAT="Little Seoul" +LACT="Land Act Reservoir" +LAGO="Lago Zancudo" +LDAM="Land Act Dam" +LMESA="La Mesa" +LOSPUER="La Puerta" +LOSSF="Los Santos Freeway" +MGCR_1="South Los Santos" +MGCR_6="Vespucci Canals" +MGSR_3="Raton Canyon" +MIRR="Mirror Park" +MORN="Morningwood" +MOVIE="Richards Majestic" +MTCHIL="Mount Chiliad" +MTGORDO="Mount Gordo" +MTJOSE="Mount Josiah" +MURRI="Murrieta Heights" +NCHU="North Chumash" +OBSERV="Galileo Observatory" +OCEANA="Pacific Ocean" +PALCOV="Paleto Cove" +PALETO="Paleto Bay" +PALFOR="Paleto Forest" +PALHIGH="Palomino Highlands" +PALMPOW="Palmer-Taylor Power Station" +PBLUFF="Pacific Bluffs" +PBOX="Pillbox Hill" +PROCOB="Procopio Beach" +PROL="North Yankton" +RANCHO="Rancho" +RGLEN="Richman Glen" +RICHM="Richman" +ROCKF="Rockford Hills" +RTRAK="Redwood Lights Track" +SANAND="San Andreas" +SANCHIA="San Chianski Mountain Range" +SANDY="Sandy Shores" +SKID="Mission Row" +SLAB="Stab City" +SLSANT="South Los Santos" +STAD="Maze Bank Arena" +STRAW="Strawberry" +TATAMO="Tataviam Mountains" +TERMINA="Terminal" +TEXTI="Textile City" +TONGVAH="Tongva Hills" +TONGVAV="Tongva Valley" +UTOPIAG="Utopia Gardens" +VCANA="Vespucci Canals" +VESP="Vespucci" +VINE="Vinewood" +WINDF="Ron Alternates Wind Farm" +WMIRROR="West Mirror Drive" +WVINE="West Vinewood" +ZANCUDO="Zancudo River" +ZENORA="Senora Freeway" diff --git a/res/global.es.ini b/res/global.es.ini index b2d3cb6..dda46a7 100644 --- a/res/global.es.ini +++ b/res/global.es.ini @@ -1,107 +1,107 @@ -[Global] -AIRP="Aeropuerto Intl. de Los Santos" -ALAMO="Alamo Sea" -ALTA="Alta" -ARMYB="Fort Zancudo" -BANNING="Banning" -BAYTRE="Baytree Canyon" -BEACH="Vespucci Beach" -BHAMCA="Banham Canyon" -BRADP="Braddock Pass" -BRADT="Túnel de Braddock" -BURTON="Burton" -CALAFB="Puente de Calafia" -CANNY="Raton Canyon" -CCREAK="Cassidy Creek" -CHAMH="Chamberlain Hills" -CHIL="Vinewood Hills" -CHU="Chumash" -CMSW="Parque natural del monte Chiliad" -COSI="Zona rural" -CYPRE="Cypress Flats" -DAVIS="Davis" -DELBE="Del Perro Beach" -DELPE="Del Perro" -DELSOL="La Puerta" -DESRT="Desierto de Grand Señora" -DOWNT="Centro" -DTVINE="Centro de Vinewood" -EAST_V="Vinewood Este" -EBURO="El Burro Heights" -ECLIPS="Eclipse" -ELGORL="Faro de El Gordo" -ELSANT="Los Santos Este" -ELYSIAN="Elysian Island" -GALFISH="Galilee" -GALLI="Galileo Park" -GOLF="Club de campo y de golf GW" -GRAPES="Grapeseed" -GREATC="Great Chaparral" -HARMO="Harmony" -HAWICK="Hawick" -HEART="Heart Attacks Beach" -HORS="Circuito de Vinewood" -HUD_MG_TRI_ALA="Alamo Sea" -HUD_MG_TRI_VES="Vespucci" -HUMLAB="Laboratorios Humane" -JAIL="Penitenciaría de Bolingbroke" -KOREAT="Little Seoul" -LACT="Embalse de Land Act" -LAGO="Lago Zancudo" -LDAM="Presa de Land Act" -LMESA="La Mesa" -LOSPFY="Autopista de La Puerta" -LOSPUER="La Puerta" -LOSSF="Autopista de Los Santos" -MGCR_1="Los Santos Sur" -MGCR_6="Canales de Vespucci" -MGSR_3="Raton Canyon" -MIRR="Mirror Park" -MORN="Morningwood" -MOVIE="Richards Majestic" -MO_CS_HIGH="Alta" -MO_HIGH="Alta" -MTCHIL="Monte Chiliad" -MTGORDO="Monte Gordo" -MTJOSE="Monte Josiah" -MURRI="Murrieta Heights" -NCHU="Chumash Norte" -OBSERV="Observatorio Galileo" -OCEANA="Océano Pacífico" -PALCOV="Paleto Cove" -PALETO="Paleto Bay" -PALFOR="Bosque de Paleto" -PALHIGH="Palomino Highlands" -PALMPOW="Central eléctrica Palmer-Taylor" -PBLUFF="Pacific Bluffs" -PBOX="Pillbox Hill" -PROCOB="Procopio Beach" -PROL="North Yankton" -RANCHO="Rancho" -RGLEN="Richman Glen" -RICHM="Richman" -ROCKF="Rockford Hills" -RTRAK="Circuito Redwood Lights" -SANAND="San Andreas" -SANCHIA="Cordillera San Chianski" -SANDY="Sandy Shores" -SENORA="Autopista de Señora" -SKID="Mission Row" -SLAB="Stab City" -SLSANT="Los Santos Sur" -STAD="Maze Bank Arena" -STRAW="Strawberry" -TATAMO="Montañas Tataviam" -TERMINA="Terminal" -TEXTI="Textile City" -TONGVAH="Colinas de Tongva" -TONGVAV="Valle de Tongva" -UTOPIAG="Utopia Gardens" -VCANA="Canales de Vespucci" -VESP="Vespucci" -VINE="Vinewood" -WINDF="Granja eólica de Ron Alternates" -WMIRROR="West Mirror Drive" -WVINE="Vinewood Oeste" -ZANCUDO="Río Zancudo" -ZENORA="Autopista de Señora" +[Global] +AIRP="Aeropuerto Intl. de Los Santos" +ALAMO="Alamo Sea" +ALTA="Alta" +ARMYB="Fort Zancudo" +BANNING="Banning" +BAYTRE="Baytree Canyon" +BEACH="Vespucci Beach" +BHAMCA="Banham Canyon" +BRADP="Braddock Pass" +BRADT="Túnel de Braddock" +BURTON="Burton" +CALAFB="Puente de Calafia" +CANNY="Raton Canyon" +CCREAK="Cassidy Creek" +CHAMH="Chamberlain Hills" +CHIL="Vinewood Hills" +CHU="Chumash" +CMSW="Parque natural del monte Chiliad" +COSI="Zona rural" +CYPRE="Cypress Flats" +DAVIS="Davis" +DELBE="Del Perro Beach" +DELPE="Del Perro" +DELSOL="La Puerta" +DESRT="Desierto de Grand Señora" +DOWNT="Centro" +DTVINE="Centro de Vinewood" +EAST_V="Vinewood Este" +EBURO="El Burro Heights" +ECLIPS="Eclipse" +ELGORL="Faro de El Gordo" +ELSANT="Los Santos Este" +ELYSIAN="Elysian Island" +GALFISH="Galilee" +GALLI="Galileo Park" +GOLF="Club de campo y de golf GW" +GRAPES="Grapeseed" +GREATC="Great Chaparral" +HARMO="Harmony" +HAWICK="Hawick" +HEART="Heart Attacks Beach" +HORS="Circuito de Vinewood" +HUD_MG_TRI_ALA="Alamo Sea" +HUD_MG_TRI_VES="Vespucci" +HUMLAB="Laboratorios Humane" +JAIL="Penitenciaría de Bolingbroke" +KOREAT="Little Seoul" +LACT="Embalse de Land Act" +LAGO="Lago Zancudo" +LDAM="Presa de Land Act" +LMESA="La Mesa" +LOSPFY="Autopista de La Puerta" +LOSPUER="La Puerta" +LOSSF="Autopista de Los Santos" +MGCR_1="Los Santos Sur" +MGCR_6="Canales de Vespucci" +MGSR_3="Raton Canyon" +MIRR="Mirror Park" +MORN="Morningwood" +MOVIE="Richards Majestic" +MO_CS_HIGH="Alta" +MO_HIGH="Alta" +MTCHIL="Monte Chiliad" +MTGORDO="Monte Gordo" +MTJOSE="Monte Josiah" +MURRI="Murrieta Heights" +NCHU="Chumash Norte" +OBSERV="Observatorio Galileo" +OCEANA="Océano Pacífico" +PALCOV="Paleto Cove" +PALETO="Paleto Bay" +PALFOR="Bosque de Paleto" +PALHIGH="Palomino Highlands" +PALMPOW="Central eléctrica Palmer-Taylor" +PBLUFF="Pacific Bluffs" +PBOX="Pillbox Hill" +PROCOB="Procopio Beach" +PROL="North Yankton" +RANCHO="Rancho" +RGLEN="Richman Glen" +RICHM="Richman" +ROCKF="Rockford Hills" +RTRAK="Circuito Redwood Lights" +SANAND="San Andreas" +SANCHIA="Cordillera San Chianski" +SANDY="Sandy Shores" +SENORA="Autopista de Señora" +SKID="Mission Row" +SLAB="Stab City" +SLSANT="Los Santos Sur" +STAD="Maze Bank Arena" +STRAW="Strawberry" +TATAMO="Montañas Tataviam" +TERMINA="Terminal" +TEXTI="Textile City" +TONGVAH="Colinas de Tongva" +TONGVAV="Valle de Tongva" +UTOPIAG="Utopia Gardens" +VCANA="Canales de Vespucci" +VESP="Vespucci" +VINE="Vinewood" +WINDF="Granja eólica de Ron Alternates" +WMIRROR="West Mirror Drive" +WVINE="Vinewood Oeste" +ZANCUDO="Río Zancudo" +ZENORA="Autopista de Señora" diff --git a/res/global.fr.ini b/res/global.fr.ini index e2669d1..130709f 100644 --- a/res/global.fr.ini +++ b/res/global.fr.ini @@ -1,103 +1,103 @@ -[Global] -AIRP="Aéroport international de LS" -ALAMO="Alamo Sea" -ALTA="Alta" -ARMYB="Fort Zancudo" -BANNING="Banning" -BAYTRE="Baytree Canyon" -BEACH="Vespucci Beach" -BHAMCA="Banham Canyon" -BRADP="Braddock Pass" -BRADT="Braddock Tunnel" -BURTON="Burton" -CALAFB="Calafia Bridge" -CANNY="Raton Canyon" -CCREAK="Cassidy Creek" -CHAMH="Chamberlain Hills" -CHIL="Vinewood Hills" -CHU="Chumash" -CMSW="Parc national du Mont Chiliad" -CYPRE="Cypress Flats" -DAVIS="Davis" -DELBE="Del Perro Beach" -DELPE="Del Perro" -DELSOL="La Puerta" -DESRT="Grand Señora Desert" -DOWNT="Centre-ville" -DTVINE="Centre de Vinewood" -EAST_V="Vinewood East" -EBURO="El Burro Heights" -ECLIPS="Eclipse" -ELGORL="Phare d'El Gordo" -ELSANT="East Los Santos" -ELYSIAN="Elysian Island" -GALFISH="Galilee" -GALLI="Galileo Park" -GOLF="Club de golf et de détente du Grand Ouest" -GRAPES="Grapeseed" -GREATC="Great Chaparral" -HARMO="Harmony" -HAWICK="Hawick" -HEART="Heart Attacks Beach" -HORS="Hippodrome de Vinewood" -HUD_MG_TRI_ALA="Alamo Sea" -HUD_MG_TRI_VES="Vespucci" -HUMLAB="Laboratoires Humane" -JAIL="Pénitencier de Bolingbroke" -KOREAT="Little Seoul" -LACT="Land Act Reservoir" -LAGO="Lago Zancudo" -LDAM="Land Act Dam" -LMESA="La Mesa" -LOSPFY="La Puerta Freeway" -LOSPUER="La Puerta" -LOSSF="Los Santos Freeway" -MGCR_1="South Los Santos" -MGCR_6="Canaux de Vespucci" -MGSR_3="Raton Canyon" -MIRR="Mirror Park" -MORN="Morningwood" -MOVIE="Richards Majestic" -MTCHIL="Mont Chiliad" -MTGORDO="Mont Gordo" -MTJOSE="Mont Josiah" -MURRI="Murrieta Heights" -NCHU="North Chumash" -OBSERV="Observatoire Galileo" -OCEANA="Océan pacifique" -PALCOV="Paleto Cove" -PALETO="Paleto Bay" -PALFOR="Paleto Forest" -PALHIGH="Palomino Highlands" -PALMPOW="Centrale Palmer-Taylor" -PBLUFF="Pacific Bluffs" -PBOX="Pillbox Hill" -PROCOB="Procopio Beach" -PROL="North Yankton" -RANCHO="Rancho" -RGLEN="Richman Glen" -RICHM="Richman" -ROCKF="Rockford Hills" -RTRAK="Circuit Redwood Lights" -SANAND="San Andreas" -SANCHIA="Monts de San Chianski" -SANDY="Sandy Shores" -SKID="Mission Row" -SLAB="Stab City" -SLSANT="South Los Santos" -STAD="Maze Bank Arena" -STRAW="Strawberry" -TATAMO="Monts Tataviam" -TERMINA="Terminal" -TEXTI="Textile City" -TONGVAH="Tongva Hills" -TONGVAV="Tongva Valley" -UTOPIAG="Utopia Gardens" -VCANA="Canaux de Vespucci" -VESP="Vespucci" -VINE="Vinewood" -WINDF="Parc d'éoliennes Ron Alternates" -WMIRROR="Mirror Drive West" -WVINE="Vinewood West" -ZANCUDO="Zancudo River" -ZENORA="Señora Freeway" +[Global] +AIRP="Aéroport international de LS" +ALAMO="Alamo Sea" +ALTA="Alta" +ARMYB="Fort Zancudo" +BANNING="Banning" +BAYTRE="Baytree Canyon" +BEACH="Vespucci Beach" +BHAMCA="Banham Canyon" +BRADP="Braddock Pass" +BRADT="Braddock Tunnel" +BURTON="Burton" +CALAFB="Calafia Bridge" +CANNY="Raton Canyon" +CCREAK="Cassidy Creek" +CHAMH="Chamberlain Hills" +CHIL="Vinewood Hills" +CHU="Chumash" +CMSW="Parc national du Mont Chiliad" +CYPRE="Cypress Flats" +DAVIS="Davis" +DELBE="Del Perro Beach" +DELPE="Del Perro" +DELSOL="La Puerta" +DESRT="Grand Señora Desert" +DOWNT="Centre-ville" +DTVINE="Centre de Vinewood" +EAST_V="Vinewood East" +EBURO="El Burro Heights" +ECLIPS="Eclipse" +ELGORL="Phare d'El Gordo" +ELSANT="East Los Santos" +ELYSIAN="Elysian Island" +GALFISH="Galilee" +GALLI="Galileo Park" +GOLF="Club de golf et de détente du Grand Ouest" +GRAPES="Grapeseed" +GREATC="Great Chaparral" +HARMO="Harmony" +HAWICK="Hawick" +HEART="Heart Attacks Beach" +HORS="Hippodrome de Vinewood" +HUD_MG_TRI_ALA="Alamo Sea" +HUD_MG_TRI_VES="Vespucci" +HUMLAB="Laboratoires Humane" +JAIL="Pénitencier de Bolingbroke" +KOREAT="Little Seoul" +LACT="Land Act Reservoir" +LAGO="Lago Zancudo" +LDAM="Land Act Dam" +LMESA="La Mesa" +LOSPFY="La Puerta Freeway" +LOSPUER="La Puerta" +LOSSF="Los Santos Freeway" +MGCR_1="South Los Santos" +MGCR_6="Canaux de Vespucci" +MGSR_3="Raton Canyon" +MIRR="Mirror Park" +MORN="Morningwood" +MOVIE="Richards Majestic" +MTCHIL="Mont Chiliad" +MTGORDO="Mont Gordo" +MTJOSE="Mont Josiah" +MURRI="Murrieta Heights" +NCHU="North Chumash" +OBSERV="Observatoire Galileo" +OCEANA="Océan pacifique" +PALCOV="Paleto Cove" +PALETO="Paleto Bay" +PALFOR="Paleto Forest" +PALHIGH="Palomino Highlands" +PALMPOW="Centrale Palmer-Taylor" +PBLUFF="Pacific Bluffs" +PBOX="Pillbox Hill" +PROCOB="Procopio Beach" +PROL="North Yankton" +RANCHO="Rancho" +RGLEN="Richman Glen" +RICHM="Richman" +ROCKF="Rockford Hills" +RTRAK="Circuit Redwood Lights" +SANAND="San Andreas" +SANCHIA="Monts de San Chianski" +SANDY="Sandy Shores" +SKID="Mission Row" +SLAB="Stab City" +SLSANT="South Los Santos" +STAD="Maze Bank Arena" +STRAW="Strawberry" +TATAMO="Monts Tataviam" +TERMINA="Terminal" +TEXTI="Textile City" +TONGVAH="Tongva Hills" +TONGVAV="Tongva Valley" +UTOPIAG="Utopia Gardens" +VCANA="Canaux de Vespucci" +VESP="Vespucci" +VINE="Vinewood" +WINDF="Parc d'éoliennes Ron Alternates" +WMIRROR="Mirror Drive West" +WVINE="Vinewood West" +ZANCUDO="Zancudo River" +ZENORA="Señora Freeway" diff --git a/res/global.ja.ini b/res/global.ja.ini index 24ad7d2..366e294 100755 --- a/res/global.ja.ini +++ b/res/global.ja.ini @@ -1,106 +1,106 @@ -[Global] -AIRP="ロスサントス国際空港" -ALAMO="アラモ海" -ALTA="アルタ" -ARMYB="フォート・ザンクード" -BANNING="バニング" -BAYTRE="ベイツリー・キャニオン" -BEACH="ベスプッチ・ビーチ" -BHAMCA="バンナムキャニオン" -BRADP="ブラドック・パス" -BRADT="ブラドック・トンネル" -BSS_BSTR_131="リチャーズ・マジェスティック" -BURTON="バートン" -CALAFB="カラフィア橋" -CANNY="ラトン・キャニオン" -CCREAK="キャシディ・クリーク" -CHAMH="チェンバーレイン・ヒルズ" -CHIL="バインウッド・ヒルズ" -CHU="チュマシュ" -CMSW="チリアド山自然保護区" -COSI="農園地帯" -CYPRE="サイプレス・フラット" -DAVIS="デイビス" -DELBE="デル・ペロ・ビーチ" -DELPE="デル・ペロ" -DELSOL="ラ・プエルタ" -DESRT="グランド・セノーラ砂漠" -DOWNT="ダウンタウン" -DTVINE="ダウンタウン・バインウッド" -EAST_V="イースト・バインウッド" -EBURO="エル・ブロ・ハイツ" -ECLIPS="イクリプス" -ELGORL="エル・ゴルド灯台" -ELSANT="イースト・ロスサントス" -ELYSIAN="エリシアン島" -GALFISH="ガリラヤ" -GALLI="ガリレオ・パーク" -GOLF="GWC&ゴルフ協会" -GRAPES="グレイプシード" -GREATC="グレート・チャパレル" -HARMO="ハーモニー" -HAWICK="ハウィック" -HEART="ハートアタック・ビーチ" -HORS="バインウッド・レーストラック" -HUD_MG_TRI_ALA="アラモ海" -HUD_MG_TRI_VES="ベスプッチ" -HUMLAB="ヒューメイン研究所" -JAIL="ボーリングブローク刑務所" -KOREAT="リトル・ソウル" -LACT="ランド・アクト貯水池" -LAGO="ラゴ・ザンクード" -LDAM="ランド・アクト・ダム" -LMESA="ラ・メサ" -LOSPFY="ラ・プエルタ高速道路" -LOSPUER="ラ・プエルタ" -LOSSF="ロスサントス高速道路" -MGCR_1="サウス・ロスサントス" -MGCR_6="ベスプッチ運河" -MGSR_3="ラトン・キャニオン" -MIRR="ミラー・パーク" -MORN="モーニングウッド" -MOVIE="リチャーズ・マジェスティック" -MTCHIL="チリアド山" -MTGORDO="ゴルド山" -MTJOSE="ジョサイア山" -MURRI="ムリエタ・ハイツ" -NCHU="北チュマシュ" -OBSERV="ガリレオ観測所" -OCEANA="太平洋" -PALCOV="パレト・コーブ" -PALETO="パレト・ベイ" -PALFOR="パレト・フォレスト" -PALHIGH="パロミノ高地" -PALMPOW="パーマー・テイラー発電所" -PBLUFF="パシフィック・ブラフス" -PBOX="ピルボックス・ヒル" -PROCOB="プロコピオ・ビーチ" -PROL="ノース・ヤンクトン" -RANCHO="ランチョ" -RGLEN="リッチマン・グレン" -RICHM="リッチマン" -ROCKF="ロックフォード・ヒルズ" -RTRAK="レッドウッド・ライト・トラック" -SANAND="サンアンドレアス" -SANCHIA="サン・チアンスキー山脈" -SANDY="サンディ海岸" -SENORA="セノーラ高速道路" -SKID="ミッション・ロウ" -SLAB="スタブシティ" -SLSANT="サウス・ロスサントス" -STAD="メイズバンク・アリーナ" -STRAW="ストロベリー" -TATAMO="タタヴィアム山地" -TERMINA="ターミナル" -TEXTI="テキスタイルシティ" -TONGVAH="トングバ・ヒルズ" -TONGVAV="トングバ・バレー" -UTOPIAG="ユートピア・ガーデンズ" -VCANA="ベスプッチ運河" -VESP="ベスプッチ" -VINE="バインウッド" -WINDF="ロン・オルタネット・ウィンドファーム" -WMIRROR="ウエスト・ミラー・ドライブ" -WVINE="ウエスト・バインウッド" -ZANCUDO="ザンクード川" -ZENORA="セノーラ高速道路" +[Global] +AIRP="ロスサントス国際空港" +ALAMO="アラモ海" +ALTA="アルタ" +ARMYB="フォート・ザンクード" +BANNING="バニング" +BAYTRE="ベイツリー・キャニオン" +BEACH="ベスプッチ・ビーチ" +BHAMCA="バンナムキャニオン" +BRADP="ブラドック・パス" +BRADT="ブラドック・トンネル" +BSS_BSTR_131="リチャーズ・マジェスティック" +BURTON="バートン" +CALAFB="カラフィア橋" +CANNY="ラトン・キャニオン" +CCREAK="キャシディ・クリーク" +CHAMH="チェンバーレイン・ヒルズ" +CHIL="バインウッド・ヒルズ" +CHU="チュマシュ" +CMSW="チリアド山自然保護区" +COSI="農園地帯" +CYPRE="サイプレス・フラット" +DAVIS="デイビス" +DELBE="デル・ペロ・ビーチ" +DELPE="デル・ペロ" +DELSOL="ラ・プエルタ" +DESRT="グランド・セノーラ砂漠" +DOWNT="ダウンタウン" +DTVINE="ダウンタウン・バインウッド" +EAST_V="イースト・バインウッド" +EBURO="エル・ブロ・ハイツ" +ECLIPS="イクリプス" +ELGORL="エル・ゴルド灯台" +ELSANT="イースト・ロスサントス" +ELYSIAN="エリシアン島" +GALFISH="ガリラヤ" +GALLI="ガリレオ・パーク" +GOLF="GWC&ゴルフ協会" +GRAPES="グレイプシード" +GREATC="グレート・チャパレル" +HARMO="ハーモニー" +HAWICK="ハウィック" +HEART="ハートアタック・ビーチ" +HORS="バインウッド・レーストラック" +HUD_MG_TRI_ALA="アラモ海" +HUD_MG_TRI_VES="ベスプッチ" +HUMLAB="ヒューメイン研究所" +JAIL="ボーリングブローク刑務所" +KOREAT="リトル・ソウル" +LACT="ランド・アクト貯水池" +LAGO="ラゴ・ザンクード" +LDAM="ランド・アクト・ダム" +LMESA="ラ・メサ" +LOSPFY="ラ・プエルタ高速道路" +LOSPUER="ラ・プエルタ" +LOSSF="ロスサントス高速道路" +MGCR_1="サウス・ロスサントス" +MGCR_6="ベスプッチ運河" +MGSR_3="ラトン・キャニオン" +MIRR="ミラー・パーク" +MORN="モーニングウッド" +MOVIE="リチャーズ・マジェスティック" +MTCHIL="チリアド山" +MTGORDO="ゴルド山" +MTJOSE="ジョサイア山" +MURRI="ムリエタ・ハイツ" +NCHU="北チュマシュ" +OBSERV="ガリレオ観測所" +OCEANA="太平洋" +PALCOV="パレト・コーブ" +PALETO="パレト・ベイ" +PALFOR="パレト・フォレスト" +PALHIGH="パロミノ高地" +PALMPOW="パーマー・テイラー発電所" +PBLUFF="パシフィック・ブラフス" +PBOX="ピルボックス・ヒル" +PROCOB="プロコピオ・ビーチ" +PROL="ノース・ヤンクトン" +RANCHO="ランチョ" +RGLEN="リッチマン・グレン" +RICHM="リッチマン" +ROCKF="ロックフォード・ヒルズ" +RTRAK="レッドウッド・ライト・トラック" +SANAND="サンアンドレアス" +SANCHIA="サン・チアンスキー山脈" +SANDY="サンディ海岸" +SENORA="セノーラ高速道路" +SKID="ミッション・ロウ" +SLAB="スタブシティ" +SLSANT="サウス・ロスサントス" +STAD="メイズバンク・アリーナ" +STRAW="ストロベリー" +TATAMO="タタヴィアム山地" +TERMINA="ターミナル" +TEXTI="テキスタイルシティ" +TONGVAH="トングバ・ヒルズ" +TONGVAV="トングバ・バレー" +UTOPIAG="ユートピア・ガーデンズ" +VCANA="ベスプッチ運河" +VESP="ベスプッチ" +VINE="バインウッド" +WINDF="ロン・オルタネット・ウィンドファーム" +WMIRROR="ウエスト・ミラー・ドライブ" +WVINE="ウエスト・バインウッド" +ZANCUDO="ザンクード川" +ZENORA="セノーラ高速道路" diff --git a/res/global.zh.ini b/res/global.zh.ini index 3990a2f..35564bd 100644 --- a/res/global.zh.ini +++ b/res/global.zh.ini @@ -1,104 +1,104 @@ -[Global] -AIRP="洛聖都國際機場" -ALAMO="阿拉莫海" -ALTA="艾爾塔" -ARMYB="桑庫多堡壘" -BANNING="班寧" -BAYTRE="貝特里峽谷" -BEACH="威斯普奇海灘" -BHAMCA="班漢峽谷" -BRADP="布萊杜要道" -BRADT="布萊杜隧道" -BURTON="巴頓" -CALAFB="卡拉非橋" -CANNY="雷通峽谷" -CCREAK="加斯迪小溪" -CHAMH="張伯倫山" -CHIL="好麥塢山" -CHU="丘瑪墟" -CMSW="奇力耶德山國家生態保護區" -CYPRE="扁柏平地" -DAVIS="戴維斯" -DELBE="佩羅海灘" -DELPE="佩羅" -DELSOL="洛波塔" -DESRT="塞諾拉大沙漠" -DOWNT="市中心" -DTVINE="好麥塢市中心" -EAST_V="東好麥塢" -EBURO="布羅高地" -ECLIPS="日蝕" -ELGORL="戈多燈塔" -ELSANT="東洛聖都" -ELYSIAN="安樂島" -GALFISH="加利利" -GALLI="伽利略公園" -GOLF="西部鄉村高爾夫俱樂部" -GRAPES="葡萄籽" -GREATC="大叢林" -HARMO="和美尼" -HAWICK="霍伊克" -HEART="驚心海灘" -HORS="好麥塢賽馬場" -HUD_MG_TRI_ALA="阿拉莫海" -HUD_MG_TRI_VES="威斯普奇" -HUMLAB="人道研究實驗室" -JAIL="博林布魯克監獄" -KOREAT="小首爾" -LACT="蘭艾水庫" -LAGO="桑庫多沼地" -LDAM="蘭艾水壩" -LMESA="梅薩" -LOSPFY="洛波塔高速公路" -LOSPUER="洛波塔" -LOSSF="洛聖都高速公路" -MGCR_1="南洛聖都" -MGCR_6="威斯普奇運河" -MGSR_3="雷通峽谷" -MIRR="米羅公園" -MORN="摩寧塢" -MOVIE="李察尊爵" -MTCHIL="奇力耶德山" -MTGORDO="戈多山" -MTJOSE="尤夏山" -MURRI="穆瑞塔高地" -NCHU="北丘瑪墟" -OBSERV="伽利略天文台" -OCEANA="太平洋" -PALCOV="佩立托小海灣" -PALETO="佩立托灣" -PALFOR="佩立托森林" -PALHIGH="巴洛米諾高地" -PALMPOW="帕莫泰勒發電站" -PBLUFF="太平崖" -PBOX="圓帽山" -PROCOB="普羅科皮奧海灘" -PROL="北揚克頓" -RANCHO="藍丘" -RGLEN="利金漫幽谷" -RICHM="利金漫" -ROCKF="羅克福德山" -RTRAK="紅木賽道" -SANAND="聖安地列斯" -SANCHIA="聖強斯基山脈" -SANDY="沙灘海岸" -SENORA="塞諾拉高速公路" -SKID="密申羅" -SLAB="背刺城" -SLSANT="南洛聖都" -STAD="花園銀行體育場" -STRAW="斯卓貝利" -TATAMO="塔塔維昂山" -TERMINA="碼頭" -TEXTI="紡織城" -TONGVAH="通瓦山" -TONGVAV="通瓦谷地" -UTOPIAG="烏托邦花園" -VCANA="威斯普奇運河" -VESP="威斯普奇" -VINE="好麥塢" -WINDF="朗恩.艾特梅茲風車農場" -WMIRROR="米羅車道西段" -WVINE="西好麥塢" -ZANCUDO="桑庫多河" -ZENORA="塞諾拉高速公路" +[Global] +AIRP="洛聖都國際機場" +ALAMO="阿拉莫海" +ALTA="艾爾塔" +ARMYB="桑庫多堡壘" +BANNING="班寧" +BAYTRE="貝特里峽谷" +BEACH="威斯普奇海灘" +BHAMCA="班漢峽谷" +BRADP="布萊杜要道" +BRADT="布萊杜隧道" +BURTON="巴頓" +CALAFB="卡拉非橋" +CANNY="雷通峽谷" +CCREAK="加斯迪小溪" +CHAMH="張伯倫山" +CHIL="好麥塢山" +CHU="丘瑪墟" +CMSW="奇力耶德山國家生態保護區" +CYPRE="扁柏平地" +DAVIS="戴維斯" +DELBE="佩羅海灘" +DELPE="佩羅" +DELSOL="洛波塔" +DESRT="塞諾拉大沙漠" +DOWNT="市中心" +DTVINE="好麥塢市中心" +EAST_V="東好麥塢" +EBURO="布羅高地" +ECLIPS="日蝕" +ELGORL="戈多燈塔" +ELSANT="東洛聖都" +ELYSIAN="安樂島" +GALFISH="加利利" +GALLI="伽利略公園" +GOLF="西部鄉村高爾夫俱樂部" +GRAPES="葡萄籽" +GREATC="大叢林" +HARMO="和美尼" +HAWICK="霍伊克" +HEART="驚心海灘" +HORS="好麥塢賽馬場" +HUD_MG_TRI_ALA="阿拉莫海" +HUD_MG_TRI_VES="威斯普奇" +HUMLAB="人道研究實驗室" +JAIL="博林布魯克監獄" +KOREAT="小首爾" +LACT="蘭艾水庫" +LAGO="桑庫多沼地" +LDAM="蘭艾水壩" +LMESA="梅薩" +LOSPFY="洛波塔高速公路" +LOSPUER="洛波塔" +LOSSF="洛聖都高速公路" +MGCR_1="南洛聖都" +MGCR_6="威斯普奇運河" +MGSR_3="雷通峽谷" +MIRR="米羅公園" +MORN="摩寧塢" +MOVIE="李察尊爵" +MTCHIL="奇力耶德山" +MTGORDO="戈多山" +MTJOSE="尤夏山" +MURRI="穆瑞塔高地" +NCHU="北丘瑪墟" +OBSERV="伽利略天文台" +OCEANA="太平洋" +PALCOV="佩立托小海灣" +PALETO="佩立托灣" +PALFOR="佩立托森林" +PALHIGH="巴洛米諾高地" +PALMPOW="帕莫泰勒發電站" +PBLUFF="太平崖" +PBOX="圓帽山" +PROCOB="普羅科皮奧海灘" +PROL="北揚克頓" +RANCHO="藍丘" +RGLEN="利金漫幽谷" +RICHM="利金漫" +ROCKF="羅克福德山" +RTRAK="紅木賽道" +SANAND="聖安地列斯" +SANCHIA="聖強斯基山脈" +SANDY="沙灘海岸" +SENORA="塞諾拉高速公路" +SKID="密申羅" +SLAB="背刺城" +SLSANT="南洛聖都" +STAD="花園銀行體育場" +STRAW="斯卓貝利" +TATAMO="塔塔維昂山" +TERMINA="碼頭" +TEXTI="紡織城" +TONGVAH="通瓦山" +TONGVAV="通瓦谷地" +UTOPIAG="烏托邦花園" +VCANA="威斯普奇運河" +VESP="威斯普奇" +VINE="好麥塢" +WINDF="朗恩.艾特梅茲風車農場" +WMIRROR="米羅車道西段" +WVINE="西好麥塢" +ZANCUDO="桑庫多河" +ZENORA="塞諾拉高速公路" diff --git a/res/gta5sync_de.qm b/res/gta5sync_de.qm index 0890c945326032de167ca1c2e830ea69c3d3a935..8b620e235c46595c44bc1cd69094c173ea6a9d75 100755 GIT binary patch delta 5031 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 Lj2UwJ9+&?w_pB=Q delta 3498 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 IKD}7<Z!f3N0{{R3 diff --git a/res/gta5sync_de.ts b/res/gta5sync_de.ts index ec70f48..6fcde10 100755 --- a/res/gta5sync_de.ts +++ b/res/gta5sync_de.ts @@ -147,51 +147,63 @@ Copyright &copy; <a href="%5">%6</a> %7<br/>%8 i <translation type="obsolete"><span style=" font-weight:600;">gta5sync</span><br/><br/>Ein Projekt zum ansehen und synchronisieren von Grand Theft Auto 5 Snapmatic Bilder und Spielständen<br/><br/>Projektversion: %1<br/>Gebaut mit Qt %2<br/>Läuft auf Qt %3<br/><br/>Copyright &copy; <a href="https://github.com/Syping/">Syping</a> 2016<br/>gta5sync is lizenziert unter <a href="https://www.gnu.org/licenses/gpl-3.0.html#content">GNU GPLv3</a></translation> </message> <message> + <location filename="../AboutDialog.cpp" line="41"/> <source>Using %1 %2</source> + <extracomment>Using specific library, example Using libmyfuck</extracomment> + <translation>Verwendet %1 %2</translation> + </message> + <message> + <location filename="../AboutDialog.cpp" line="43"/> + <source>Translated by %1</source> + <extracomment>Translated by translator, example Translated by Syping</extracomment> + <translation>Übersetzt von %1</translation> + </message> + <message> + <source>Using %1 %2</source> + <comment>Exp. Using libmyfuck</comment> <translation type="vanished">Verwendet %1 %2</translation> </message> <message> <source>Translated by %1</source> + <comment>Exp. Translated by Syping</comment> <translation type="vanished">Übersetzt von %1</translation> </message> <message> - <location filename="../AboutDialog.cpp" line="40"/> - <source>Using %1 %2</source> - <comment>Exp. Using libmyfuck</comment> - <translation>Verwendet %1 %2</translation> - </message> - <message> - <location filename="../AboutDialog.cpp" line="41"/> - <source>Translated by %1</source> - <comment>Exp. Translated by Syping</comment> - <translation>Übersetzt von %1</translation> - </message> - <message> - <location filename="../AboutDialog.cpp" line="42"/> <source>NAME_OF_TRANSLATOR</source> <comment>Your Name (The person behind your screen looking at this text!)</comment> + <translation type="vanished">Syping</translation> + </message> + <message> + <source>TRANSLATOR_PROFILE</source> + <comment>mailto: http:// https:// Exp. https://github.com/Syping/</comment> + <translation type="vanished">https://github.com/Syping/</translation> + </message> + <message> + <location filename="../AboutDialog.cpp" line="45"/> + <source>NAME_OF_TRANSLATOR</source> + <extracomment>Enter your name there</extracomment> <translation>Syping</translation> </message> <message> - <location filename="../AboutDialog.cpp" line="43"/> + <location filename="../AboutDialog.cpp" line="47"/> <source>TRANSLATOR_PROFILE</source> - <comment>mailto: http:// https:// Exp. https://github.com/Syping/</comment> + <extracomment>Enter your proilfe there, example a GitHub profile, E-Mail with "mailto: afucker@sumfuck.com" or a webpage</extracomment> <translation>https://github.com/Syping/</translation> </message> <message> - <location filename="../AboutDialog.cpp" line="64"/> + <location filename="../AboutDialog.cpp" line="80"/> <source>A project for viewing Grand Theft Auto V Snapmatic<br/> Pictures and Savegames</source> <translation>Ein Projekt zum ansehen von Grand Theft Auto V<br/> Snapmatic Bilder und Spielständen</translation> </message> <message> - <location filename="../AboutDialog.cpp" line="68"/> + <location filename="../AboutDialog.cpp" line="84"/> <source>Copyright &copy; <a href="%1">%2</a> %3</source> <translation>Copyright &copy; <a href="%1">%2</a> %3</translation> </message> <message> - <location filename="../AboutDialog.cpp" line="70"/> + <location filename="../AboutDialog.cpp" line="86"/> <source>%1 is licensed under <a href="https://www.gnu.org/licenses/gpl-3.0.html#content">GNU GPLv3</a></source> <translation>%1 ist lizenziert unter <a href="https://www.gnu.org/licenses/gpl-3.0.html#content">GNU GPLv3</a></translation> </message> @@ -200,17 +212,47 @@ Snapmatic Bilder und Spielständen</translation> <translation type="vanished">Copyright &copy; <a href="%1">%2</a> %3<br/>%4 ist lizenziert unter <a href="https://www.gnu.org/licenses/gpl-3.0.html#content">GNU GPLv3</a></translation> </message> <message> - <location filename="../AboutDialog.cpp" line="62"/> + <location filename="../AboutDialog.cpp" line="78"/> <source>A project for viewing and sync Grand Theft Auto V Snapmatic<br/> Pictures and Savegames</source> <translation>Ein Projekt zum ansehen und synchronisieren von<br/> Grand Theft Auto V Snapmatic Bilder und Spielständen</translation> </message> + <message> + <location filename="../config.h" line="62"/> + <source>Release</source> + <translation>Release</translation> + </message> + <message> + <location filename="../config.h" line="68"/> + <source>Release Candidate</source> + <translation>Release Candidate</translation> + </message> + <message> + <location filename="../config.h" line="74"/> + <source>Daily Build</source> + <translation>Daily Build</translation> + </message> + <message> + <location filename="../config.h" line="80"/> + <source>Developer</source> + <translation>Entwickler</translation> + </message> + <message> + <location filename="../config.h" line="86"/> + <source>Beta</source> + <translation>Beta</translation> + </message> + <message> + <location filename="../config.h" line="92"/> + <source>Alpha</source> + <translation>Alpha</translation> + </message> </context> <context> <name>CrewDatabase</name> <message> - <location filename="../CrewDatabase.cpp" line="64"/> + <location filename="../CrewDatabase.cpp" line="102"/> <source>No Crew</source> <translation>Keine Crew</translation> </message> @@ -305,30 +347,110 @@ Grand Theft Auto V Snapmatic Bilder und Spielständen</translation> <translation>Einstellungen</translation> </message> <message> - <location filename="../ImportDialog.ui" line="96"/> <source>&Keep Aspect Ratio</source> - <translation>Seitenverhältnis &behalten</translation> + <translation type="vanished">Seitenverhältnis &behalten</translation> </message> <message> - <location filename="../ImportDialog.ui" line="103"/> <source>&Ignore Aspect Ratio</source> - <translation>Seitenverhältnis &ignorieren</translation> + <translation type="vanished">Seitenverhältnis &ignorieren</translation> </message> <message> - <location filename="../ImportDialog.ui" line="110"/> <source>&Avatar</source> - <translation>&Avatar</translation> + <translation type="vanished">&Avatar</translation> </message> <message> - <location filename="../ImportDialog.ui" line="154"/> + <source>Keep Aspect Ratio</source> + <translation type="vanished">Seitenverhältnis behalten</translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="148"/> + <source>Ignore Aspect Ratio</source> + <translation>Seitenverhältnis ignorieren</translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="135"/> + <source>Avatar</source> + <translation>Avatar</translation> + </message> + <message> + <source>Background Colour: <span style="color:rgb(%1,%2,%3)">%4</span></source> + <translation type="vanished">Hintergrundfarbe: <span style="color:rgb(%1,%2,%3)">%4</span></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="98"/> + <location filename="../ImportDialog.cpp" line="57"/> + <location filename="../ImportDialog.cpp" line="216"/> + <source>Background Colour: <span style="color: %1">%1</span></source> + <translation>Hintergrundfarbe: <span style="color: %1">%1</span></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="105"/> + <source>...</source> + <translation>...</translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="194"/> + <source>Import picture</source> + <translation>Bild importieren</translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="197"/> <source>&OK</source> <translation>&OK</translation> </message> <message> - <location filename="../ImportDialog.ui" line="167"/> + <location filename="../ImportDialog.ui" line="210"/> + <source>Discard picture</source> + <translation>Bild verwerfen</translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="213"/> <source>&Cancel</source> <translation>Abbre&chen</translation> </message> + <message> + <source>Select Colour</source> + <translation type="vanished">Farbe auswählen</translation> + </message> + <message> + <source>Are you sure to use a square image outside of the Avatar Zone? +When you plan to use it as Avatar the picture will be cut!</source> + <translation type="vanished">Bist du sicher ein Quadrat Bild außerhalb der Avatar Zone zu verwenden? +Wenn du planst es als Avatar zu verwenden das Bild wird abgetrennt!</translation> + </message> + <message> + <location filename="../ImportDialog.cpp" line="173"/> + <source>Are you sure to use a square image outside of the Avatar Zone? +When you want to use it as Avatar the image will be detached!</source> + <translation>Bist du sicher ein Quadrat Bild außerhalb der Avatar Zone zu verwenden? +Wenn du es als Avatar verwenden möchtest wird es abgetrennt!</translation> + </message> + <message> + <location filename="../ImportDialog.cpp" line="173"/> + <source>Snapmatic Avatar Zone</source> + <translation>Snapmatic Avatar Zone</translation> + </message> + <message> + <location filename="../ImportDialog.cpp" line="212"/> + <source>Select Colour...</source> + <translation>Farbe auswählen...</translation> + </message> +</context> +<context> + <name>MapPreviewDialog</name> + <message> + <source>Map Preview</source> + <translation type="vanished">Map Vorschau</translation> + </message> + <message> + <source>Snapmatic Coordinate Viewer</source> + <translation type="vanished">Snapmatic Koordinatenansicht</translation> + </message> + <message> + <location filename="../MapPreviewDialog.ui" line="26"/> + <source>Snapmatic Map Viewer</source> + <translation>Snapmatic Kartenansicht</translation> + </message> </context> <context> <name>OptionsDialog</name> @@ -509,12 +631,22 @@ Grand Theft Auto V Snapmatic Bilder und Spielständen</translation> </message> <message> <location filename="../OptionsDialog.ui" line="463"/> + <source>Apply changes</source> + <translation>Änderungen übernehmen</translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="466"/> <source>&OK</source> <extracomment>OK, Cancel, Apply</extracomment> <translation>&OK</translation> </message> <message> - <location filename="../OptionsDialog.ui" line="476"/> + <location filename="../OptionsDialog.ui" line="479"/> + <source>Discard changes</source> + <translation>Änderungen verwerfen</translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="482"/> <source>&Cancel</source> <extracomment>OK, Cancel, Apply</extracomment> <translation>Abbre&chen</translation> @@ -525,48 +657,60 @@ Grand Theft Auto V Snapmatic Bilder und Spielständen</translation> <translation type="obsolete">%1 (%2 wenn verfügbar) [sys]</translation> </message> <message> - <location filename="../OptionsDialog.cpp" line="133"/> <source>System</source> <comment>System like PC System</comment> - <translation>System</translation> + <translation type="vanished">System</translation> </message> <message> - <location filename="../OptionsDialog.cpp" line="133"/> <source>%1 (%2 if available)</source> <comment>System like PC System = %1, System Language like Deutsch = %2</comment> - <translation>%1 (%2 wenn verfügbar)</translation> + <translation type="vanished">%1 (%2 wenn verfügbar)</translation> </message> <message> - <location filename="../OptionsDialog.cpp" line="292"/> - <location filename="../OptionsDialog.cpp" line="296"/> + <location filename="../OptionsDialog.cpp" line="289"/> <source>%1</source> <comment>%1</comment> <translation>%1</translation> </message> <message> - <location filename="../OptionsDialog.cpp" line="292"/> <source>The new Custom Folder will initialize after you restart %1.</source> - <translation>Der eigene Ordner wird initialisiert sobald du %1 neugestartet hast.</translation> + <translation type="vanished">Der eigene Ordner wird initialisiert sobald du %1 neugestartet hast.</translation> </message> <message> <source>The new Custom Folder initialize after you restart %1.</source> <translation type="vanished">Der eigene Ordner initialisiert sobald du %1 neugestartet hast.</translation> </message> <message> - <location filename="../OptionsDialog.cpp" line="296"/> - <source>The language change will take effect after you restart %1.</source> - <translation>Die Änderung der Sprache nimmt Effekt sobald du %1 neugestartet hast.</translation> + <location filename="../OptionsDialog.cpp" line="132"/> + <source>%1 (Next Closest Language)</source> + <comment>First language a person can talk with a different person/application. "Native" or "Not Native".</comment> + <translation>%1 (Erste näheste Sprache)</translation> </message> <message> - <location filename="../OptionsDialog.cpp" line="306"/> + <location filename="../OptionsDialog.cpp" line="132"/> + <source>System</source> + <comment>System in context of System default</comment> + <translation>System</translation> + </message> + <message> + <location filename="../OptionsDialog.cpp" line="289"/> + <source>The new Custom Folder will initialise after you restart %1.</source> + <translation>Der eigene Ordner wird initialisiert sobald du %1 neugestartet hast.</translation> + </message> + <message> + <source>The language change will take effect after you restart %1.</source> + <translation type="vanished">Die Änderung der Sprache nimmt Effekt sobald du %1 neugestartet hast.</translation> + </message> + <message> + <location filename="../OptionsDialog.cpp" line="299"/> <source>No Profile</source> <comment>No Profile, as default</comment> <translation>Kein Profil</translation> </message> <message> - <location filename="../OptionsDialog.cpp" line="314"/> - <location filename="../OptionsDialog.cpp" line="318"/> - <location filename="../OptionsDialog.cpp" line="320"/> + <location filename="../OptionsDialog.cpp" line="307"/> + <location filename="../OptionsDialog.cpp" line="311"/> + <location filename="../OptionsDialog.cpp" line="313"/> <source>Profile: %1</source> <translation>Profil: %1</translation> </message> @@ -603,7 +747,7 @@ Grand Theft Auto V Snapmatic Bilder und Spielständen</translation> <span style=" font-weight:600;">Erstellt: </span>%8</translation> </message> <message> - <location filename="../PictureDialog.ui" line="104"/> + <location filename="../PictureDialog.ui" line="117"/> <source><span style=" font-weight:600;">Title: </span>%6<br/> <span style=" font-weight:600;">Location: </span>%7 (%1, %2, %3)<br/> <span style=" font-weight:600;">Players: </span>%4 (Crew %5)<br/> @@ -614,14 +758,28 @@ Grand Theft Auto V Snapmatic Bilder und Spielständen</translation> <span style=" font-weight:600;">Erstellt: </span>%8</translation> </message> <message> - <location filename="../PictureDialog.ui" line="167"/> <source>&Export</source> - <translation>&Exportieren</translation> + <translation type="vanished">&Exportieren</translation> </message> <message> - <location filename="../PictureDialog.ui" line="189"/> + <location filename="../PictureDialog.ui" line="177"/> + <source>Manage picture</source> + <translation>Bild verwalten</translation> + </message> + <message> + <location filename="../PictureDialog.ui" line="180"/> + <source>&Manage</source> + <translation>&Verwalten</translation> + </message> + <message> + <location filename="../PictureDialog.ui" line="199"/> + <source>Close viewer</source> + <translation>Ansicht schließen</translation> + </message> + <message> + <location filename="../PictureDialog.ui" line="202"/> <source>&Close</source> - <translation>&Schließen</translation> + <translation>S&chließen</translation> </message> <message> <source><span style=" font-weight:600;">Location: </span>%1, %2, %3 <br><span style=" font-weight:600;">Players: </span>%4<br><span style=" font-weight:600;">Crew ID: </span>%5</source> @@ -648,8 +806,8 @@ Grand Theft Auto V Snapmatic Bilder und Spielständen</translation> <span style=" font-weight:600;">Crew ID: </span>%5</translation> </message> <message> - <location filename="../PictureExport.cpp" line="89"/> - <location filename="../PictureExport.cpp" line="221"/> + <location filename="../PictureExport.cpp" line="91"/> + <location filename="../PictureExport.cpp" line="223"/> <source>Export</source> <translation>Exportieren</translation> </message> @@ -658,22 +816,52 @@ Grand Theft Auto V Snapmatic Bilder und Spielständen</translation> <translation type="obsolete">Kopieren</translation> </message> <message> - <location filename="../PictureDialog.ui" line="186"/> <source>Close</source> - <translation>Schließen</translation> + <translation type="vanished">Schließen</translation> </message> <message> - <location filename="../PictureDialog.cpp" line="141"/> <source>Export as &JPG picture...</source> - <translation>Exportiere als &JPG Bild...</translation> + <translation type="vanished">Exportiere als &JPG Bild...</translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="145"/> + <source>Export as &Picture...</source> + <translation>Exportiere als &Bild...</translation> </message> <message> - <location filename="../PictureDialog.cpp" line="142"/> <source>Export as &GTA Snapmatic...</source> - <translation>Exportiere als &GTA Snapmatic...</translation> + <translation type="vanished">Exportiere als &GTA Snapmatic...</translation> </message> <message> - <location filename="../PictureDialog.cpp" line="358"/> + <location filename="../PictureDialog.cpp" line="146"/> + <source>Export as &Snapmatic...</source> + <translation>Exportiere als &Snapmatic...</translation> + </message> + <message> + <source>Edi&t</source> + <translation type="vanished">Bearbei&ten</translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="148"/> + <source>Open &Map View...</source> + <translation>&Kartenansicht öffnen...</translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="150"/> + <source>&Edit Properties...</source> + <translation>Eigenschaften bearb&eiten...</translation> + </message> + <message> + <source>&Other</source> + <translation type="vanished">&Andere</translation> + </message> + <message> + <source>&Advanced</source> + <comment>Advanced for more options</comment> + <translation type="vanished">Erweitert (&A)</translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="373"/> <source>Key 1 - Avatar Preview Mode Key 2 - Toggle Overlay Arrow Keys - Navigate</source> @@ -682,19 +870,31 @@ Taste 2 - Overlay umschalten Pfeiltasten - Navigieren</translation> </message> <message> - <location filename="../PictureDialog.cpp" line="417"/> - <location filename="../PictureDialog.cpp" line="489"/> + <location filename="../PictureDialog.cpp" line="433"/> + <location filename="../PictureDialog.cpp" line="476"/> <source>Snapmatic Picture Viewer</source> <translation>Snapmatic Bildansicht</translation> </message> <message> - <location filename="../PictureDialog.cpp" line="417"/> - <location filename="../PictureDialog.cpp" line="489"/> + <location filename="../PictureDialog.cpp" line="433"/> + <location filename="../PictureDialog.cpp" line="476"/> <source>Failed at %1</source> <translation>Fehlgeschlagen bei %1</translation> </message> <message> - <location filename="../PictureDialog.cpp" line="572"/> + <location filename="../PictureDialog.cpp" line="475"/> + <location filename="../PictureDialog.cpp" line="589"/> + <source>No Crew</source> + <translation>Keine Crew</translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="475"/> + <location filename="../PictureDialog.cpp" line="614"/> + <source>No Players</source> + <translation>Keine Spieler</translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="560"/> <source>Avatar Preview Mode Press 1 for Default View</source> <translation>Avatar Vorschaumodus @@ -731,19 +931,15 @@ Drücke A für Standardansicht</translation> <translation type="vanished">Avatar Vorschaumodus<br>Drücke A für Standardansicht</translation> </message> <message> - <location filename="../PictureDialog.cpp" line="478"/> - <location filename="../PictureDialog.cpp" line="488"/> <source>No player</source> - <translation>Keine Spieler</translation> + <translation type="vanished">Keine Spieler</translation> </message> <message> - <location filename="../PictureDialog.cpp" line="481"/> - <location filename="../PictureDialog.cpp" line="488"/> <source>No crew</source> - <translation>Keine Crew</translation> + <translation type="vanished">Keine Crew</translation> </message> <message> - <location filename="../PictureDialog.cpp" line="488"/> + <location filename="../PictureDialog.cpp" line="475"/> <source>Unknown Location</source> <translation>Unbekannter Standort</translation> </message> @@ -752,59 +948,80 @@ Drücke A für Standardansicht</translation> <translation type="obsolete">Exportiere Bild...</translation> </message> <message> - <location filename="../PictureExport.cpp" line="88"/> <source>Export as JPG picture...</source> - <translation>Exportiere als JPG Bild...</translation> + <translation type="vanished">Exportiere als JPG Bild...</translation> </message> <message> - <location filename="../PictureExport.cpp" line="92"/> <source>JPEG picture (*.jpg)</source> - <translation>JPEG Bild (*.jpg)</translation> + <translation type="vanished">JPEG Bild (*.jpg)</translation> </message> <message> - <location filename="../PictureExport.cpp" line="93"/> + <location filename="../PictureExport.cpp" line="95"/> <source>Portable Network Graphics (*.png)</source> <translation>Portable Network Graphics (*.png)</translation> </message> <message> - <location filename="../PictureExport.cpp" line="143"/> - <location filename="../PictureExport.cpp" line="147"/> - <location filename="../PictureExport.cpp" line="181"/> - <location filename="../PictureExport.cpp" line="187"/> <source>Export as JPG picture</source> - <translation>Exportiere als JPG Bild</translation> + <translation type="vanished">Exportiere als JPG Bild</translation> </message> <message> - <location filename="../PictureExport.cpp" line="143"/> - <location filename="../PictureExport.cpp" line="246"/> + <location filename="../PictureExport.cpp" line="145"/> + <location filename="../PictureExport.cpp" line="260"/> <source>Overwrite %1 with current Snapmatic picture?</source> <translation>Überschreibe %1 mit aktuellen Snapmatic Bild?</translation> </message> <message> - <location filename="../PictureExport.cpp" line="246"/> - <location filename="../PictureExport.cpp" line="250"/> - <location filename="../PictureExport.cpp" line="265"/> - <location filename="../PictureExport.cpp" line="286"/> - <location filename="../PictureExport.cpp" line="291"/> - <location filename="../PictureExport.cpp" line="297"/> <source>Export as GTA Snapmatic</source> - <translation>Exportiere als GTA Snapmatic</translation> + <translation type="vanished">Exportiere als GTA Snapmatic</translation> </message> <message> - <location filename="../PictureExport.cpp" line="147"/> - <location filename="../PictureExport.cpp" line="250"/> + <location filename="../PictureExport.cpp" line="149"/> + <location filename="../PictureExport.cpp" line="264"/> <source>Failed to overwrite %1 with current Snapmatic picture</source> <translation>Fehlgeschlagen beim Überschreiben von %1 mit aktuellen Snapmatic Bild</translation> </message> <message> - <location filename="../PictureExport.cpp" line="181"/> - <location filename="../PictureExport.cpp" line="265"/> - <location filename="../PictureExport.cpp" line="286"/> + <location filename="../PictureExport.cpp" line="90"/> + <source>Export as Picture...</source> + <translation>Exportiere als Bild...</translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="94"/> + <source>JPEG Graphics (*.jpg *.jpeg)</source> + <translation>JPEG Graphics (*.jpg *.jpeg)</translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="145"/> + <location filename="../PictureExport.cpp" line="149"/> + <location filename="../PictureExport.cpp" line="183"/> + <location filename="../PictureExport.cpp" line="189"/> + <source>Export as Picture</source> + <translation>Exportiere als Bild</translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="183"/> + <location filename="../PictureExport.cpp" line="279"/> + <location filename="../PictureExport.cpp" line="288"/> <source>Failed to export current Snapmatic picture</source> <translation>Fehlgeschlagen beim Exportieren vom aktuellen Snapmatic Bild</translation> </message> <message> - <location filename="../PictureExport.cpp" line="291"/> + <location filename="../PictureExport.cpp" line="222"/> + <source>Export as Snapmatic...</source> + <translation>Exportiere als Snapmatic...</translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="260"/> + <location filename="../PictureExport.cpp" line="264"/> + <location filename="../PictureExport.cpp" line="279"/> + <location filename="../PictureExport.cpp" line="288"/> + <location filename="../PictureExport.cpp" line="293"/> + <location filename="../PictureExport.cpp" line="299"/> + <source>Export as Snapmatic</source> + <translation>Export as Snapmatic</translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="293"/> <source>Exported Snapmatic to "%1" because of using the .auto extension.</source> <translation>Snapmatic wurde wegen Benutzung der .auto Erweiterung zu "%1" exportiert.</translation> </message> @@ -821,22 +1038,21 @@ Drücke A für Standardansicht</translation> <translation type="obsolete">Exporti</translation> </message> <message> - <location filename="../PictureExport.cpp" line="220"/> <source>Export as GTA Snapmatic...</source> - <translation>Exportiere als GTA Snapmatic...</translation> + <translation type="vanished">Exportiere als GTA Snapmatic...</translation> </message> <message> - <location filename="../PictureExport.cpp" line="224"/> + <location filename="../PictureExport.cpp" line="226"/> <source>GTA V Export (*.g5e)</source> <translation>GTA V Export (*.g5e)</translation> </message> <message> - <location filename="../PictureExport.cpp" line="225"/> + <location filename="../PictureExport.cpp" line="227"/> <source>GTA V Raw Export (*.auto)</source> <translation>GTA V Roher Export (*.auto)</translation> </message> <message> - <location filename="../PictureExport.cpp" line="226"/> + <location filename="../PictureExport.cpp" line="228"/> <source>Snapmatic pictures (PGTA*)</source> <translation>Snapmatic Bilder (PGTA*)</translation> </message> @@ -857,9 +1073,8 @@ Drücke A für Standardansicht</translation> <translation type="obsolete">JPEG Bild (*.jpg);;Portable Network Graphics (*.png)</translation> </message> <message> - <location filename="../PictureDialog.ui" line="164"/> <source>Export picture</source> - <translation>Bild exportieren</translation> + <translation type="vanished">Bild exportieren</translation> </message> <message> <source>Snapmatic Picture Exporter</source> @@ -870,8 +1085,8 @@ Drücke A für Standardansicht</translation> <translation type="obsolete">Beim Speichern des Bildes ist ein Fehler aufgetreten</translation> </message> <message> - <location filename="../PictureExport.cpp" line="187"/> - <location filename="../PictureExport.cpp" line="297"/> + <location filename="../PictureExport.cpp" line="189"/> + <location filename="../PictureExport.cpp" line="299"/> <source>No valid file is selected</source> <translation>Keine gültige Datei wurde ausgewählt</translation> </message> @@ -890,27 +1105,31 @@ Drücke A für Standardansicht</translation> <translation>Lade Datei %1 von %2 Dateien</translation> </message> <message> - <location filename="../ProfileInterface.ui" line="169"/> + <location filename="../ProfileInterface.ui" line="172"/> <source>%1 %2</source> <translation>%1 %2</translation> </message> <message> - <location filename="../ProfileInterface.ui" line="195"/> - <source>Import exported file</source> - <translation>Importiere exportierte Datei</translation> + <location filename="../ProfileInterface.ui" line="198"/> + <source>Import file</source> + <translation>Importiere Datei</translation> </message> <message> - <location filename="../ProfileInterface.ui" line="198"/> + <source>Import exported file</source> + <translation type="vanished">Importiere exportierte Datei</translation> + </message> + <message> + <location filename="../ProfileInterface.ui" line="201"/> <source>&Import...</source> <translation>&Importieren...</translation> </message> <message> - <location filename="../ProfileInterface.ui" line="214"/> + <location filename="../ProfileInterface.ui" line="217"/> <source>Close profile</source> <translation>Profil schließen</translation> </message> <message> - <location filename="../ProfileInterface.ui" line="217"/> + <location filename="../ProfileInterface.ui" line="220"/> <source>&Close</source> <translation>S&chließen</translation> </message> @@ -931,29 +1150,30 @@ Drücke A für Standardansicht</translation> <translation type="obsolete">Profil schließen</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="114"/> + <location filename="../ProfileInterface.cpp" line="129"/> <source>Loading...</source> <translation>Lade...</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="390"/> - <location filename="../ProfileInterface.cpp" line="427"/> + <location filename="../ProfileInterface.cpp" line="426"/> + <location filename="../ProfileInterface.cpp" line="491"/> <source>Import...</source> <translation>Importieren...</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="391"/> - <location filename="../ProfileInterface.cpp" line="481"/> - <location filename="../ProfileInterface.cpp" line="486"/> - <location filename="../ProfileInterface.cpp" line="513"/> - <location filename="../ProfileInterface.cpp" line="529"/> - <location filename="../ProfileInterface.cpp" line="679"/> - <location filename="../ProfileInterface.cpp" line="684"/> - <location filename="../ProfileInterface.cpp" line="702"/> - <location filename="../ProfileInterface.cpp" line="707"/> - <location filename="../ProfileInterface.cpp" line="718"/> + <location filename="../ProfileInterface.cpp" line="427"/> + <location filename="../ProfileInterface.cpp" line="470"/> + <location filename="../ProfileInterface.cpp" line="522"/> + <location filename="../ProfileInterface.cpp" line="542"/> + <location filename="../ProfileInterface.cpp" line="558"/> + <location filename="../ProfileInterface.cpp" line="674"/> <location filename="../ProfileInterface.cpp" line="755"/> - <location filename="../ProfileInterface.cpp" line="761"/> + <location filename="../ProfileInterface.cpp" line="760"/> + <location filename="../ProfileInterface.cpp" line="778"/> + <location filename="../ProfileInterface.cpp" line="783"/> + <location filename="../ProfileInterface.cpp" line="794"/> + <location filename="../ProfileInterface.cpp" line="831"/> + <location filename="../ProfileInterface.cpp" line="837"/> <source>Import</source> <translation>Importieren</translation> </message> @@ -962,41 +1182,49 @@ Drücke A für Standardansicht</translation> <translation type="vanished">Alle Profildateien (SGTA* PGTA*)</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="394"/> <source>Importable files (*.g5e *.jpg *.png SGTA* PGTA*)</source> - <translation>Importfähige Dateien (*.g5e *.jpg *.png SGTA* PGTA*)</translation> + <translation type="vanished">Importfähige Dateien (*.g5e *.jpg *.png SGTA* PGTA*)</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="396"/> - <location filename="../UserInterface.cpp" line="351"/> + <location filename="../ProfileInterface.cpp" line="444"/> + <location filename="../UserInterface.cpp" line="365"/> <source>Savegames files (SGTA*)</source> <translation>Spielstanddateien (SGTA*)</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="397"/> - <location filename="../UserInterface.cpp" line="352"/> + <location filename="../ProfileInterface.cpp" line="445"/> + <location filename="../UserInterface.cpp" line="366"/> <source>Snapmatic pictures (PGTA*)</source> <translation>Snapmatic Bilder (PGTA*)</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="398"/> <source>All image files (*.jpg *.png)</source> - <translation>Alle Bilddateien (*.jpg *.png)</translation> + <translation type="vanished">Alle Bilddateien (*.jpg *.png)</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="399"/> - <location filename="../UserInterface.cpp" line="353"/> + <location filename="../ProfileInterface.cpp" line="442"/> + <source>Importable files (%1)</source> + <translation>Importfähige Dateien (%1)</translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="446"/> + <source>All image files (%1)</source> + <translation>Alle Bilddateien (%1)</translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="447"/> + <location filename="../UserInterface.cpp" line="367"/> <source>All files (**)</source> <translation>Alle Dateien (**)</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="428"/> - <location filename="../ProfileInterface.cpp" line="443"/> + <location filename="../ProfileInterface.cpp" line="492"/> + <location filename="../ProfileInterface.cpp" line="507"/> <source>Import file %1 of %2 files</source> <translation>Importiere Datei %1 von %2 Dateien</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="481"/> + <location filename="../ProfileInterface.cpp" line="522"/> <source>Import failed with... %1</source> @@ -1005,46 +1233,60 @@ Drücke A für Standardansicht</translation> %1</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="513"/> - <location filename="../UserInterface.cpp" line="393"/> + <location filename="../ProfileInterface.cpp" line="542"/> + <location filename="../UserInterface.cpp" line="407"/> <source>Failed to read Snapmatic picture</source> <translation>Fehler beim Lesen vom Snapmatic Bild</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="529"/> - <location filename="../UserInterface.cpp" line="409"/> + <location filename="../ProfileInterface.cpp" line="558"/> + <location filename="../UserInterface.cpp" line="423"/> <source>Failed to read Savegame file</source> <translation>Fehler beim Lesen von Spielstanddatei</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="679"/> - <source>Can't import %1 because of not valid file format</source> - <translation>Kann %1 nicht importieren weil das Dateiformat nicht gültig ist</translation> + <location filename="../ProfileInterface.cpp" line="674"/> + <source>Can't import %1 because file can't be parsed properly</source> + <translation>Kann %1 nicht importieren weil die Datei nicht richtig gelesen werden kann</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="702"/> + <location filename="../ProfileInterface.cpp" line="755"/> + <source>Can't import %1 because file format can't be detected</source> + <translation>Kann %1 nicht importieren weil das Dateiformat nicht erkannt werden kann</translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="984"/> + <source>Initialising export...</source> + <translation>Initialisiere Export...</translation> + </message> + <message> + <source>Can't import %1 because of not valid file format</source> + <translation type="vanished">Kann %1 nicht importieren weil das Dateiformat nicht gültig ist</translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="778"/> <source>Failed to import the Snapmatic picture, file not begin with PGTA or end with .g5e</source> <translation>Fehlgeschlagen beim Importieren vom Snapmatic Bild, Datei beginnt nicht mit PGTA oder endet mit .g5e</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="707"/> + <location filename="../ProfileInterface.cpp" line="783"/> <source>Failed to import the Snapmatic picture, the picture is already in the game</source> <translation>Fehlgeschlagen beim Importieren vom Snapmatic Bild, dieses Bild ist bereits im Spiel</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="862"/> + <location filename="../ProfileInterface.cpp" line="938"/> <source>%1Export Snapmatic pictures%2<br><br>JPG pictures make it possible to open the picture with a Image Viewer<br>GTA Snapmatic make it possible to import the picture into the game<br><br>Export as:</source> <translation>%1Exportiere Snapmatic Bilder%2<br><br>JPG Bilder machen es möglich sie mit ein Bildansicht Programm zu öffnen<br>Das GTA Snapmatic Format macht es möglich sie wieder ins Game zu importieren<br><br>Exportieren als:</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="486"/> - <location filename="../ProfileInterface.cpp" line="684"/> - <location filename="../UserInterface.cpp" line="441"/> + <location filename="../ProfileInterface.cpp" line="470"/> + <location filename="../ProfileInterface.cpp" line="760"/> + <location filename="../UserInterface.cpp" line="455"/> <source>No valid file is selected</source> <translation>Keine gültige Datei wurde ausgewählt</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="62"/> + <location filename="../ProfileInterface.cpp" line="65"/> <source>Enabled pictures: %1 of %2</source> <translation>Aktivierte Bilder: %1 von %2</translation> </message> @@ -1053,35 +1295,35 @@ Drücke A für Standardansicht</translation> <translation type="vanished">Fehlgeschlagen beim Importieren vom Snapmatic Bild, Datei beginnt nicht mit PGTA</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="718"/> + <location filename="../ProfileInterface.cpp" line="794"/> <source>Failed to import the Snapmatic picture, can't copy the file into profile</source> - <translation>Fehlgeschlagen beim Importieren vom Snapmatic Bild, kann Snapmatic Bild nicht ins Profil kopieren </translation> + <translation>Fehlgeschlagen beim Importieren vom Snapmatic Bild, kann Snapmatic Bild nicht ins Profil kopieren</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="755"/> + <location filename="../ProfileInterface.cpp" line="831"/> <source>Failed to import the Savegame, can't copy the file into profile</source> <translation>Fehlgeschlagen beim Importieren vom Spielstand, kann Spielstanddatei nicht ins Profil kopieren</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="761"/> + <location filename="../ProfileInterface.cpp" line="837"/> <source>Failed to import the Savegame, no Savegame slot is left</source> <translation>Fehlgeschlagen beim Importieren vom Spielstand, kein Spielstandslot mehr frei</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="847"/> - <location filename="../ProfileInterface.cpp" line="865"/> + <location filename="../ProfileInterface.cpp" line="923"/> + <location filename="../ProfileInterface.cpp" line="941"/> <source>JPG pictures and GTA Snapmatic</source> <translation>JPG Bilder und GTA Snapmatic</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="848"/> - <location filename="../ProfileInterface.cpp" line="870"/> + <location filename="../ProfileInterface.cpp" line="924"/> + <location filename="../ProfileInterface.cpp" line="946"/> <source>JPG pictures only</source> <translation>Nur JPG Bilder</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="849"/> - <location filename="../ProfileInterface.cpp" line="874"/> + <location filename="../ProfileInterface.cpp" line="925"/> + <location filename="../ProfileInterface.cpp" line="950"/> <source>GTA Snapmatic only</source> <translation>Nur GTA Snapmatic</translation> </message> @@ -1100,25 +1342,25 @@ Das GTA Snapmatic Format macht es möglich sie wieder ins Game zu importieren Exportieren als:</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="959"/> - <location filename="../ProfileInterface.cpp" line="1001"/> + <location filename="../ProfileInterface.cpp" line="1037"/> + <location filename="../ProfileInterface.cpp" line="1079"/> <source>No Snapmatic pictures or Savegames files are selected</source> <translation>Keine Snapmatic Bilder oder Spielstände ausgewählt</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="967"/> - <location filename="../ProfileInterface.cpp" line="995"/> - <location filename="../ProfileInterface.cpp" line="1001"/> + <location filename="../ProfileInterface.cpp" line="1045"/> + <location filename="../ProfileInterface.cpp" line="1073"/> + <location filename="../ProfileInterface.cpp" line="1079"/> <source>Remove selected</source> <translation>Auswahl löschen</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="967"/> + <location filename="../ProfileInterface.cpp" line="1045"/> <source>You really want remove the selected Snapmatic picutres and Savegame files?</source> <translation>Möchtest du wirklich die ausgewählten Snapmatic Bilder und Spielstanddateien löschen?</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="995"/> + <location filename="../ProfileInterface.cpp" line="1073"/> <source>Failed at remove the complete selected Snapmatic pictures and/or Savegame files</source> <translation>Fehlgeschlagen beim kompletten entfernen der ausgewählten Snapmatic Bilder und/oder der Spielstanddateien</translation> </message> @@ -1139,10 +1381,10 @@ Exportieren als:</translation> <translation type="obsolete">Fehlgeschlagenen beim Import vom Spielstand weil kein Spielstandslot mehr übrig ist</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="824"/> - <location filename="../ProfileInterface.cpp" line="862"/> - <location filename="../ProfileInterface.cpp" line="939"/> - <location filename="../ProfileInterface.cpp" line="959"/> + <location filename="../ProfileInterface.cpp" line="900"/> + <location filename="../ProfileInterface.cpp" line="938"/> + <location filename="../ProfileInterface.cpp" line="1017"/> + <location filename="../ProfileInterface.cpp" line="1037"/> <source>Export selected</source> <translation>Auswahl exportieren</translation> </message> @@ -1163,21 +1405,20 @@ Exportieren als:</translation> <translation type="obsolete">Wie sollen wir mit den Snapmatic Bilder umgehen?</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="905"/> + <location filename="../ProfileInterface.cpp" line="983"/> <source>Export selected...</source> <translation>Auswahl exportieren...</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="906"/> <source>Initializing export...</source> - <translation>Initialisiere Export...</translation> + <translation type="vanished">Initialisiere Export...</translation> </message> <message> <source>Initializing...</source> <translation type="obsolete">Initialisierung...</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="939"/> + <location filename="../ProfileInterface.cpp" line="1017"/> <source>Export failed with... %1</source> @@ -1200,20 +1441,20 @@ Exportieren als:</translation> <translation type="obsolete">Aktueller Exportiervorgang: %1</translation> </message> <message> - <location filename="../ExportThread.cpp" line="96"/> - <location filename="../ExportThread.cpp" line="135"/> - <location filename="../ExportThread.cpp" line="156"/> + <location filename="../ExportThread.cpp" line="97"/> + <location filename="../ExportThread.cpp" line="136"/> + <location filename="../ExportThread.cpp" line="157"/> <source>Export file %1 of %2 files</source> <translation>Exportiere Datei %1 von %2 Dateien</translation> </message> <message> - <location filename="../UserInterface.cpp" line="349"/> + <location filename="../UserInterface.cpp" line="363"/> <source>All profile files (*.g5e SGTA* PGTA*)</source> <translation>Alle Profildateien (*.g5e SGTA* PGTA*)</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="395"/> - <location filename="../UserInterface.cpp" line="350"/> + <location filename="../ProfileInterface.cpp" line="443"/> + <location filename="../UserInterface.cpp" line="364"/> <source>GTA V Export (*.g5e)</source> <translation>GTA V Export (*.g5e)</translation> </message> @@ -1221,12 +1462,12 @@ Exportieren als:</translation> <context> <name>QApplication</name> <message> - <location filename="../main.cpp" line="68"/> + <location filename="../main.cpp" line="66"/> <source>Font</source> <translation>Schrift</translation> </message> <message> - <location filename="../main.cpp" line="68"/> + <location filename="../main.cpp" line="66"/> <source>Selected Font: %1</source> <translation>Ausgewähle Schrift: %1</translation> </message> @@ -1240,12 +1481,12 @@ Exportieren als:</translation> <translation>Spielstandanzeiger</translation> </message> <message> - <location filename="../SavegameDialog.ui" line="29"/> + <location filename="../SavegameDialog.ui" line="23"/> <source><span style=" font-weight:600;">Savegame</span><br><br>%1</source> <translation><span style=" font-weight:600;">Spielstand</span><br><br>%1</translation> </message> <message> - <location filename="../SavegameDialog.ui" line="63"/> + <location filename="../SavegameDialog.ui" line="70"/> <source>&Export</source> <translation>&Exportieren</translation> </message> @@ -1254,7 +1495,7 @@ Exportieren als:</translation> <translation type="obsolete">&Kopieren</translation> </message> <message> - <location filename="../SavegameDialog.ui" line="76"/> + <location filename="../SavegameDialog.ui" line="83"/> <source>&Close</source> <translation>S&chließen</translation> </message> @@ -1294,12 +1535,12 @@ Exportieren als:</translation> <translation type="vanished">SPIELSTAND - %1<br>%2</translation> </message> <message> - <location filename="../SavegameWidget.ui" line="83"/> + <location filename="../SavegameWidget.ui" line="86"/> <source>View</source> <translation>Ansehen</translation> </message> <message> - <location filename="../SavegameWidget.ui" line="99"/> + <location filename="../SavegameWidget.ui" line="102"/> <location filename="../SavegameCopy.cpp" line="48"/> <source>Export</source> <translation>Exportieren</translation> @@ -1309,14 +1550,14 @@ Exportieren als:</translation> <translation type="obsolete">Kopieren</translation> </message> <message> - <location filename="../SavegameWidget.ui" line="118"/> + <location filename="../SavegameWidget.ui" line="121"/> <source>Delete</source> <translation>Löschen</translation> </message> <message> - <location filename="../SavegameWidget.ui" line="115"/> - <location filename="../SavegameWidget.cpp" line="139"/> - <location filename="../SavegameWidget.cpp" line="152"/> + <location filename="../SavegameWidget.ui" line="118"/> + <location filename="../SavegameWidget.cpp" line="131"/> + <location filename="../SavegameWidget.cpp" line="144"/> <source>Delete savegame</source> <translation>Savegame löschen</translation> </message> @@ -1326,13 +1567,13 @@ Exportieren als:</translation> <translation>Spielstand exportieren...</translation> </message> <message> - <location filename="../SavegameWidget.ui" line="64"/> + <location filename="../SavegameWidget.ui" line="67"/> <source>SAVE %3 - %1<br>%2</source> <translation>SPIELSTAND %3 - %1<br>%2</translation> </message> <message> - <location filename="../SavegameWidget.cpp" line="101"/> - <location filename="../SavegameWidget.cpp" line="102"/> + <location filename="../SavegameWidget.cpp" line="89"/> + <location filename="../SavegameWidget.cpp" line="90"/> <source>WRONG FORMAT</source> <translation>FALSCHES FORMAT</translation> </message> @@ -1341,63 +1582,63 @@ Exportieren als:</translation> <translation type="vanished">AUTO</translation> </message> <message> - <location filename="../SavegameWidget.cpp" line="64"/> + <location filename="../SavegameWidget.cpp" line="60"/> + <location filename="../SavegameWidget.cpp" line="117"/> <source>AUTOSAVE - %1 %2</source> <translation>AUTOSAVE - %1 %2</translation> </message> <message> - <location filename="../SavegameWidget.cpp" line="65"/> + <location filename="../SavegameWidget.cpp" line="61"/> + <location filename="../SavegameWidget.cpp" line="118"/> <source>SAVE %3 - %1 %2</source> <translation>SPIELSTAND %3 - %1 %2</translation> </message> <message> - <location filename="../SavegameWidget.cpp" line="125"/> + <location filename="../SavegameWidget.cpp" line="111"/> <source>UNKNOWN</source> <translation>UNKNOWN</translation> </message> <message> - <location filename="../SavegameWidget.cpp" line="139"/> + <location filename="../SavegameWidget.cpp" line="131"/> <source>Are you sure to delete %1 from your savegames?</source> <translation>Bist du sicher %1 von deinen Spielständen zu löschen?</translation> </message> <message> - <location filename="../SavegameWidget.cpp" line="152"/> + <location filename="../SavegameWidget.cpp" line="144"/> <source>Failed at deleting %1 from your savegames</source> <translation>Fehlgeschlagen beim Löschen %1 von deinen Spielständen</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1124"/> + <location filename="../ProfileInterface.cpp" line="1225"/> <source>&View</source> <translation>A&nsehen</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1126"/> + <location filename="../ProfileInterface.cpp" line="1227"/> <source>&Remove</source> <translation>Entfe&rnen</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1130"/> - <location filename="../ProfileInterface.cpp" line="1141"/> + <location filename="../ProfileInterface.cpp" line="1229"/> <source>&Select</source> <translation>Au&swählen</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1131"/> + <location filename="../ProfileInterface.cpp" line="1230"/> <source>&Deselect</source> <translation>A&bwählen</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1132"/> - <location filename="../ProfileInterface.cpp" line="1142"/> + <location filename="../ProfileInterface.cpp" line="1233"/> <source>Select &All</source> <translation>&Alles auswählen</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1135"/> + <location filename="../ProfileInterface.cpp" line="1237"/> <source>&Deselect All</source> <translation>Alles a&bwählen</translation> </message> @@ -1426,17 +1667,17 @@ Exportieren als:</translation> <translation type="obsolete">Umschalt+S</translation> </message> <message> - <location filename="../SavegameWidget.ui" line="80"/> + <location filename="../SavegameWidget.ui" line="83"/> <source>View savegame</source> <translation>Spielstand ansehen</translation> </message> <message> - <location filename="../SavegameWidget.ui" line="96"/> + <location filename="../SavegameWidget.ui" line="99"/> <source>Copy savegame</source> <translation>Spielstand kopieren</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1125"/> + <location filename="../ProfileInterface.cpp" line="1226"/> <source>&Export</source> <translation>&Exportieren</translation> </message> @@ -1512,7 +1753,7 @@ Exportieren als:</translation> <message> <location filename="../SnapmaticEditor.ui" line="14"/> <location filename="../SnapmaticEditor.ui" line="81"/> - <location filename="../SnapmaticEditor.cpp" line="244"/> + <location filename="../SnapmaticEditor.cpp" line="245"/> <source>Snapmatic Properties</source> <translation>Snapmatic Eigenschaften</translation> </message> @@ -1556,7 +1797,7 @@ Exportieren als:</translation> <translation>Meme</translation> </message> <message> - <location filename="../SnapmaticEditor.cpp" line="294"/> + <location filename="../SnapmaticEditor.cpp" line="295"/> <source>Snapmatic Title</source> <translation>Snapmatic Titel</translation> </message> @@ -1567,20 +1808,20 @@ Exportieren als:</translation> </message> <message> <location filename="../SnapmaticEditor.ui" line="113"/> - <location filename="../SnapmaticEditor.cpp" line="199"/> + <location filename="../SnapmaticEditor.cpp" line="200"/> <source>Crew: %1 (%2)</source> <translation>Crew: %1 (%2)</translation> </message> <message> <location filename="../SnapmaticEditor.ui" line="126"/> - <location filename="../SnapmaticEditor.cpp" line="184"/> + <location filename="../SnapmaticEditor.cpp" line="185"/> <source>Title: %1 (%2)</source> <translation>Titel: %1 (%2)</translation> </message> <message> <location filename="../SnapmaticEditor.ui" line="136"/> - <location filename="../SnapmaticEditor.cpp" line="188"/> - <location filename="../SnapmaticEditor.cpp" line="192"/> + <location filename="../SnapmaticEditor.cpp" line="189"/> + <location filename="../SnapmaticEditor.cpp" line="193"/> <source>Appropriate: %1</source> <translation>Angemessen: %1</translation> </message> @@ -1592,7 +1833,7 @@ Exportieren als:</translation> <message> <location filename="../SnapmaticEditor.ui" line="155"/> <source>Qualify as Avatar automatically at apply</source> - <translation>Beim Übernehmen als Avatar qualifizieren </translation> + <translation>Beim Übernehmen als Avatar qualifizieren</translation> </message> <message> <location filename="../SnapmaticEditor.ui" line="168"/> @@ -1618,40 +1859,40 @@ Exportieren als:</translation> <translation type="vanished">Cancel</translation> </message> <message> - <location filename="../SnapmaticEditor.cpp" line="183"/> - <location filename="../SnapmaticEditor.cpp" line="198"/> + <location filename="../SnapmaticEditor.cpp" line="184"/> + <location filename="../SnapmaticEditor.cpp" line="199"/> <source>Edit</source> <translation>Bearbeiten</translation> </message> <message> - <location filename="../SnapmaticEditor.cpp" line="188"/> + <location filename="../SnapmaticEditor.cpp" line="189"/> <source>Yes</source> <comment>Yes, should work fine</comment> <translation>Ja</translation> </message> <message> - <location filename="../SnapmaticEditor.cpp" line="192"/> + <location filename="../SnapmaticEditor.cpp" line="193"/> <source>No</source> <comment>No, could lead to issues</comment> <translation>Nein</translation> </message> <message> - <location filename="../SnapmaticEditor.cpp" line="244"/> + <location filename="../SnapmaticEditor.cpp" line="245"/> <source>Patching of Snapmatic Properties failed because of I/O Error</source> <translation>Patchen von Snapmatic Eigenschaften fehlgeschlagen wegen I/O Fehler</translation> </message> <message> - <location filename="../SnapmaticEditor.cpp" line="294"/> + <location filename="../SnapmaticEditor.cpp" line="295"/> <source>New Snapmatic title:</source> <translation>Neuer Snapmatic Titel:</translation> </message> <message> - <location filename="../SnapmaticEditor.cpp" line="319"/> + <location filename="../SnapmaticEditor.cpp" line="324"/> <source>Snapmatic Crew</source> <translation>Snapmatic Crew</translation> </message> <message> - <location filename="../SnapmaticEditor.cpp" line="319"/> + <location filename="../SnapmaticEditor.cpp" line="324"/> <source>New Snapmatic crew:</source> <translation>Neue Snapmatic Crew:</translation> </message> @@ -1659,7 +1900,7 @@ Exportieren als:</translation> <context> <name>SnapmaticPicture</name> <message> - <location filename="../SnapmaticPicture.cpp" line="367"/> + <location filename="../SnapmaticPicture.cpp" line="411"/> <source>PHOTO - %1</source> <translation>FOTO - %1</translation> </message> @@ -1672,44 +1913,44 @@ Exportieren als:</translation> <translation>Snapmatic Widget</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="82"/> + <location filename="../SnapmaticWidget.ui" line="85"/> <source>PHOTO - 00/00/00 00:00:00</source> <translation>FOTO - 00/00/00 00:00:00</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="101"/> + <location filename="../SnapmaticWidget.ui" line="104"/> <source>View</source> <translation>Ansehen</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="120"/> + <location filename="../SnapmaticWidget.ui" line="123"/> <source>Copy</source> <translation>Kopieren</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="136"/> + <location filename="../SnapmaticWidget.ui" line="139"/> <source>Export</source> <translation>Exportieren</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="152"/> + <location filename="../SnapmaticWidget.ui" line="155"/> <source>Delete</source> <translation>Löschen</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="149"/> - <location filename="../SnapmaticWidget.cpp" line="163"/> - <location filename="../SnapmaticWidget.cpp" line="172"/> + <location filename="../SnapmaticWidget.ui" line="152"/> + <location filename="../SnapmaticWidget.cpp" line="144"/> + <location filename="../SnapmaticWidget.cpp" line="153"/> <source>Delete picture</source> <translation>Bild löschen</translation> </message> <message> - <location filename="../SnapmaticWidget.cpp" line="163"/> + <location filename="../SnapmaticWidget.cpp" line="144"/> <source>Are you sure to delete %1 from your Snapmatic pictures?</source> <translation>Bist du sicher %1 von deine Snapmatic Bilder zu löschen?</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1083"/> + <location filename="../ProfileInterface.cpp" line="1178"/> <source>Edi&t</source> <translation>Bearbei&ten</translation> </message> @@ -1722,7 +1963,7 @@ Exportieren als:</translation> <translation type="vanished">&Im Spiel deaktivieren</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1093"/> + <location filename="../ProfileInterface.cpp" line="1188"/> <source>&Export</source> <translation>&Exportieren</translation> </message> @@ -1735,12 +1976,12 @@ Exportieren als:</translation> <translation type="obsolete">Exportiere als &GTA Snapmatic</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1086"/> + <location filename="../ProfileInterface.cpp" line="1181"/> <source>Show &In-game</source> <translation>&Im Spiel anzeigen</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1090"/> + <location filename="../ProfileInterface.cpp" line="1185"/> <source>Hide &In-game</source> <translation>&Im Spiel ausblenden</translation> </message> @@ -1753,49 +1994,55 @@ Exportieren als:</translation> <translation type="vanished">FOTO - %1</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1092"/> + <location filename="../ProfileInterface.cpp" line="1187"/> <source>&Edit Properties...</source> <translation>&Eigenschaften bearbeiten...</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1094"/> <source>Export as &JPG picture...</source> - <translation>Exportiere als &JPG Bild...</translation> + <translation type="vanished">Exportiere als &JPG Bild...</translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1189"/> + <source>Export as &Picture...</source> + <translation>Exportiere als &Bild...</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1095"/> <source>Export as &GTA Snapmatic...</source> - <translation>Exportiere als &GTA Snapmatic...</translation> + <translation type="vanished">Exportiere als &GTA Snapmatic...</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1096"/> + <location filename="../ProfileInterface.cpp" line="1190"/> + <source>Export as &Snapmatic...</source> + <translation>Exportiere als &Snapmatic...</translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1191"/> <source>&View</source> <translation>A&nsehen</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1099"/> + <location filename="../ProfileInterface.cpp" line="1194"/> <source>&Remove</source> <translation>Entfe&rnen</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1103"/> - <location filename="../ProfileInterface.cpp" line="1114"/> + <location filename="../ProfileInterface.cpp" line="1196"/> <source>&Select</source> <translation>Au&swählen</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1104"/> + <location filename="../ProfileInterface.cpp" line="1197"/> <source>&Deselect</source> <translation>A&bwählen</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1105"/> - <location filename="../ProfileInterface.cpp" line="1115"/> + <location filename="../ProfileInterface.cpp" line="1200"/> <source>Select &All</source> <translation>Alles &auswählen</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1108"/> + <location filename="../ProfileInterface.cpp" line="1204"/> <source>&Deselect All</source> <translation>Alles a&bwählen</translation> </message> @@ -1824,17 +2071,17 @@ Exportieren als:</translation> <translation type="obsolete">Umschalt+S</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="98"/> + <location filename="../SnapmaticWidget.ui" line="101"/> <source>View picture</source> <translation>Bild ansehen</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="117"/> + <location filename="../SnapmaticWidget.ui" line="120"/> <source>Copy picture</source> <translation>Bild kopieren</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="133"/> + <location filename="../SnapmaticWidget.ui" line="136"/> <source>Export picture</source> <translation>Bild exportieren</translation> </message> @@ -1843,7 +2090,7 @@ Exportieren als:</translation> <translation type="obsolete">Bist du sicher %1 von deinen Snapmatic Bilder zu löschen?</translation> </message> <message> - <location filename="../SnapmaticWidget.cpp" line="172"/> + <location filename="../SnapmaticWidget.cpp" line="153"/> <source>Failed at deleting %1 from your Snapmatic pictures</source> <translation>Fehlgeschlagen beim Löschen von %1 von deinen Snapmatic Bildern</translation> </message> @@ -1883,7 +2130,7 @@ Exportieren als:</translation> <translation type="obsolete">Über gta5sync</translation> </message> <message> - <location filename="../UserInterface.ui" line="258"/> + <location filename="../UserInterface.ui" line="264"/> <source>Ctrl+A</source> <translation>Strg+A</translation> </message> @@ -1896,7 +2143,7 @@ Exportieren als:</translation> <translation type="obsolete">Optionen</translation> </message> <message> - <location filename="../UserInterface.ui" line="298"/> + <location filename="../UserInterface.ui" line="304"/> <source>Ctrl+O</source> <translation>Strg+O</translation> </message> @@ -1905,7 +2152,7 @@ Exportieren als:</translation> <translation type="obsolete">Alles auswählen</translation> </message> <message> - <location filename="../UserInterface.ui" line="250"/> + <location filename="../UserInterface.ui" line="256"/> <source>Ctrl+S</source> <translation>Strg+S</translation> </message> @@ -1922,7 +2169,7 @@ Exportieren als:</translation> <translation type="obsolete">Auswahl exportieren</translation> </message> <message> - <location filename="../UserInterface.ui" line="274"/> + <location filename="../UserInterface.ui" line="280"/> <source>Ctrl+E</source> <translation>Strg+E</translation> </message> @@ -1931,17 +2178,17 @@ Exportieren als:</translation> <translation type="obsolete">Auswahl löschen</translation> </message> <message> - <location filename="../UserInterface.ui" line="266"/> + <location filename="../UserInterface.ui" line="272"/> <source>Ctrl+D</source> <translation>Strg+D</translation> </message> <message> - <location filename="../UserInterface.ui" line="231"/> + <location filename="../UserInterface.ui" line="237"/> <source>Exit</source> <translation>Beenden</translation> </message> <message> - <location filename="../UserInterface.ui" line="199"/> + <location filename="../UserInterface.ui" line="205"/> <source>&Selection visibility</source> <translation>Auswahl &Sichtbarkeit</translation> </message> @@ -1950,12 +2197,12 @@ Exportieren als:</translation> <translation type="vanished">&Über Produkt</translation> </message> <message> - <location filename="../UserInterface.ui" line="228"/> + <location filename="../UserInterface.ui" line="234"/> <source>&Exit</source> <translation>B&eenden</translation> </message> <message> - <location filename="../UserInterface.ui" line="234"/> + <location filename="../UserInterface.ui" line="240"/> <source>Ctrl+Q</source> <translation>Strg+Q</translation> </message> @@ -1970,22 +2217,33 @@ Exportieren als:</translation> <translation>%1 %2</translation> </message> <message> - <location filename="../UserInterface.ui" line="173"/> + <location filename="../UserInterface.ui" line="131"/> + <source>Reload profile overview</source> + <translation>Übersicht der Profile neuladen</translation> + </message> + <message> + <location filename="../UserInterface.ui" line="150"/> + <source>Close %1</source> + <extracomment>Close %1 <- (gta5view/gta5sync) - %1 will be replaced automatically</extracomment> + <translation>Schließe %1</translation> + </message> + <message> + <location filename="../UserInterface.ui" line="179"/> <source>&File</source> <translation>&Datei</translation> </message> <message> - <location filename="../UserInterface.ui" line="183"/> + <location filename="../UserInterface.ui" line="189"/> <source>&Help</source> <translation>&Hilfe</translation> </message> <message> - <location filename="../UserInterface.ui" line="189"/> + <location filename="../UserInterface.ui" line="195"/> <source>&Edit</source> <translation>Bearb&eiten</translation> </message> <message> - <location filename="../UserInterface.ui" line="195"/> + <location filename="../UserInterface.ui" line="201"/> <source>&Profile</source> <translation>&Profil</translation> </message> @@ -1998,43 +2256,43 @@ Exportieren als:</translation> <translation type="vanished">&Über gta5sync</translation> </message> <message> - <location filename="../UserInterface.ui" line="239"/> + <location filename="../UserInterface.ui" line="245"/> <source>Close &Profile</source> <translation>&Profil schließen</translation> </message> <message> - <location filename="../UserInterface.ui" line="242"/> + <location filename="../UserInterface.ui" line="248"/> <source>Ctrl+End</source> <translation>Strg+Ende</translation> </message> <message> - <location filename="../UserInterface.ui" line="282"/> + <location filename="../UserInterface.ui" line="288"/> <source>Ctrl+Del</source> <translation>Strg+Entf</translation> </message> <message> - <location filename="../UserInterface.ui" line="295"/> + <location filename="../UserInterface.ui" line="301"/> <source>&Open File...</source> <translation>Datei &öffnen...</translation> </message> <message> - <location filename="../UserInterface.ui" line="303"/> - <location filename="../UserInterface.cpp" line="151"/> + <location filename="../UserInterface.ui" line="309"/> + <location filename="../UserInterface.cpp" line="163"/> <source>Select &GTA V Folder...</source> <translation>Wähle &GTA V Ordner...</translation> </message> <message> - <location filename="../UserInterface.ui" line="309"/> + <location filename="../UserInterface.ui" line="315"/> <source>Ctrl+G</source> <translation>Strg+G</translation> </message> <message> - <location filename="../UserInterface.ui" line="314"/> + <location filename="../UserInterface.ui" line="320"/> <source>Show In-gam&e</source> <translation>Im Spiel anzeig&en</translation> </message> <message> - <location filename="../UserInterface.ui" line="322"/> + <location filename="../UserInterface.ui" line="328"/> <source>Hi&de In-game</source> <translation>Im Spiel ausblen&den</translation> </message> @@ -2047,7 +2305,7 @@ Exportieren als:</translation> <translation type="vanished">Im Spiel aktivier&en</translation> </message> <message> - <location filename="../UserInterface.ui" line="317"/> + <location filename="../UserInterface.ui" line="323"/> <source>Shift+E</source> <translation>Umschalt+E</translation> </message> @@ -2056,12 +2314,12 @@ Exportieren als:</translation> <translation type="vanished">Im Spiel &deaktivieren</translation> </message> <message> - <location filename="../UserInterface.ui" line="325"/> + <location filename="../UserInterface.ui" line="331"/> <source>Shift+D</source> <translation>Umschalt+D</translation> </message> <message> - <location filename="../UserInterface.ui" line="147"/> + <location filename="../UserInterface.ui" line="153"/> <source>&Close</source> <translation>S&chließen</translation> </message> @@ -2070,7 +2328,7 @@ Exportieren als:</translation> <translation type="obsolete">&Profil auswählen</translation> </message> <message> - <location filename="../UserInterface.ui" line="223"/> + <location filename="../UserInterface.ui" line="229"/> <source>Ctrl+P</source> <translation>Strg+P</translation> </message> @@ -2079,27 +2337,27 @@ Exportieren als:</translation> <translation type="obsolete">&Optionen</translation> </message> <message> - <location filename="../UserInterface.ui" line="247"/> + <location filename="../UserInterface.ui" line="253"/> <source>&Settings</source> <translation>Ein&stellungen</translation> </message> <message> - <location filename="../UserInterface.ui" line="255"/> + <location filename="../UserInterface.ui" line="261"/> <source>Select &All</source> <translation>&Alles auswählen</translation> </message> <message> - <location filename="../UserInterface.ui" line="263"/> + <location filename="../UserInterface.ui" line="269"/> <source>&Deselect All</source> <translation>Alles a&bwählen</translation> </message> <message> - <location filename="../UserInterface.ui" line="271"/> + <location filename="../UserInterface.ui" line="277"/> <source>&Export selected...</source> <translation>Auswahl &exportieren...</translation> </message> <message> - <location filename="../UserInterface.ui" line="279"/> + <location filename="../UserInterface.ui" line="285"/> <source>&Remove selected</source> <translation>Auswahl entfe&rnen</translation> </message> @@ -2108,12 +2366,12 @@ Exportieren als:</translation> <translation type="obsolete">Strg+R</translation> </message> <message> - <location filename="../UserInterface.ui" line="287"/> + <location filename="../UserInterface.ui" line="293"/> <source>&Import files...</source> <translation>Dateien &importieren...</translation> </message> <message> - <location filename="../UserInterface.ui" line="290"/> + <location filename="../UserInterface.ui" line="296"/> <source>Ctrl+I</source> <translation>Strg+I</translation> </message> @@ -2122,16 +2380,17 @@ Exportieren als:</translation> <translation type="obsolete">GTA V Ordner nicht gefunden!</translation> </message> <message> - <location filename="../UserInterface.cpp" line="62"/> - <location filename="../UserInterface.cpp" line="220"/> + <location filename="../UserInterface.cpp" line="64"/> + <location filename="../UserInterface.cpp" line="234"/> + <location filename="../UserInterface.cpp" line="550"/> <source>Select Profile</source> <translation>Profil auswählen</translation> </message> <message> - <location filename="../UserInterface.ui" line="306"/> - <location filename="../OptionsDialog.cpp" line="452"/> - <location filename="../UserInterface.cpp" line="99"/> - <location filename="../UserInterface.cpp" line="495"/> + <location filename="../UserInterface.ui" line="312"/> + <location filename="../OptionsDialog.cpp" line="445"/> + <location filename="../UserInterface.cpp" line="104"/> + <location filename="../UserInterface.cpp" line="513"/> <source>Select GTA V Folder...</source> <translation>Wähle GTA V Ordner...</translation> </message> @@ -2140,7 +2399,7 @@ Exportieren als:</translation> <translation type="vanished">Wähle GTA V &Ordner...</translation> </message> <message> - <location filename="../UserInterface.cpp" line="346"/> + <location filename="../UserInterface.cpp" line="360"/> <source>Open File...</source> <translation>Datei öffnen...</translation> </message> @@ -2150,26 +2409,27 @@ Exportieren als:</translation> </message> <message> <location filename="../UserInterface.ui" line="20"/> - <location filename="../UserInterface.cpp" line="60"/> + <location filename="../UserInterface.cpp" line="62"/> <source>%2 - %1</source> <translation>%2 - %1</translation> </message> <message> - <location filename="../UserInterface.ui" line="220"/> - <location filename="../UserInterface.cpp" line="59"/> + <location filename="../UserInterface.ui" line="226"/> + <location filename="../UserInterface.cpp" line="60"/> + <location filename="../UserInterface.cpp" line="542"/> <source>&About %1</source> <translation>&Über %1</translation> </message> <message> - <location filename="../UserInterface.cpp" line="393"/> - <location filename="../UserInterface.cpp" line="409"/> - <location filename="../UserInterface.cpp" line="436"/> - <location filename="../UserInterface.cpp" line="441"/> + <location filename="../UserInterface.cpp" line="407"/> + <location filename="../UserInterface.cpp" line="423"/> + <location filename="../UserInterface.cpp" line="450"/> + <location filename="../UserInterface.cpp" line="455"/> <source>Open File</source> <translation>Datei öffnen</translation> </message> <message> - <location filename="../UserInterface.cpp" line="436"/> + <location filename="../UserInterface.cpp" line="450"/> <source>Can't open %1 because of not valid file format</source> <translation>Kann nicht %1 öffnen weil Dateiformat nicht gültig ist</translation> </message> @@ -2186,7 +2446,7 @@ Exportieren als:</translation> <translation type="obsolete">Grand Theft Auto V Ordner wurde nicht gefunden!</translation> </message> <message> - <location filename="../UserInterface.ui" line="131"/> + <location filename="../UserInterface.ui" line="134"/> <source>&Reload</source> <translation>&Neuladen</translation> </message> diff --git a/res/gta5sync_en_US.qm b/res/gta5sync_en_US.qm new file mode 100644 index 0000000000000000000000000000000000000000..a7fe0365dd97100a27318bb3caf55c4bfcc03940 GIT binary patch literal 18703 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 RA+^I9W6|qS&}?~m{|&%<qhA03 literal 0 HcmV?d00001 diff --git a/res/gta5sync_en_US.ts b/res/gta5sync_en_US.ts new file mode 100644 index 0000000..7720a27 --- /dev/null +++ b/res/gta5sync_en_US.ts @@ -0,0 +1,1619 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="en_US"> +<context> + <name>AboutDialog</name> + <message> + <location filename="../AboutDialog.ui" line="14"/> + <source>About %1</source> + <translation></translation> + </message> + <message> + <location filename="../AboutDialog.ui" line="29"/> + <source><span style=" font-weight:600;">%1</span><br/> +<br/> +%2<br/> +<br/> +Version %3<br/> +Created on %4<br/> +Built with Qt %5<br/> +Running with Qt %6<br/> +<br/> +%7</source> + <translation></translation> + </message> + <message> + <location filename="../AboutDialog.ui" line="75"/> + <source>&Close</source> + <translation></translation> + </message> + <message> + <location filename="../AboutDialog.cpp" line="41"/> + <source>Using %1 %2</source> + <extracomment>Using specific library, example Using libmyfuck</extracomment> + <translation></translation> + </message> + <message> + <location filename="../AboutDialog.cpp" line="43"/> + <source>Translated by %1</source> + <extracomment>Translated by translator, example Translated by Syping</extracomment> + <translation></translation> + </message> + <message> + <location filename="../AboutDialog.cpp" line="45"/> + <source>NAME_OF_TRANSLATOR</source> + <extracomment>Enter your name there</extracomment> + <translation>Syping</translation> + </message> + <message> + <location filename="../AboutDialog.cpp" line="47"/> + <source>TRANSLATOR_PROFILE</source> + <extracomment>Enter your proilfe there, example a GitHub profile, E-Mail with "mailto: afucker@sumfuck.com" or a webpage</extracomment> + <translation>https://github.com/Syping/</translation> + </message> + <message> + <location filename="../AboutDialog.cpp" line="78"/> + <source>A project for viewing and sync Grand Theft Auto V Snapmatic<br/> +Pictures and Savegames</source> + <translation></translation> + </message> + <message> + <location filename="../AboutDialog.cpp" line="80"/> + <source>A project for viewing Grand Theft Auto V Snapmatic<br/> +Pictures and Savegames</source> + <translation></translation> + </message> + <message> + <location filename="../AboutDialog.cpp" line="84"/> + <source>Copyright &copy; <a href="%1">%2</a> %3</source> + <translation></translation> + </message> + <message> + <location filename="../AboutDialog.cpp" line="86"/> + <source>%1 is licensed under <a href="https://www.gnu.org/licenses/gpl-3.0.html#content">GNU GPLv3</a></source> + <translation></translation> + </message> + <message> + <location filename="../config.h" line="62"/> + <source>Release</source> + <translation></translation> + </message> + <message> + <location filename="../config.h" line="68"/> + <source>Release Candidate</source> + <translation></translation> + </message> + <message> + <location filename="../config.h" line="74"/> + <source>Daily Build</source> + <translation></translation> + </message> + <message> + <location filename="../config.h" line="80"/> + <source>Developer</source> + <translation></translation> + </message> + <message> + <location filename="../config.h" line="86"/> + <source>Beta</source> + <translation></translation> + </message> + <message> + <location filename="../config.h" line="92"/> + <source>Alpha</source> + <translation></translation> + </message> +</context> +<context> + <name>CrewDatabase</name> + <message> + <location filename="../CrewDatabase.cpp" line="102"/> + <source>No Crew</source> + <translation></translation> + </message> +</context> +<context> + <name>ExportDialog</name> + <message> + <location filename="../ExportDialog.ui" line="14"/> + <source>Dialog</source> + <translation></translation> + </message> + <message> + <location filename="../ExportDialog.ui" line="45"/> + <source>Export Format</source> + <translation></translation> + </message> + <message> + <location filename="../ExportDialog.ui" line="51"/> + <source>&JPEG/PNG format</source> + <translation></translation> + </message> + <message> + <location filename="../ExportDialog.ui" line="58"/> + <source>GTA &Snapmatic format</source> + <translation></translation> + </message> + <message> + <location filename="../ExportDialog.ui" line="68"/> + <source>Export Size</source> + <translation></translation> + </message> + <message> + <location filename="../ExportDialog.ui" line="74"/> + <source>Default &Size</source> + <translation></translation> + </message> + <message> + <location filename="../ExportDialog.ui" line="81"/> + <source>&Desktop Size</source> + <translation></translation> + </message> + <message> + <location filename="../ExportDialog.ui" line="88"/> + <source>&Custom Size</source> + <translation></translation> + </message> + <message> + <location filename="../ExportDialog.ui" line="100"/> + <source>Custom Size:</source> + <translation></translation> + </message> + <message> + <location filename="../ExportDialog.ui" line="123"/> + <source>x</source> + <translation></translation> + </message> + <message> + <location filename="../ExportDialog.ui" line="198"/> + <source>&Export</source> + <translation></translation> + </message> + <message> + <location filename="../ExportDialog.ui" line="211"/> + <source>&Close</source> + <translation></translation> + </message> +</context> +<context> + <name>ImportDialog</name> + <message> + <location filename="../ImportDialog.ui" line="26"/> + <source>Import...</source> + <translation></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="90"/> + <source>Settings</source> + <translation></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="98"/> + <location filename="../ImportDialog.cpp" line="57"/> + <location filename="../ImportDialog.cpp" line="216"/> + <source>Background Colour: <span style="color: %1">%1</span></source> + <translation>Background Color: <span style="color: %1">%1</span></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="105"/> + <source>...</source> + <translation></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="135"/> + <source>Avatar</source> + <translation></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="148"/> + <source>Ignore Aspect Ratio</source> + <translation></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="194"/> + <source>Import picture</source> + <translation></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="197"/> + <source>&OK</source> + <translation></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="210"/> + <source>Discard picture</source> + <translation></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="213"/> + <source>&Cancel</source> + <translation></translation> + </message> + <message> + <location filename="../ImportDialog.cpp" line="173"/> + <source>Snapmatic Avatar Zone</source> + <translation></translation> + </message> + <message> + <location filename="../ImportDialog.cpp" line="173"/> + <source>Are you sure to use a square image outside of the Avatar Zone? +When you want to use it as Avatar the image will be detached!</source> + <translation></translation> + </message> + <message> + <location filename="../ImportDialog.cpp" line="212"/> + <source>Select Colour...</source> + <translation>Select Color...</translation> + </message> +</context> +<context> + <name>MapPreviewDialog</name> + <message> + <location filename="../MapPreviewDialog.ui" line="26"/> + <source>Snapmatic Map Viewer</source> + <translation></translation> + </message> +</context> +<context> + <name>OptionsDialog</name> + <message> + <location filename="../OptionsDialog.ui" line="14"/> + <source>%1 - Settings</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="27"/> + <source>Profiles</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="33"/> + <source>Content Open/Select Mode</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="39"/> + <source>Open with Singleclick</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="49"/> + <source>Open with Doubleclick</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="56"/> + <source>Select with Singleclick</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="66"/> + <source>Default Profile</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="78"/> + <source>Custom GTA V Folder</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="84"/> + <source>Force using Custom Folder</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="96"/> + <source>...</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="122"/> + <source>Pictures</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="128"/> + <source>Export Size</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="134"/> + <source>Default: %1x%2</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="144"/> + <source>Screen Resolution: %1x%2</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="153"/> + <location filename="../OptionsDialog.ui" line="163"/> + <source>Custom Size:</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="189"/> + <source>x</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="229"/> + <source>Ignore Aspect Ratio</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="241"/> + <source>Export Quality</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="247"/> + <source>Enable Custom Quality</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="259"/> + <source>Quality:</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="288"/> + <source>%1%</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="303"/> + <source>Picture Viewer</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="309"/> + <source>Enable Navigation Bar</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="333"/> + <source>Players</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="373"/> + <source>ID</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="378"/> + <source>Name</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="387"/> + <location filename="../OptionsDialog.ui" line="393"/> + <source>Language</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="419"/> + <source>Sync</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="425"/> + <source>Sync is not implemented at current time</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="463"/> + <source>Apply changes</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="466"/> + <source>&OK</source> + <extracomment>OK, Cancel, Apply</extracomment> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="479"/> + <source>Discard changes</source> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="482"/> + <source>&Cancel</source> + <extracomment>OK, Cancel, Apply</extracomment> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.cpp" line="132"/> + <source>%1 (Next Closest Language)</source> + <comment>First language a person can talk with a different person/application. "Native" or "Not Native".</comment> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.cpp" line="132"/> + <source>System</source> + <comment>System in context of System default</comment> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.cpp" line="289"/> + <source>%1</source> + <comment>%1</comment> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.cpp" line="289"/> + <source>The new Custom Folder will initialise after you restart %1.</source> + <translation>The new Custom Folder will initialize after you restart %1.</translation> + </message> + <message> + <location filename="../OptionsDialog.cpp" line="299"/> + <source>No Profile</source> + <comment>No Profile, as default</comment> + <translation></translation> + </message> + <message> + <location filename="../OptionsDialog.cpp" line="307"/> + <location filename="../OptionsDialog.cpp" line="311"/> + <location filename="../OptionsDialog.cpp" line="313"/> + <source>Profile: %1</source> + <translation></translation> + </message> +</context> +<context> + <name>PictureDialog</name> + <message> + <location filename="../PictureDialog.ui" line="14"/> + <source>%1 - Snapmatic Picture Viewer</source> + <translation></translation> + </message> + <message> + <location filename="../PictureDialog.ui" line="117"/> + <source><span style=" font-weight:600;">Title: </span>%6<br/> +<span style=" font-weight:600;">Location: </span>%7 (%1, %2, %3)<br/> +<span style=" font-weight:600;">Players: </span>%4 (Crew %5)<br/> +<span style=" font-weight:600;">Created: </span>%8</source> + <translation></translation> + </message> + <message> + <location filename="../PictureDialog.ui" line="177"/> + <source>Manage picture</source> + <translation></translation> + </message> + <message> + <location filename="../PictureDialog.ui" line="180"/> + <source>&Manage</source> + <translation></translation> + </message> + <message> + <location filename="../PictureDialog.ui" line="199"/> + <source>Close viewer</source> + <translation></translation> + </message> + <message> + <location filename="../PictureDialog.ui" line="202"/> + <source>&Close</source> + <translation></translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="145"/> + <source>Export as &Picture...</source> + <translation></translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="146"/> + <source>Export as &Snapmatic...</source> + <translation></translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="148"/> + <source>Open &Map View...</source> + <translation></translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="150"/> + <source>&Edit Properties...</source> + <translation></translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="373"/> + <source>Key 1 - Avatar Preview Mode +Key 2 - Toggle Overlay +Arrow Keys - Navigate</source> + <translation></translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="433"/> + <location filename="../PictureDialog.cpp" line="476"/> + <source>Snapmatic Picture Viewer</source> + <translation></translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="433"/> + <location filename="../PictureDialog.cpp" line="476"/> + <source>Failed at %1</source> + <translation></translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="475"/> + <location filename="../PictureDialog.cpp" line="614"/> + <source>No Players</source> + <translation></translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="475"/> + <location filename="../PictureDialog.cpp" line="589"/> + <source>No Crew</source> + <translation></translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="475"/> + <source>Unknown Location</source> + <translation></translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="560"/> + <source>Avatar Preview Mode +Press 1 for Default View</source> + <translation></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="90"/> + <source>Export as Picture...</source> + <translation></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="91"/> + <location filename="../PictureExport.cpp" line="223"/> + <source>Export</source> + <translation></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="94"/> + <source>JPEG Graphics (*.jpg *.jpeg)</source> + <translation></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="95"/> + <source>Portable Network Graphics (*.png)</source> + <translation></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="145"/> + <location filename="../PictureExport.cpp" line="149"/> + <location filename="../PictureExport.cpp" line="183"/> + <location filename="../PictureExport.cpp" line="189"/> + <source>Export as Picture</source> + <translation></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="145"/> + <location filename="../PictureExport.cpp" line="260"/> + <source>Overwrite %1 with current Snapmatic picture?</source> + <translation></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="149"/> + <location filename="../PictureExport.cpp" line="264"/> + <source>Failed to overwrite %1 with current Snapmatic picture</source> + <translation></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="183"/> + <location filename="../PictureExport.cpp" line="279"/> + <location filename="../PictureExport.cpp" line="288"/> + <source>Failed to export current Snapmatic picture</source> + <translation></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="189"/> + <location filename="../PictureExport.cpp" line="299"/> + <source>No valid file is selected</source> + <translation></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="222"/> + <source>Export as Snapmatic...</source> + <translation></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="226"/> + <source>GTA V Export (*.g5e)</source> + <translation></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="227"/> + <source>GTA V Raw Export (*.auto)</source> + <translation></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="228"/> + <source>Snapmatic pictures (PGTA*)</source> + <translation></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="260"/> + <location filename="../PictureExport.cpp" line="264"/> + <location filename="../PictureExport.cpp" line="279"/> + <location filename="../PictureExport.cpp" line="288"/> + <location filename="../PictureExport.cpp" line="293"/> + <location filename="../PictureExport.cpp" line="299"/> + <source>Export as Snapmatic</source> + <translation></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="293"/> + <source>Exported Snapmatic to "%1" because of using the .auto extension.</source> + <translation></translation> + </message> +</context> +<context> + <name>ProfileInterface</name> + <message> + <location filename="../ProfileInterface.ui" line="14"/> + <source>Profile Interface</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.ui" line="55"/> + <source>Loading file %1 of %2 files</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.ui" line="172"/> + <source>%1 %2</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.ui" line="198"/> + <source>Import file</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.ui" line="201"/> + <source>&Import...</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.ui" line="217"/> + <source>Close profile</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.ui" line="220"/> + <source>&Close</source> + <translation></translation> + </message> + <message> + <location filename="../ExportThread.cpp" line="97"/> + <location filename="../ExportThread.cpp" line="136"/> + <location filename="../ExportThread.cpp" line="157"/> + <source>Export file %1 of %2 files</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="65"/> + <source>Enabled pictures: %1 of %2</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="129"/> + <source>Loading...</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="426"/> + <location filename="../ProfileInterface.cpp" line="491"/> + <source>Import...</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="427"/> + <location filename="../ProfileInterface.cpp" line="470"/> + <location filename="../ProfileInterface.cpp" line="522"/> + <location filename="../ProfileInterface.cpp" line="542"/> + <location filename="../ProfileInterface.cpp" line="558"/> + <location filename="../ProfileInterface.cpp" line="674"/> + <location filename="../ProfileInterface.cpp" line="755"/> + <location filename="../ProfileInterface.cpp" line="760"/> + <location filename="../ProfileInterface.cpp" line="778"/> + <location filename="../ProfileInterface.cpp" line="783"/> + <location filename="../ProfileInterface.cpp" line="794"/> + <location filename="../ProfileInterface.cpp" line="831"/> + <location filename="../ProfileInterface.cpp" line="837"/> + <source>Import</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="442"/> + <source>Importable files (%1)</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="443"/> + <location filename="../UserInterface.cpp" line="364"/> + <source>GTA V Export (*.g5e)</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="444"/> + <location filename="../UserInterface.cpp" line="365"/> + <source>Savegames files (SGTA*)</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="445"/> + <location filename="../UserInterface.cpp" line="366"/> + <source>Snapmatic pictures (PGTA*)</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="446"/> + <source>All image files (%1)</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="447"/> + <location filename="../UserInterface.cpp" line="367"/> + <source>All files (**)</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="470"/> + <location filename="../ProfileInterface.cpp" line="760"/> + <location filename="../UserInterface.cpp" line="455"/> + <source>No valid file is selected</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="492"/> + <location filename="../ProfileInterface.cpp" line="507"/> + <source>Import file %1 of %2 files</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="522"/> + <source>Import failed with... + +%1</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="542"/> + <location filename="../UserInterface.cpp" line="407"/> + <source>Failed to read Snapmatic picture</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="558"/> + <location filename="../UserInterface.cpp" line="423"/> + <source>Failed to read Savegame file</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="674"/> + <source>Can't import %1 because file can't be parsed properly</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="755"/> + <source>Can't import %1 because file format can't be detected</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="778"/> + <source>Failed to import the Snapmatic picture, file not begin with PGTA or end with .g5e</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="783"/> + <source>Failed to import the Snapmatic picture, the picture is already in the game</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="794"/> + <source>Failed to import the Snapmatic picture, can't copy the file into profile</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="831"/> + <source>Failed to import the Savegame, can't copy the file into profile</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="837"/> + <source>Failed to import the Savegame, no Savegame slot is left</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="900"/> + <location filename="../ProfileInterface.cpp" line="938"/> + <location filename="../ProfileInterface.cpp" line="1017"/> + <location filename="../ProfileInterface.cpp" line="1037"/> + <source>Export selected</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="923"/> + <location filename="../ProfileInterface.cpp" line="941"/> + <source>JPG pictures and GTA Snapmatic</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="924"/> + <location filename="../ProfileInterface.cpp" line="946"/> + <source>JPG pictures only</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="925"/> + <location filename="../ProfileInterface.cpp" line="950"/> + <source>GTA Snapmatic only</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="938"/> + <source>%1Export Snapmatic pictures%2<br><br>JPG pictures make it possible to open the picture with a Image Viewer<br>GTA Snapmatic make it possible to import the picture into the game<br><br>Export as:</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="983"/> + <source>Export selected...</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="984"/> + <source>Initialising export...</source> + <translation>Initializing export...</translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1017"/> + <source>Export failed with... + +%1</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1037"/> + <location filename="../ProfileInterface.cpp" line="1079"/> + <source>No Snapmatic pictures or Savegames files are selected</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1045"/> + <location filename="../ProfileInterface.cpp" line="1073"/> + <location filename="../ProfileInterface.cpp" line="1079"/> + <source>Remove selected</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1045"/> + <source>You really want remove the selected Snapmatic picutres and Savegame files?</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1073"/> + <source>Failed at remove the complete selected Snapmatic pictures and/or Savegame files</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.cpp" line="363"/> + <source>All profile files (*.g5e SGTA* PGTA*)</source> + <translation></translation> + </message> +</context> +<context> + <name>QApplication</name> + <message> + <location filename="../main.cpp" line="66"/> + <source>Font</source> + <translation></translation> + </message> + <message> + <location filename="../main.cpp" line="66"/> + <source>Selected Font: %1</source> + <translation></translation> + </message> +</context> +<context> + <name>SavegameDialog</name> + <message> + <location filename="../SavegameDialog.ui" line="14"/> + <location filename="../SavegameDialog.cpp" line="38"/> + <source>Savegame Viewer</source> + <translation></translation> + </message> + <message> + <location filename="../SavegameDialog.ui" line="23"/> + <source><span style=" font-weight:600;">Savegame</span><br><br>%1</source> + <translation></translation> + </message> + <message> + <location filename="../SavegameDialog.ui" line="70"/> + <source>&Export</source> + <translation></translation> + </message> + <message> + <location filename="../SavegameDialog.ui" line="83"/> + <source>&Close</source> + <translation></translation> + </message> + <message> + <location filename="../SavegameDialog.cpp" line="38"/> + <source>Failed at %1</source> + <translation></translation> + </message> +</context> +<context> + <name>SavegameWidget</name> + <message> + <location filename="../SavegameWidget.ui" line="14"/> + <source>Savegame Widget</source> + <translation></translation> + </message> + <message> + <location filename="../SavegameWidget.ui" line="67"/> + <source>SAVE %3 - %1<br>%2</source> + <translation></translation> + </message> + <message> + <location filename="../SavegameWidget.ui" line="83"/> + <source>View savegame</source> + <translation></translation> + </message> + <message> + <location filename="../SavegameWidget.ui" line="86"/> + <source>View</source> + <translation></translation> + </message> + <message> + <location filename="../SavegameWidget.ui" line="99"/> + <source>Copy savegame</source> + <translation></translation> + </message> + <message> + <location filename="../SavegameWidget.ui" line="102"/> + <location filename="../SavegameCopy.cpp" line="48"/> + <source>Export</source> + <translation></translation> + </message> + <message> + <location filename="../SavegameWidget.ui" line="118"/> + <location filename="../SavegameWidget.cpp" line="131"/> + <location filename="../SavegameWidget.cpp" line="144"/> + <source>Delete savegame</source> + <translation></translation> + </message> + <message> + <location filename="../SavegameWidget.ui" line="121"/> + <source>Delete</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1225"/> + <source>&View</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1226"/> + <source>&Export</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1227"/> + <source>&Remove</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1229"/> + <source>&Select</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1230"/> + <source>&Deselect</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1233"/> + <source>Select &All</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1237"/> + <source>&Deselect All</source> + <translation></translation> + </message> + <message> + <location filename="../SavegameCopy.cpp" line="51"/> + <source>Savegame files (SGTA*)</source> + <translation></translation> + </message> + <message> + <location filename="../SavegameCopy.cpp" line="52"/> + <source>All files (**)</source> + <translation></translation> + </message> + <message> + <location filename="../SavegameCopy.cpp" line="70"/> + <location filename="../SavegameCopy.cpp" line="74"/> + <location filename="../SavegameCopy.cpp" line="87"/> + <location filename="../SavegameCopy.cpp" line="93"/> + <source>Export Savegame</source> + <translation></translation> + </message> + <message> + <location filename="../SavegameCopy.cpp" line="70"/> + <source>Overwrite %1 with current Savegame?</source> + <translation></translation> + </message> + <message> + <location filename="../SavegameCopy.cpp" line="74"/> + <source>Failed to overwrite %1 with current Savegame</source> + <translation></translation> + </message> + <message> + <location filename="../SavegameCopy.cpp" line="87"/> + <source>Failed to export current Savegame</source> + <translation></translation> + </message> + <message> + <location filename="../SavegameCopy.cpp" line="93"/> + <source>No valid file is selected</source> + <translation></translation> + </message> + <message> + <location filename="../SavegameWidget.cpp" line="57"/> + <source>Export Savegame...</source> + <translation></translation> + </message> + <message> + <location filename="../SavegameWidget.cpp" line="60"/> + <location filename="../SavegameWidget.cpp" line="117"/> + <source>AUTOSAVE - %1 +%2</source> + <translation></translation> + </message> + <message> + <location filename="../SavegameWidget.cpp" line="61"/> + <location filename="../SavegameWidget.cpp" line="118"/> + <source>SAVE %3 - %1 +%2</source> + <translation></translation> + </message> + <message> + <location filename="../SavegameWidget.cpp" line="89"/> + <location filename="../SavegameWidget.cpp" line="90"/> + <source>WRONG FORMAT</source> + <translation></translation> + </message> + <message> + <location filename="../SavegameWidget.cpp" line="111"/> + <source>UNKNOWN</source> + <translation></translation> + </message> + <message> + <location filename="../SavegameWidget.cpp" line="131"/> + <source>Are you sure to delete %1 from your savegames?</source> + <translation></translation> + </message> + <message> + <location filename="../SavegameWidget.cpp" line="144"/> + <source>Failed at deleting %1 from your savegames</source> + <translation></translation> + </message> +</context> +<context> + <name>SnapmaticEditor</name> + <message> + <location filename="../SnapmaticEditor.ui" line="14"/> + <location filename="../SnapmaticEditor.ui" line="81"/> + <location filename="../SnapmaticEditor.cpp" line="245"/> + <source>Snapmatic Properties</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="44"/> + <source>Snapmatic Type</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="50"/> + <source>Editor</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="57"/> + <source>Selfie</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="64"/> + <source>Regular</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="71"/> + <source>Mugshot</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="87"/> + <source>Meme</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="94"/> + <source>Director</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="104"/> + <source>Snapmatic Values</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="113"/> + <location filename="../SnapmaticEditor.cpp" line="200"/> + <source>Crew: %1 (%2)</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="126"/> + <location filename="../SnapmaticEditor.cpp" line="185"/> + <source>Title: %1 (%2)</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="136"/> + <location filename="../SnapmaticEditor.cpp" line="189"/> + <location filename="../SnapmaticEditor.cpp" line="193"/> + <source>Appropriate: %1</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="149"/> + <source>Extras</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="155"/> + <source>Qualify as Avatar automatically at apply</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="168"/> + <source>Qualify as Avatar allows you to use this Snapmatic as a Social Club profile picture</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="218"/> + <source>&Apply</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticEditor.ui" line="231"/> + <source>&Cancel</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticEditor.cpp" line="184"/> + <location filename="../SnapmaticEditor.cpp" line="199"/> + <source>Edit</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticEditor.cpp" line="189"/> + <source>Yes</source> + <comment>Yes, should work fine</comment> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticEditor.cpp" line="193"/> + <source>No</source> + <comment>No, could lead to issues</comment> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticEditor.cpp" line="245"/> + <source>Patching of Snapmatic Properties failed because of I/O Error</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticEditor.cpp" line="295"/> + <source>Snapmatic Title</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticEditor.cpp" line="295"/> + <source>New Snapmatic title:</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticEditor.cpp" line="324"/> + <source>Snapmatic Crew</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticEditor.cpp" line="324"/> + <source>New Snapmatic crew:</source> + <translation></translation> + </message> +</context> +<context> + <name>SnapmaticPicture</name> + <message> + <location filename="../SnapmaticPicture.cpp" line="411"/> + <source>PHOTO - %1</source> + <translation></translation> + </message> +</context> +<context> + <name>SnapmaticWidget</name> + <message> + <location filename="../SnapmaticWidget.ui" line="14"/> + <source>Snapmatic Widget</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticWidget.ui" line="85"/> + <source>PHOTO - 00/00/00 00:00:00</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticWidget.ui" line="101"/> + <source>View picture</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticWidget.ui" line="104"/> + <source>View</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticWidget.ui" line="120"/> + <source>Copy picture</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticWidget.ui" line="123"/> + <source>Copy</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticWidget.ui" line="136"/> + <source>Export picture</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticWidget.ui" line="139"/> + <source>Export</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticWidget.ui" line="152"/> + <location filename="../SnapmaticWidget.cpp" line="144"/> + <location filename="../SnapmaticWidget.cpp" line="153"/> + <source>Delete picture</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticWidget.ui" line="155"/> + <source>Delete</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1178"/> + <source>Edi&t</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1181"/> + <source>Show &In-game</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1185"/> + <source>Hide &In-game</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1187"/> + <source>&Edit Properties...</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1188"/> + <source>&Export</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1189"/> + <source>Export as &Picture...</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1190"/> + <source>Export as &Snapmatic...</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1191"/> + <source>&View</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1194"/> + <source>&Remove</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1196"/> + <source>&Select</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1197"/> + <source>&Deselect</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1200"/> + <source>Select &All</source> + <translation></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1204"/> + <source>&Deselect All</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticWidget.cpp" line="144"/> + <source>Are you sure to delete %1 from your Snapmatic pictures?</source> + <translation></translation> + </message> + <message> + <location filename="../SnapmaticWidget.cpp" line="153"/> + <source>Failed at deleting %1 from your Snapmatic pictures</source> + <translation></translation> + </message> +</context> +<context> + <name>UserInterface</name> + <message> + <location filename="../UserInterface.ui" line="20"/> + <location filename="../UserInterface.cpp" line="62"/> + <source>%2 - %1</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="74"/> + <source>Select profile</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="105"/> + <source>%1 %2</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="131"/> + <source>Reload profile overview</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="134"/> + <source>&Reload</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="150"/> + <source>Close %1</source> + <extracomment>Close %1 <- (gta5view/gta5sync) - %1 will be replaced automatically</extracomment> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="153"/> + <source>&Close</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="179"/> + <source>&File</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="189"/> + <source>&Help</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="195"/> + <source>&Edit</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="201"/> + <source>&Profile</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="205"/> + <source>&Selection visibility</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="226"/> + <location filename="../UserInterface.cpp" line="60"/> + <location filename="../UserInterface.cpp" line="542"/> + <source>&About %1</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="229"/> + <source>Ctrl+P</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="234"/> + <source>&Exit</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="237"/> + <source>Exit</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="240"/> + <source>Ctrl+Q</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="245"/> + <source>Close &Profile</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="248"/> + <source>Ctrl+End</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="253"/> + <source>&Settings</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="256"/> + <source>Ctrl+S</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="261"/> + <source>Select &All</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="264"/> + <source>Ctrl+A</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="269"/> + <source>&Deselect All</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="272"/> + <source>Ctrl+D</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="277"/> + <source>&Export selected...</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="280"/> + <source>Ctrl+E</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="285"/> + <source>&Remove selected</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="288"/> + <source>Ctrl+Del</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="293"/> + <source>&Import files...</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="296"/> + <source>Ctrl+I</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="301"/> + <source>&Open File...</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="304"/> + <source>Ctrl+O</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="309"/> + <location filename="../UserInterface.cpp" line="163"/> + <source>Select &GTA V Folder...</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="312"/> + <location filename="../OptionsDialog.cpp" line="445"/> + <location filename="../UserInterface.cpp" line="104"/> + <location filename="../UserInterface.cpp" line="513"/> + <source>Select GTA V Folder...</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="315"/> + <source>Ctrl+G</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="320"/> + <source>Show In-gam&e</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="323"/> + <source>Shift+E</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="328"/> + <source>Hi&de In-game</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="331"/> + <source>Shift+D</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.cpp" line="64"/> + <location filename="../UserInterface.cpp" line="234"/> + <location filename="../UserInterface.cpp" line="550"/> + <source>Select Profile</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.cpp" line="360"/> + <source>Open File...</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.cpp" line="407"/> + <location filename="../UserInterface.cpp" line="423"/> + <location filename="../UserInterface.cpp" line="450"/> + <location filename="../UserInterface.cpp" line="455"/> + <source>Open File</source> + <translation></translation> + </message> + <message> + <location filename="../UserInterface.cpp" line="450"/> + <source>Can't open %1 because of not valid file format</source> + <translation></translation> + </message> +</context> +</TS> diff --git a/res/gta5sync_fr.qm b/res/gta5sync_fr.qm index 2b5dd18f811ea60d0e80dc7589cceb57babdac1b..affe051b68b31e35db7fe008f38fc898fa6add59 100644 GIT binary patch delta 2261 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 M+Pxe#CC8lq2Wk0ih5!Hn delta 3548 zcmb7F3sh8f8vpKahncza5*Xy+>k<yaAmczHsAxRojfe{Ikk>d2Ff=nD53@a6qq%PR zqSm{toy}EA<&;vXlaD0zAX2fVn7P`!-3p7`6J@fsR<^&H>k75op0j7po!^~1|Nr;> ze&6@|{&)Biv*#+~N;+N>{O6G!9p}O(pRVpa`F<*qyord`5GhR}hFm3*tRqsV6S0?w z{Pz+`mk=$r6Gg@oX+nvj=M$-Ril|vj6sy7W14LDQME7nbw(9|+(g%p`VTqPJMC>52 zwue~P<wByAD<n-qpaPzxS-^lck{(PW3gSpQ_zKZti-?uKB6;UB5D2HpxQB@hlSQn& zK?YCY>NqlZ0$10O;ewvXEG5I=A;O$Q(I>NsrVmlHCtmtXB9;u2Ye6DZC00?o70Onw zqRb7zdxj}zP6yG{)0BGvzst6grNRY;v&dDvlqj&3Ha~w6N>XWGjUQ2}oVqvm6UnC1 zv72o~`feJ!gnirx^x0EVqGem?D`!4Y)LDjmZzj>AE)k2fT;fgDyUdhl?jrJ2Gqv}Q zLU}&Za`z1=zsfwgqmt;ZMa-MIw}_H5m@n0bi00)>%3r~{(q|=(4TVG&mt<qBlPE+g z*<Bq=6h2wRwC5#H-#?cq|8B{Ck02&bMEP<NLtT%HH#4t@nA#v>)jmnLd59=8L~`Uv zJW-BLa`a3%Q8p(z#YQ3EsAS*|TA~?l$>1vdUppfCa3Ggx;x5TYT{@!5*^=)}0YpWg z`Y5{oLR5aiC%$bI&-eSJbXh_0rcY7#qeQMrjL&1m3Ze<!KIhj$ne4YdpUy$zxnHrq z%6=@YX5+t`hh7)32`LD$cpF=gxC?~7W*_xi4pW|EH$O29bg)~?+F@8?543+pRMQAV z1#9*IvCrxU{06ul_)p+5;E&`Y>oxYkW7t+Z4afkO1ATyxu-!BFp#rN!Ed7psetj`| z8pHM|SEBca*;Bh_!?XqL=}MG1<|sS3`u9ZBCWx4&60z(oJ9vCO)_=~v_u&Sjuu1G^ z6+J|{0`~gHFTzy%W$d>XUxVw1*zZrogYgt8>j^aXs8sj#c8p_?bfO0%-jc>R9zueC z5m!7YEjxdPD7Q%J*li&)y(HZ+6G{u$NIP#965V}5x_4bEO#O!R;Qo{F)Ts2Mt03<C zfv+^dP2}@y-zohr%xU#b-(?kgqWA;87D*$<G10fa2&HAaWwIfEqEMxb8*N3eOGLb9 zhKM=aWs%?aVHy_5s_r`iqL0dKDR8;!RT1Z>%kKLde#cCZIr>06I9k?t<s+OKmu1cG zV0vZ*${u&^YJ>7lS;zSf%;`<p-d-p0nCwvQ7evLKvLhE~6D=&2ojC*3`K^`xbus3D zLWx|O0dG_c$*1%iaoB8?r`+6&*3`&TuXp0m(aZCm9>jD=<oSnDk$`*Tj?O)pnwRB` zy;hiblYDL1+c=mO$X%z-fJtGBy#FjpGiy*j(gPxz%Zi}Wy;yKU5%hjC5``=D70(dO z->8WAHXLrwP(-akAa19Keisy(+uK3hp{S6dw1LMIE4PDq-b95x3ude;SJ-QTzEVZ= zH*rL1Hx#Yg&^p;gmtu=C9;Uc1;)?5vy}kKFbsH1|$?!%-x8g#14ovo>;<7OT2NI(g zxeTSY0pLEO2I81&Ad=b5sRQqV7Y=d!VkDRt&FR->qtr_|(`;07aWpr-b_WQ(En>ws z5$jz2+~Q#@%q!=LM>ItB9b65eBD!Ze+s@~R_-D8+o1VhEppbha8v&G?MAT%8n7@iU zJ~<F4<_7MyYi%Huz@1CQ6s5k;4X%EHND(Ds=*uFec8a*@mWZwr4R?835sugd?yddT ziL`m#Cx-`!7R=^`UxNvgdX&sjm}lVxWylNt=)F`~_68KDf1zBjL1h9*lw0Bp;qo}; zmW&}hpC@8TuCo2sWK7c)<zw^-<~?265ri>aKA_wY{Tr-X<3$&hY*L<bAh68=L;#zg z^6bK4B4es@uoa2xCn_)g$%>QgS>>A@czF~)r~F6HJ5bgoqP9oH{xKab%U3C`jS|gn zSLq%JK(Dh^Q(nTGaj8TV9r-l`ZBs3m)gbQYs+L?-YEG|eV_FA#EFV;DkHG`Quxbax z;^j~-;=Mnp_G-a6Ia_sNqy=aELRAj~RLfPb=LX>{U#p%p3|AL^uQt5f0fOb~gpC+q z|JT(Cn{lEktFtKToI(6M8Ovx;Dp$@H%$`dhpKz;0_3kSsXM{on2TcqwQ4a5}u zPW?`ofZivnKXD>K><#s|`R8HMhc&F{NRB(Gd7;{dxh@tlV~IAj0YnqO)GoY^-sg8~ zvobsfRhEclx3tcShf#?qv`y`3mBONZ>c=9YtaR;xN#~FtP^RrWjuI!lsvUjOh(Goq zdc!uiL|&o{)ldYb&}uSME3Rfaj%xD7C5sS#2$(FC1tiW$#FA{PBPTUdGg)!*WC!xN zGgA{jp69JXdFUjGE<#wTi;7OdmNYzeQj2%P>i@mX*FPfHYHbqgb>YItfx*K50Dob# zZeO;6^c0Ick-#`$3)%2pgYOn^RwwROdbvd1A+FQM@{#&D-d4+-SDS5i^GdrlN>~~c z<TeFXa<d+yJTG+%)q}hfvaIC5<%E7uXpb!W?SI<HD)db&)z2%exAJzgv#!ltXXP#R zxU=&2+w69})qJ0ox7OBLEv-T-ALDMH*2@UCv`E3K_jkV-cG@S%KpBYH?9Cw-&WsGJ zg-%|ly~A0WW^Zh<3TFKhCRw;@oW?{5yBCB;lF{?IvuaZMnx@9)R^HsgM`RYJ@XMX% zCWpDzW)XIWg-9sTvvaNunao~QJbI8r1(f--Fd^f@<P>D`O*TtwTeEds5W!*$5!&Y| zf`i7E{xqRkAH>Y@<P(G#|A?Q`4E?1|UX~`$F4K6HUXFJ}29E6>Pwq~_IsdWsXYzvo zdjKRC`d1{QF#+y_dW}!&ba;BKR2~xPD3!-+21IOtzv^h5t8xm`@05y<G#DG2>V)2z z!R}L$`HaNUEL7=348fSBHnQMyB2WYT4+r5In<_<qBj02<Kd>z<#O*Lt`Z76!!=%q0 zuW5XK-pi%QYtu0<Q&QkOo5SP9TASV4a+?lsFg7{sgoCC&W|^>RPK@xN#i%x=nVmCQ zvD)Jt;ix52IAWUUZi%ht)M5etJ-j#T!~AsF-etVi>oaQ&FEl1h6(Zt--Ph)aGfV1W zWgFzx<J)8D7KrpPza0X$6KB!$TvSm<@!o+NtLQjI!i3oH=_WCyXGq7y)WusN1{J<7 vDKB=0TeIN!)bYa+{j;|J;&2#^M&VFt2;&`(r16#hzsBQs828I7_GtbE?iZ+& diff --git a/res/gta5sync_fr.ts b/res/gta5sync_fr.ts index 42e78d2..78dc45b 100644 --- a/res/gta5sync_fr.ts +++ b/res/gta5sync_fr.ts @@ -111,43 +111,63 @@ Copyright &copy; <a href="%5">%6</a> %7<br/> <translation>&Fermer</translation> </message> <message> - <location filename="../AboutDialog.cpp" line="40"/> <source>Using %1 %2</source> <comment>Exp. Using libmyfuck</comment> - <translation>Utilise %1 %2</translation> + <translation type="vanished">Utilise %1 %2</translation> + </message> + <message> + <source>Translated by %1</source> + <comment>Exp. Translated by Syping</comment> + <translation type="vanished">Traduit par %1</translation> + </message> + <message> + <source>NAME_OF_TRANSLATOR</source> + <comment>Your Name (The person behind your screen looking at this text!)</comment> + <translation type="vanished">Ganjalo</translation> + </message> + <message> + <source>TRANSLATOR_PROFILE</source> + <comment>mailto: http:// https:// Exp. https://github.com/Syping/</comment> + <translation type="vanished">https://github.com/Ganjalo/</translation> </message> <message> <location filename="../AboutDialog.cpp" line="41"/> - <source>Translated by %1</source> - <comment>Exp. Translated by Syping</comment> - <translation>Traduit par %1</translation> - </message> - <message> - <location filename="../AboutDialog.cpp" line="42"/> - <source>NAME_OF_TRANSLATOR</source> - <comment>Your Name (The person behind your screen looking at this text!)</comment> - <translation>Ganjalo</translation> + <source>Using %1 %2</source> + <extracomment>Using specific library, example Using libmyfuck</extracomment> + <translation>Utilise %1 %2</translation> </message> <message> <location filename="../AboutDialog.cpp" line="43"/> + <source>Translated by %1</source> + <extracomment>Translated by translator, example Translated by Syping</extracomment> + <translation>Traduit par %1</translation> + </message> + <message> + <location filename="../AboutDialog.cpp" line="45"/> + <source>NAME_OF_TRANSLATOR</source> + <extracomment>Enter your name there</extracomment> + <translation>Ganjalo</translation> + </message> + <message> + <location filename="../AboutDialog.cpp" line="47"/> <source>TRANSLATOR_PROFILE</source> - <comment>mailto: http:// https:// Exp. https://github.com/Syping/</comment> + <extracomment>Enter your proilfe there, example a GitHub profile, E-Mail with "mailto: afucker@sumfuck.com" or a webpage</extracomment> <translation>https://github.com/Ganjalo/</translation> </message> <message> - <location filename="../AboutDialog.cpp" line="64"/> + <location filename="../AboutDialog.cpp" line="80"/> <source>A project for viewing Grand Theft Auto V Snapmatic<br/> Pictures and Savegames</source> <translation>Un outil pour gérer les photos Snapmatic<br/> et les fichiers de sauvegarde de Grand Theft Auto V</translation> </message> <message> - <location filename="../AboutDialog.cpp" line="68"/> + <location filename="../AboutDialog.cpp" line="84"/> <source>Copyright &copy; <a href="%1">%2</a> %3</source> <translation>Copyright &copy; <a href="%1">%2</a> %3</translation> </message> <message> - <location filename="../AboutDialog.cpp" line="70"/> + <location filename="../AboutDialog.cpp" line="86"/> <source>%1 is licensed under <a href="https://www.gnu.org/licenses/gpl-3.0.html#content">GNU GPLv3</a></source> <translation>%1 est distribué sous license <a href="https://www.gnu.org/licenses/gpl-3.0.html#content">GNU GPLv3</a></translation> </message> @@ -156,17 +176,47 @@ et les fichiers de sauvegarde de Grand Theft Auto V</translation> <translation type="vanished">Copyright &copy; <a href="%1">%2</a> %3<br/>%4 est distribué sous license <a href="https://www.gnu.org/licenses/gpl-3.0.html#content">GNU GPLv3</a></translation> </message> <message> - <location filename="../AboutDialog.cpp" line="62"/> + <location filename="../AboutDialog.cpp" line="78"/> <source>A project for viewing and sync Grand Theft Auto V Snapmatic<br/> Pictures and Savegames</source> <translation>Un outil pour gérer et synchroniser les photos Snapmatic<br/> et les fichiers de sauvegarde de Grand Theft Auto V</translation> </message> + <message> + <location filename="../config.h" line="62"/> + <source>Release</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../config.h" line="68"/> + <source>Release Candidate</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../config.h" line="74"/> + <source>Daily Build</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../config.h" line="80"/> + <source>Developer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../config.h" line="86"/> + <source>Beta</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../config.h" line="92"/> + <source>Alpha</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>CrewDatabase</name> <message> - <location filename="../CrewDatabase.cpp" line="64"/> + <location filename="../CrewDatabase.cpp" line="102"/> <source>No Crew</source> <translation>Aucun crew</translation> </message> @@ -247,30 +297,87 @@ et les fichiers de sauvegarde de Grand Theft Auto V</translation> <translation>Paramètres</translation> </message> <message> - <location filename="../ImportDialog.ui" line="96"/> <source>&Keep Aspect Ratio</source> - <translation>&Conserver le rapport d'aspect</translation> + <translation type="vanished">&Conserver le rapport d'aspect</translation> </message> <message> - <location filename="../ImportDialog.ui" line="103"/> <source>&Ignore Aspect Ratio</source> - <translation>&Ignorer le rapport d'aspect</translation> + <translation type="vanished">&Ignorer le rapport d'aspect</translation> </message> <message> - <location filename="../ImportDialog.ui" line="110"/> <source>&Avatar</source> - <translation>&Avatar</translation> + <translation type="vanished">&Avatar</translation> </message> <message> - <location filename="../ImportDialog.ui" line="154"/> + <source>Keep Aspect Ratio</source> + <translation type="vanished">Conserver le rapport d'aspect</translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="148"/> + <source>Ignore Aspect Ratio</source> + <translation>Déverrouiller le ratio d'aspect</translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="135"/> + <source>Avatar</source> + <translation>Avatar</translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="98"/> + <location filename="../ImportDialog.cpp" line="57"/> + <location filename="../ImportDialog.cpp" line="216"/> + <source>Background Colour: <span style="color: %1">%1</span></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="105"/> + <source>...</source> + <translation type="unfinished">...</translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="194"/> + <source>Import picture</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="197"/> <source>&OK</source> <translation>&OK</translation> </message> <message> - <location filename="../ImportDialog.ui" line="167"/> + <location filename="../ImportDialog.ui" line="210"/> + <source>Discard picture</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="213"/> <source>&Cancel</source> <translation>A&nnuler</translation> </message> + <message> + <location filename="../ImportDialog.cpp" line="173"/> + <source>Are you sure to use a square image outside of the Avatar Zone? +When you want to use it as Avatar the image will be detached!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ImportDialog.cpp" line="173"/> + <source>Snapmatic Avatar Zone</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ImportDialog.cpp" line="212"/> + <source>Select Colour...</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MapPreviewDialog</name> + <message> + <location filename="../MapPreviewDialog.ui" line="26"/> + <source>Snapmatic Map Viewer</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>OptionsDialog</name> @@ -423,55 +530,77 @@ et les fichiers de sauvegarde de Grand Theft Auto V</translation> </message> <message> <location filename="../OptionsDialog.ui" line="463"/> + <source>Apply changes</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="466"/> <source>&OK</source> <extracomment>OK, Cancel, Apply</extracomment> <translation>&OK</translation> </message> <message> - <location filename="../OptionsDialog.ui" line="476"/> + <location filename="../OptionsDialog.ui" line="479"/> + <source>Discard changes</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="482"/> <source>&Cancel</source> <extracomment>OK, Cancel, Apply</extracomment> <translation>&Annuler</translation> </message> <message> - <location filename="../OptionsDialog.cpp" line="133"/> <source>%1 (%2 if available)</source> <comment>System like PC System = %1, System Language like Deutsch = %2</comment> - <translation>%1 (%2 si disponible)</translation> + <translation type="vanished">%1 (%2 si disponible)</translation> </message> <message> - <location filename="../OptionsDialog.cpp" line="133"/> <source>System</source> <comment>System like PC System</comment> + <translation type="vanished">Système</translation> + </message> + <message> + <location filename="../OptionsDialog.cpp" line="132"/> + <source>%1 (Next Closest Language)</source> + <comment>First language a person can talk with a different person/application. "Native" or "Not Native".</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.cpp" line="132"/> + <source>System</source> + <comment>System in context of System default</comment> <translation>Système</translation> </message> <message> - <location filename="../OptionsDialog.cpp" line="292"/> - <location filename="../OptionsDialog.cpp" line="296"/> + <location filename="../OptionsDialog.cpp" line="289"/> <source>%1</source> <comment>%1</comment> <translation>%1</translation> </message> <message> - <location filename="../OptionsDialog.cpp" line="292"/> + <location filename="../OptionsDialog.cpp" line="289"/> + <source>The new Custom Folder will initialise after you restart %1.</source> + <translation type="unfinished"></translation> + </message> + <message> <source>The new Custom Folder will initialize after you restart %1.</source> - <translation>Le répertoire personnalisé sera actif au prochain lancement de %1.</translation> + <translation type="vanished">Le répertoire personnalisé sera actif au prochain lancement de %1.</translation> </message> <message> - <location filename="../OptionsDialog.cpp" line="296"/> <source>The language change will take effect after you restart %1.</source> - <translation>Le changement de langue sera actif au prochain lancement de %1.</translation> + <translation type="vanished">Le changement de langue sera actif au prochain lancement de %1.</translation> </message> <message> - <location filename="../OptionsDialog.cpp" line="306"/> + <location filename="../OptionsDialog.cpp" line="299"/> <source>No Profile</source> <comment>No Profile, as default</comment> <translation>Aucun profil</translation> </message> <message> - <location filename="../OptionsDialog.cpp" line="314"/> - <location filename="../OptionsDialog.cpp" line="318"/> - <location filename="../OptionsDialog.cpp" line="320"/> + <location filename="../OptionsDialog.cpp" line="307"/> + <location filename="../OptionsDialog.cpp" line="311"/> + <location filename="../OptionsDialog.cpp" line="313"/> <source>Profile: %1</source> <translation>Profil : %1</translation> </message> @@ -484,7 +613,7 @@ et les fichiers de sauvegarde de Grand Theft Auto V</translation> <translation>%1 - Visionneuse de photo Snapmatic</translation> </message> <message> - <location filename="../PictureDialog.ui" line="104"/> + <location filename="../PictureDialog.ui" line="117"/> <source><span style=" font-weight:600;">Title: </span>%6<br/> <span style=" font-weight:600;">Location: </span>%7 (%1, %2, %3)<br/> <span style=" font-weight:600;">Players: </span>%4 (Crew %5)<br/> @@ -495,47 +624,73 @@ et les fichiers de sauvegarde de Grand Theft Auto V</translation> <span style=" font-weight:600;">Créé le : </span>%8</translation> </message> <message> - <location filename="../PictureDialog.ui" line="164"/> + <location filename="../PictureDialog.ui" line="177"/> + <source>Manage picture</source> + <translation type="unfinished"></translation> + </message> + <message> <source>Export picture</source> - <translation>Exporter la photo</translation> + <translation type="vanished">Exporter la photo</translation> + </message> + <message> + <location filename="../PictureDialog.ui" line="180"/> + <source>&Manage</source> + <translation type="unfinished"></translation> </message> <message> - <location filename="../PictureDialog.ui" line="167"/> <source>&Export</source> - <translation>&Exporter</translation> + <translation type="vanished">&Exporter</translation> + </message> + <message> + <location filename="../PictureDialog.ui" line="199"/> + <source>Close viewer</source> + <translation type="unfinished"></translation> </message> <message> - <location filename="../PictureDialog.ui" line="186"/> <source>Close</source> - <translation>Fermer la visionneuse</translation> + <translation type="vanished">Fermer la visionneuse</translation> </message> <message> - <location filename="../PictureDialog.ui" line="189"/> + <location filename="../PictureDialog.ui" line="202"/> <source>&Close</source> <translation>&Fermer</translation> </message> <message> - <location filename="../PictureExport.cpp" line="220"/> <source>Export as GTA Snapmatic...</source> - <translation>Exporter comme Snapmatic...</translation> + <translation type="vanished">Exporter comme Snapmatic...</translation> </message> <message> - <location filename="../PictureExport.cpp" line="224"/> + <location filename="../PictureExport.cpp" line="222"/> + <source>Export as Snapmatic...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="226"/> <source>GTA V Export (*.g5e)</source> <translation>GTA V Export (*.g5e)</translation> </message> <message> - <location filename="../PictureExport.cpp" line="225"/> + <location filename="../PictureExport.cpp" line="227"/> <source>GTA V Raw Export (*.auto)</source> <translation>GTA V Export Brut (*.g5e)</translation> </message> <message> - <location filename="../PictureExport.cpp" line="226"/> + <location filename="../PictureExport.cpp" line="228"/> <source>Snapmatic pictures (PGTA*)</source> <translation>Fichiers GTA Snapmatic (PGTA*)</translation> </message> <message> - <location filename="../PictureExport.cpp" line="291"/> + <location filename="../PictureExport.cpp" line="260"/> + <location filename="../PictureExport.cpp" line="264"/> + <location filename="../PictureExport.cpp" line="279"/> + <location filename="../PictureExport.cpp" line="288"/> + <location filename="../PictureExport.cpp" line="293"/> + <location filename="../PictureExport.cpp" line="299"/> + <source>Export as Snapmatic</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="293"/> <source>Exported Snapmatic to "%1" because of using the .auto extension.</source> <translation>Exporté comme "%1" avec l'utilisation de l'extension .auto.</translation> </message> @@ -544,24 +699,36 @@ et les fichiers de sauvegarde de Grand Theft Auto V</translation> <translation type="vanished">Tous les fichiers (**)</translation> </message> <message> - <location filename="../PictureExport.cpp" line="246"/> - <location filename="../PictureExport.cpp" line="250"/> - <location filename="../PictureExport.cpp" line="265"/> - <location filename="../PictureExport.cpp" line="286"/> - <location filename="../PictureExport.cpp" line="291"/> - <location filename="../PictureExport.cpp" line="297"/> <source>Export as GTA Snapmatic</source> - <translation>Exporter comme GTA Snapmatic</translation> + <translation type="vanished">Exporter comme GTA Snapmatic</translation> </message> <message> - <location filename="../PictureExport.cpp" line="143"/> - <location filename="../PictureExport.cpp" line="246"/> + <location filename="../PictureExport.cpp" line="145"/> + <location filename="../PictureExport.cpp" line="260"/> <source>Overwrite %1 with current Snapmatic picture?</source> <translation>%1 existe déjà. Vous-vous le remplacer ?</translation> </message> <message> - <location filename="../PictureExport.cpp" line="147"/> - <location filename="../PictureExport.cpp" line="250"/> + <location filename="../PictureExport.cpp" line="90"/> + <source>Export as Picture...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="94"/> + <source>JPEG Graphics (*.jpg *.jpeg)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="145"/> + <location filename="../PictureExport.cpp" line="149"/> + <location filename="../PictureExport.cpp" line="183"/> + <location filename="../PictureExport.cpp" line="189"/> + <source>Export as Picture</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="149"/> + <location filename="../PictureExport.cpp" line="264"/> <source>Failed to overwrite %1 with current Snapmatic picture</source> <translation>Echec du remplacement de %1</translation> </message> @@ -570,23 +737,45 @@ et les fichiers de sauvegarde de Grand Theft Auto V</translation> <translation type="vanished">Echec de la copie</translation> </message> <message> - <location filename="../PictureExport.cpp" line="187"/> - <location filename="../PictureExport.cpp" line="297"/> + <location filename="../PictureExport.cpp" line="189"/> + <location filename="../PictureExport.cpp" line="299"/> <source>No valid file is selected</source> <translation>Fichier invalide</translation> </message> <message> - <location filename="../PictureDialog.cpp" line="141"/> <source>Export as &JPG picture...</source> - <translation>Exporter comme image &JPG...</translation> + <translation type="vanished">Exporter comme image &JPG...</translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="145"/> + <source>Export as &Picture...</source> + <translation type="unfinished"></translation> </message> <message> - <location filename="../PictureDialog.cpp" line="142"/> <source>Export as &GTA Snapmatic...</source> - <translation>Exporter comme &GTA Snapmatic...</translation> + <translation type="vanished">Exporter comme &GTA Snapmatic...</translation> </message> <message> - <location filename="../PictureDialog.cpp" line="358"/> + <location filename="../PictureDialog.cpp" line="146"/> + <source>Export as &Snapmatic...</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Edi&t</source> + <translation type="obsolete">Édi&ter</translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="148"/> + <source>Open &Map View...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="150"/> + <source>&Edit Properties...</source> + <translation>Modifier les &propriétés...</translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="373"/> <source>Key 1 - Avatar Preview Mode Key 2 - Toggle Overlay Arrow Keys - Navigate</source> @@ -595,19 +784,31 @@ Touche 2 - Activer/désactiver l'overlay Touches fléchées - Naviguer</translation> </message> <message> - <location filename="../PictureDialog.cpp" line="417"/> - <location filename="../PictureDialog.cpp" line="489"/> + <location filename="../PictureDialog.cpp" line="433"/> + <location filename="../PictureDialog.cpp" line="476"/> <source>Snapmatic Picture Viewer</source> <translation>Visionneuse de photo Snapmatic</translation> </message> <message> - <location filename="../PictureDialog.cpp" line="417"/> - <location filename="../PictureDialog.cpp" line="489"/> + <location filename="../PictureDialog.cpp" line="433"/> + <location filename="../PictureDialog.cpp" line="476"/> <source>Failed at %1</source> <translation>Echec de %1</translation> </message> <message> - <location filename="../PictureDialog.cpp" line="572"/> + <location filename="../PictureDialog.cpp" line="475"/> + <location filename="../PictureDialog.cpp" line="589"/> + <source>No Crew</source> + <translation>Aucun crew</translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="475"/> + <location filename="../PictureDialog.cpp" line="614"/> + <source>No Players</source> + <translation>Aucun joueurs</translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="560"/> <source>Avatar Preview Mode Press 1 for Default View</source> <translation>Mode Aperçu Avatar @@ -618,55 +819,45 @@ Appuyer sur 1 pour le mode par défaut</translation> <translation type="vanished">Aperçu avatar<br>Appuyer sur A pour la vue par défaut</translation> </message> <message> - <location filename="../PictureDialog.cpp" line="478"/> - <location filename="../PictureDialog.cpp" line="488"/> <source>No player</source> - <translation>Aucun joueur</translation> + <translation type="vanished">Aucun joueur</translation> </message> <message> - <location filename="../PictureDialog.cpp" line="481"/> - <location filename="../PictureDialog.cpp" line="488"/> <source>No crew</source> - <translation>Aucun crew</translation> + <translation type="vanished">Aucun crew</translation> </message> <message> - <location filename="../PictureDialog.cpp" line="488"/> + <location filename="../PictureDialog.cpp" line="475"/> <source>Unknown Location</source> <translation>Emplacement inconnu</translation> </message> <message> - <location filename="../PictureExport.cpp" line="88"/> <source>Export as JPG picture...</source> - <translation>Exporter comme image JPG...</translation> + <translation type="vanished">Exporter comme image JPG...</translation> </message> <message> - <location filename="../PictureExport.cpp" line="89"/> - <location filename="../PictureExport.cpp" line="221"/> + <location filename="../PictureExport.cpp" line="91"/> + <location filename="../PictureExport.cpp" line="223"/> <source>Export</source> <translation>Exporter</translation> </message> <message> - <location filename="../PictureExport.cpp" line="92"/> <source>JPEG picture (*.jpg)</source> - <translation>Image JPEG (*.jpg)</translation> + <translation type="vanished">Image JPEG (*.jpg)</translation> </message> <message> - <location filename="../PictureExport.cpp" line="93"/> + <location filename="../PictureExport.cpp" line="95"/> <source>Portable Network Graphics (*.png)</source> <translation>Portable Network Graphics (*.png)</translation> </message> <message> - <location filename="../PictureExport.cpp" line="143"/> - <location filename="../PictureExport.cpp" line="147"/> - <location filename="../PictureExport.cpp" line="181"/> - <location filename="../PictureExport.cpp" line="187"/> <source>Export as JPG picture</source> - <translation>Exporter comme image JPG</translation> + <translation type="vanished">Exporter comme image JPG</translation> </message> <message> - <location filename="../PictureExport.cpp" line="181"/> - <location filename="../PictureExport.cpp" line="265"/> - <location filename="../PictureExport.cpp" line="286"/> + <location filename="../PictureExport.cpp" line="183"/> + <location filename="../PictureExport.cpp" line="279"/> + <location filename="../PictureExport.cpp" line="288"/> <source>Failed to export current Snapmatic picture</source> <translation>Échec de l'export de la photo Snapmatic</translation> </message> @@ -684,66 +875,71 @@ Appuyer sur 1 pour le mode par défaut</translation> <translation>Chargement du fichier %1 sur %2</translation> </message> <message> - <location filename="../ProfileInterface.ui" line="169"/> + <location filename="../ProfileInterface.ui" line="172"/> <source>%1 %2</source> <translation>%1 %2</translation> </message> <message> - <location filename="../ProfileInterface.ui" line="195"/> - <source>Import exported file</source> - <translation>Importer un profil</translation> + <location filename="../ProfileInterface.ui" line="198"/> + <source>Import file</source> + <translation type="unfinished"></translation> </message> <message> - <location filename="../ProfileInterface.ui" line="198"/> + <source>Import exported file</source> + <translation type="vanished">Importer un profil</translation> + </message> + <message> + <location filename="../ProfileInterface.ui" line="201"/> <source>&Import...</source> <translation>&Importer...</translation> </message> <message> - <location filename="../ProfileInterface.ui" line="214"/> + <location filename="../ProfileInterface.ui" line="217"/> <source>Close profile</source> <translation>Fermer</translation> </message> <message> - <location filename="../ProfileInterface.ui" line="217"/> + <location filename="../ProfileInterface.ui" line="220"/> <source>&Close</source> <translation>&Fermer</translation> </message> <message> - <location filename="../ExportThread.cpp" line="96"/> - <location filename="../ExportThread.cpp" line="135"/> - <location filename="../ExportThread.cpp" line="156"/> + <location filename="../ExportThread.cpp" line="97"/> + <location filename="../ExportThread.cpp" line="136"/> + <location filename="../ExportThread.cpp" line="157"/> <source>Export file %1 of %2 files</source> <translation>Copie du fichier %1 sur %2</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="62"/> + <location filename="../ProfileInterface.cpp" line="65"/> <source>Enabled pictures: %1 of %2</source> <translation>Photos activées : %1 sur %2</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="114"/> + <location filename="../ProfileInterface.cpp" line="129"/> <source>Loading...</source> <translation>Chargement...</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="390"/> - <location filename="../ProfileInterface.cpp" line="427"/> + <location filename="../ProfileInterface.cpp" line="426"/> + <location filename="../ProfileInterface.cpp" line="491"/> <source>Import...</source> <translation>Importer...</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="391"/> - <location filename="../ProfileInterface.cpp" line="481"/> - <location filename="../ProfileInterface.cpp" line="486"/> - <location filename="../ProfileInterface.cpp" line="513"/> - <location filename="../ProfileInterface.cpp" line="529"/> - <location filename="../ProfileInterface.cpp" line="679"/> - <location filename="../ProfileInterface.cpp" line="684"/> - <location filename="../ProfileInterface.cpp" line="702"/> - <location filename="../ProfileInterface.cpp" line="707"/> - <location filename="../ProfileInterface.cpp" line="718"/> + <location filename="../ProfileInterface.cpp" line="427"/> + <location filename="../ProfileInterface.cpp" line="470"/> + <location filename="../ProfileInterface.cpp" line="522"/> + <location filename="../ProfileInterface.cpp" line="542"/> + <location filename="../ProfileInterface.cpp" line="558"/> + <location filename="../ProfileInterface.cpp" line="674"/> <location filename="../ProfileInterface.cpp" line="755"/> - <location filename="../ProfileInterface.cpp" line="761"/> + <location filename="../ProfileInterface.cpp" line="760"/> + <location filename="../ProfileInterface.cpp" line="778"/> + <location filename="../ProfileInterface.cpp" line="783"/> + <location filename="../ProfileInterface.cpp" line="794"/> + <location filename="../ProfileInterface.cpp" line="831"/> + <location filename="../ProfileInterface.cpp" line="837"/> <source>Import</source> <translation>Importer</translation> </message> @@ -752,31 +948,36 @@ Appuyer sur 1 pour le mode par défaut</translation> <translation type="vanished">Fichiers de profil GTA (SGTA* PGTA*)</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="396"/> - <location filename="../UserInterface.cpp" line="351"/> + <location filename="../ProfileInterface.cpp" line="444"/> + <location filename="../UserInterface.cpp" line="365"/> <source>Savegames files (SGTA*)</source> <translation>Fichiers de sauvegarde GTA (SGTA*)</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="397"/> - <location filename="../UserInterface.cpp" line="352"/> + <location filename="../ProfileInterface.cpp" line="445"/> + <location filename="../UserInterface.cpp" line="366"/> <source>Snapmatic pictures (PGTA*)</source> <translation>Photos Snapmatic (PGTA*)</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="399"/> - <location filename="../UserInterface.cpp" line="353"/> + <location filename="../ProfileInterface.cpp" line="446"/> + <source>All image files (%1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="447"/> + <location filename="../UserInterface.cpp" line="367"/> <source>All files (**)</source> <translation>Tous les fichiers (**)</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="428"/> - <location filename="../ProfileInterface.cpp" line="443"/> + <location filename="../ProfileInterface.cpp" line="492"/> + <location filename="../ProfileInterface.cpp" line="507"/> <source>Import file %1 of %2 files</source> <translation>Importation du fichier %1 sur %2</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="481"/> + <location filename="../ProfileInterface.cpp" line="522"/> <source>Import failed with... %1</source> @@ -785,111 +986,127 @@ Appuyer sur 1 pour le mode par défaut</translation> %1</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="486"/> - <location filename="../ProfileInterface.cpp" line="684"/> - <location filename="../UserInterface.cpp" line="441"/> + <location filename="../ProfileInterface.cpp" line="470"/> + <location filename="../ProfileInterface.cpp" line="760"/> + <location filename="../UserInterface.cpp" line="455"/> <source>No valid file is selected</source> <translation>Fichier invalide</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="513"/> - <location filename="../UserInterface.cpp" line="393"/> + <location filename="../ProfileInterface.cpp" line="442"/> + <source>Importable files (%1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="542"/> + <location filename="../UserInterface.cpp" line="407"/> <source>Failed to read Snapmatic picture</source> <translation>Impossible d'ouvrir la photo Snapmatic</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="529"/> - <location filename="../UserInterface.cpp" line="409"/> + <location filename="../ProfileInterface.cpp" line="558"/> + <location filename="../UserInterface.cpp" line="423"/> <source>Failed to read Savegame file</source> <translation>Impossible de lire le fichier de sauvegarde</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="679"/> <source>Can't import %1 because of not valid file format</source> - <translation>Impossible d'importer %1, format invalide</translation> + <translation type="vanished">Impossible d'importer %1, format invalide</translation> </message> <message> <source>Failed to import the Snapmatic picture, file not begin with PGTA</source> <translation type="vanished">Impossible d'importer la photo Snapmatic,nom de fichier incorrect (PGTA*)</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="394"/> <source>Importable files (*.g5e *.jpg *.png SGTA* PGTA*)</source> - <translation>Fichiers importables (*.g5e *.jpg *.png SGTA* PGTA*)</translation> + <translation type="vanished">Fichiers importables (*.g5e *.jpg *.png SGTA* PGTA*)</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="398"/> <source>All image files (*.jpg *.png)</source> - <translation>Tous les fichiers image (*.jpg *.png)</translation> + <translation type="vanished">Tous les fichiers image (*.jpg *.png)</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="702"/> + <location filename="../ProfileInterface.cpp" line="674"/> + <source>Can't import %1 because file can't be parsed properly</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="755"/> + <source>Can't import %1 because file format can't be detected</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="778"/> <source>Failed to import the Snapmatic picture, file not begin with PGTA or end with .g5e</source> <translation>Impossible d'importer la photo Snapmatic,nom de fichier incorrect (PGTA*, *.g5e)</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="707"/> + <location filename="../ProfileInterface.cpp" line="783"/> <source>Failed to import the Snapmatic picture, the picture is already in the game</source> <translation>Impossible d'importer la photo Snapmatic, un fichier du même nom existe déjà</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="718"/> + <location filename="../ProfileInterface.cpp" line="794"/> <source>Failed to import the Snapmatic picture, can't copy the file into profile</source> <translation>Impossible d'importer la photo Snapmatic, impossible de copier le fichier dans le profil</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="755"/> + <location filename="../ProfileInterface.cpp" line="831"/> <source>Failed to import the Savegame, can't copy the file into profile</source> <translation>Impossible d'importer la sauvegarde, impossible de copier le fichier dans le profil</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="761"/> + <location filename="../ProfileInterface.cpp" line="837"/> <source>Failed to import the Savegame, no Savegame slot is left</source> <translation>Impossible d'importer la sauvegarde, aucun emplacement libre</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="824"/> - <location filename="../ProfileInterface.cpp" line="862"/> - <location filename="../ProfileInterface.cpp" line="939"/> - <location filename="../ProfileInterface.cpp" line="959"/> + <location filename="../ProfileInterface.cpp" line="900"/> + <location filename="../ProfileInterface.cpp" line="938"/> + <location filename="../ProfileInterface.cpp" line="1017"/> + <location filename="../ProfileInterface.cpp" line="1037"/> <source>Export selected</source> <translation>Exporter la sélection</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="847"/> - <location filename="../ProfileInterface.cpp" line="865"/> + <location filename="../ProfileInterface.cpp" line="923"/> + <location filename="../ProfileInterface.cpp" line="941"/> <source>JPG pictures and GTA Snapmatic</source> <translation>Images JPG et GTA Snapmatic</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="848"/> - <location filename="../ProfileInterface.cpp" line="870"/> + <location filename="../ProfileInterface.cpp" line="924"/> + <location filename="../ProfileInterface.cpp" line="946"/> <source>JPG pictures only</source> <translation>Images JPG seulement</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="849"/> - <location filename="../ProfileInterface.cpp" line="874"/> + <location filename="../ProfileInterface.cpp" line="925"/> + <location filename="../ProfileInterface.cpp" line="950"/> <source>GTA Snapmatic only</source> <translation>GTA Snapmatic seulement</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="862"/> + <location filename="../ProfileInterface.cpp" line="938"/> <source>%1Export Snapmatic pictures%2<br><br>JPG pictures make it possible to open the picture with a Image Viewer<br>GTA Snapmatic make it possible to import the picture into the game<br><br>Export as:</source> <translation>%1Exporter les photos Snapmatic%2<br><br>Les fichiers JPG permettent d'ouvrir les photos avec une visionneuse d'images<br>Les GTA Snapmatic permettent d'importer les photos dans le jeu<br><br>Exporter comme :</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="905"/> + <location filename="../ProfileInterface.cpp" line="983"/> <source>Export selected...</source> <translation>Exporter la sélection...</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="906"/> - <source>Initializing export...</source> - <translation>Initialisation de l'export...</translation> + <location filename="../ProfileInterface.cpp" line="984"/> + <source>Initialising export...</source> + <translation type="unfinished"></translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="939"/> + <source>Initializing export...</source> + <translation type="vanished">Initialisation de l'export...</translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1017"/> <source>Export failed with... %1</source> @@ -898,36 +1115,36 @@ Appuyer sur 1 pour le mode par défaut</translation> %1</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="959"/> - <location filename="../ProfileInterface.cpp" line="1001"/> + <location filename="../ProfileInterface.cpp" line="1037"/> + <location filename="../ProfileInterface.cpp" line="1079"/> <source>No Snapmatic pictures or Savegames files are selected</source> <translation>Aucun fichier de sauvegarde ou photo Snapmatic sélectionné</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="967"/> - <location filename="../ProfileInterface.cpp" line="995"/> - <location filename="../ProfileInterface.cpp" line="1001"/> + <location filename="../ProfileInterface.cpp" line="1045"/> + <location filename="../ProfileInterface.cpp" line="1073"/> + <location filename="../ProfileInterface.cpp" line="1079"/> <source>Remove selected</source> <translation>Supprimer la sélection</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="967"/> + <location filename="../ProfileInterface.cpp" line="1045"/> <source>You really want remove the selected Snapmatic picutres and Savegame files?</source> <translation>Supprimer la sélection ?</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="995"/> + <location filename="../ProfileInterface.cpp" line="1073"/> <source>Failed at remove the complete selected Snapmatic pictures and/or Savegame files</source> <translation>Impossible de supprimer la sélection</translation> </message> <message> - <location filename="../UserInterface.cpp" line="349"/> + <location filename="../UserInterface.cpp" line="363"/> <source>All profile files (*.g5e SGTA* PGTA*)</source> <translation>Tous les fichiers de profil (*.g5e SGTA* PGTA*)</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="395"/> - <location filename="../UserInterface.cpp" line="350"/> + <location filename="../ProfileInterface.cpp" line="443"/> + <location filename="../UserInterface.cpp" line="364"/> <source>GTA V Export (*.g5e)</source> <translation>GTA V Export (*.g5e)</translation> </message> @@ -935,12 +1152,12 @@ Appuyer sur 1 pour le mode par défaut</translation> <context> <name>QApplication</name> <message> - <location filename="../main.cpp" line="68"/> + <location filename="../main.cpp" line="66"/> <source>Font</source> <translation>Police</translation> </message> <message> - <location filename="../main.cpp" line="68"/> + <location filename="../main.cpp" line="66"/> <source>Selected Font: %1</source> <translation>Police sélectionnée : %1</translation> </message> @@ -954,17 +1171,17 @@ Appuyer sur 1 pour le mode par défaut</translation> <translation>Gestionnaire de sauvegardes</translation> </message> <message> - <location filename="../SavegameDialog.ui" line="29"/> + <location filename="../SavegameDialog.ui" line="23"/> <source><span style=" font-weight:600;">Savegame</span><br><br>%1</source> <translation><span style=" font-weight:600;">Sauvegarde</span><br><br>%1</translation> </message> <message> - <location filename="../SavegameDialog.ui" line="63"/> + <location filename="../SavegameDialog.ui" line="70"/> <source>&Export</source> <translation>&Exporter</translation> </message> <message> - <location filename="../SavegameDialog.ui" line="76"/> + <location filename="../SavegameDialog.ui" line="83"/> <source>&Close</source> <translation>&Fermer</translation> </message> @@ -982,45 +1199,45 @@ Appuyer sur 1 pour le mode par défaut</translation> <translation>Sauvegarde</translation> </message> <message> - <location filename="../SavegameWidget.ui" line="64"/> + <location filename="../SavegameWidget.ui" line="67"/> <source>SAVE %3 - %1<br>%2</source> <translation>SAUVEGARDE %3 - %1<br>%2</translation> </message> <message> - <location filename="../SavegameWidget.ui" line="80"/> + <location filename="../SavegameWidget.ui" line="83"/> <source>View savegame</source> <translation>Voir la sauvegarde</translation> </message> <message> - <location filename="../SavegameWidget.ui" line="83"/> + <location filename="../SavegameWidget.ui" line="86"/> <source>View</source> <translation>Voir</translation> </message> <message> - <location filename="../SavegameWidget.ui" line="96"/> + <location filename="../SavegameWidget.ui" line="99"/> <source>Copy savegame</source> <translation>Copier la sauvegarde</translation> </message> <message> - <location filename="../SavegameWidget.ui" line="99"/> + <location filename="../SavegameWidget.ui" line="102"/> <location filename="../SavegameCopy.cpp" line="48"/> <source>Export</source> <translation>Exporter</translation> </message> <message> - <location filename="../SavegameWidget.ui" line="115"/> - <location filename="../SavegameWidget.cpp" line="139"/> - <location filename="../SavegameWidget.cpp" line="152"/> + <location filename="../SavegameWidget.ui" line="118"/> + <location filename="../SavegameWidget.cpp" line="131"/> + <location filename="../SavegameWidget.cpp" line="144"/> <source>Delete savegame</source> <translation>Supprimer la sauvegarde</translation> </message> <message> - <location filename="../SavegameWidget.ui" line="118"/> + <location filename="../SavegameWidget.ui" line="121"/> <source>Delete</source> <translation>Supprimer</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1125"/> + <location filename="../ProfileInterface.cpp" line="1226"/> <source>&Export</source> <translation>&Exporter</translation> </message> @@ -1068,69 +1285,69 @@ Appuyer sur 1 pour le mode par défaut</translation> <translation>Exporter la sauvegarde...</translation> </message> <message> - <location filename="../SavegameWidget.cpp" line="64"/> + <location filename="../SavegameWidget.cpp" line="60"/> + <location filename="../SavegameWidget.cpp" line="117"/> <source>AUTOSAVE - %1 %2</source> <translation>SAUVEGARDE AUTO - %1 %2</translation> </message> <message> - <location filename="../SavegameWidget.cpp" line="65"/> + <location filename="../SavegameWidget.cpp" line="61"/> + <location filename="../SavegameWidget.cpp" line="118"/> <source>SAVE %3 - %1 %2</source> <translation>SAUVEGARDE %3 - %1 %2</translation> </message> <message> - <location filename="../SavegameWidget.cpp" line="101"/> - <location filename="../SavegameWidget.cpp" line="102"/> + <location filename="../SavegameWidget.cpp" line="89"/> + <location filename="../SavegameWidget.cpp" line="90"/> <source>WRONG FORMAT</source> <translation>Format invalide</translation> </message> <message> - <location filename="../SavegameWidget.cpp" line="125"/> + <location filename="../SavegameWidget.cpp" line="111"/> <source>UNKNOWN</source> <translation>Inconnu</translation> </message> <message> - <location filename="../SavegameWidget.cpp" line="139"/> + <location filename="../SavegameWidget.cpp" line="131"/> <source>Are you sure to delete %1 from your savegames?</source> <translation>Supprimer %1 ?</translation> </message> <message> - <location filename="../SavegameWidget.cpp" line="152"/> + <location filename="../SavegameWidget.cpp" line="144"/> <source>Failed at deleting %1 from your savegames</source> <translation>Impossible de supprimer %1</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1124"/> + <location filename="../ProfileInterface.cpp" line="1225"/> <source>&View</source> <translation>&Voir</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1126"/> + <location filename="../ProfileInterface.cpp" line="1227"/> <source>&Remove</source> <translation>&Supprimer</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1130"/> - <location filename="../ProfileInterface.cpp" line="1141"/> + <location filename="../ProfileInterface.cpp" line="1229"/> <source>&Select</source> <translation>&Sélectionner</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1131"/> + <location filename="../ProfileInterface.cpp" line="1230"/> <source>&Deselect</source> <translation>&Déselectionner</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1132"/> - <location filename="../ProfileInterface.cpp" line="1142"/> + <location filename="../ProfileInterface.cpp" line="1233"/> <source>Select &All</source> <translation>Sélectionner to&ut</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1135"/> + <location filename="../ProfileInterface.cpp" line="1237"/> <source>&Deselect All</source> <translation>&Déselectionner tout</translation> </message> @@ -1140,7 +1357,7 @@ Appuyer sur 1 pour le mode par défaut</translation> <message> <location filename="../SnapmaticEditor.ui" line="14"/> <location filename="../SnapmaticEditor.ui" line="81"/> - <location filename="../SnapmaticEditor.cpp" line="244"/> + <location filename="../SnapmaticEditor.cpp" line="245"/> <source>Snapmatic Properties</source> <translation>Propriétés Snapmatic</translation> </message> @@ -1184,7 +1401,7 @@ Appuyer sur 1 pour le mode par défaut</translation> <translation>Meme</translation> </message> <message> - <location filename="../SnapmaticEditor.cpp" line="294"/> + <location filename="../SnapmaticEditor.cpp" line="295"/> <source>Snapmatic Title</source> <translation>Titre Snapmatic</translation> </message> @@ -1195,20 +1412,20 @@ Appuyer sur 1 pour le mode par défaut</translation> </message> <message> <location filename="../SnapmaticEditor.ui" line="113"/> - <location filename="../SnapmaticEditor.cpp" line="199"/> + <location filename="../SnapmaticEditor.cpp" line="200"/> <source>Crew: %1 (%2)</source> <translation>Crew : %1 (%2)</translation> </message> <message> <location filename="../SnapmaticEditor.ui" line="126"/> - <location filename="../SnapmaticEditor.cpp" line="184"/> + <location filename="../SnapmaticEditor.cpp" line="185"/> <source>Title: %1 (%2)</source> <translation>Titre : %1 (%2)</translation> </message> <message> <location filename="../SnapmaticEditor.ui" line="136"/> - <location filename="../SnapmaticEditor.cpp" line="188"/> - <location filename="../SnapmaticEditor.cpp" line="192"/> + <location filename="../SnapmaticEditor.cpp" line="189"/> + <location filename="../SnapmaticEditor.cpp" line="193"/> <source>Appropriate: %1</source> <translation>Valide : %1</translation> </message> @@ -1238,42 +1455,42 @@ Appuyer sur 1 pour le mode par défaut</translation> <translation>A&nnuler</translation> </message> <message> - <location filename="../SnapmaticEditor.cpp" line="183"/> - <location filename="../SnapmaticEditor.cpp" line="198"/> + <location filename="../SnapmaticEditor.cpp" line="184"/> + <location filename="../SnapmaticEditor.cpp" line="199"/> <source>Edit</source> <translation>Éditer</translation> </message> <message> - <location filename="../SnapmaticEditor.cpp" line="188"/> + <location filename="../SnapmaticEditor.cpp" line="189"/> <source>Yes</source> <comment>Yes, should work fine</comment> <translatorcomment>Oui, devrait fonctionner</translatorcomment> <translation>Oui</translation> </message> <message> - <location filename="../SnapmaticEditor.cpp" line="192"/> + <location filename="../SnapmaticEditor.cpp" line="193"/> <source>No</source> <comment>No, could lead to issues</comment> <translatorcomment>Non, pourrait causer des erreurs</translatorcomment> <translation>Non</translation> </message> <message> - <location filename="../SnapmaticEditor.cpp" line="244"/> + <location filename="../SnapmaticEditor.cpp" line="245"/> <source>Patching of Snapmatic Properties failed because of I/O Error</source> <translation>La modification des propriétés Snapmatic a échoué : erreur d'entrée/sortie</translation> </message> <message> - <location filename="../SnapmaticEditor.cpp" line="294"/> + <location filename="../SnapmaticEditor.cpp" line="295"/> <source>New Snapmatic title:</source> <translation>Nouveau titre Snapmatic :</translation> </message> <message> - <location filename="../SnapmaticEditor.cpp" line="319"/> + <location filename="../SnapmaticEditor.cpp" line="324"/> <source>Snapmatic Crew</source> <translation>Crew Snapmatic</translation> </message> <message> - <location filename="../SnapmaticEditor.cpp" line="319"/> + <location filename="../SnapmaticEditor.cpp" line="324"/> <source>New Snapmatic crew:</source> <translation>Nouveau crew Snapmatic :</translation> </message> @@ -1281,7 +1498,7 @@ Appuyer sur 1 pour le mode par défaut</translation> <context> <name>SnapmaticPicture</name> <message> - <location filename="../SnapmaticPicture.cpp" line="367"/> + <location filename="../SnapmaticPicture.cpp" line="411"/> <source>PHOTO - %1</source> <translation>PHOTO - %1</translation> </message> @@ -1294,126 +1511,132 @@ Appuyer sur 1 pour le mode par défaut</translation> <translation>Snapmatic</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="82"/> + <location filename="../SnapmaticWidget.ui" line="85"/> <source>PHOTO - 00/00/00 00:00:00</source> <translation>Photo - 00/00/00 00:00:00</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="98"/> + <location filename="../SnapmaticWidget.ui" line="101"/> <source>View picture</source> <translation>Voir la photo</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="101"/> + <location filename="../SnapmaticWidget.ui" line="104"/> <source>View</source> <translation>Voir</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="117"/> + <location filename="../SnapmaticWidget.ui" line="120"/> <source>Copy picture</source> <translation>Copier la photo</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="120"/> + <location filename="../SnapmaticWidget.ui" line="123"/> <source>Copy</source> <translation>Copier</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="133"/> + <location filename="../SnapmaticWidget.ui" line="136"/> <source>Export picture</source> <translation>Exporter la photo</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="136"/> + <location filename="../SnapmaticWidget.ui" line="139"/> <source>Export</source> <translation>Exporter</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="149"/> - <location filename="../SnapmaticWidget.cpp" line="163"/> - <location filename="../SnapmaticWidget.cpp" line="172"/> + <location filename="../SnapmaticWidget.ui" line="152"/> + <location filename="../SnapmaticWidget.cpp" line="144"/> + <location filename="../SnapmaticWidget.cpp" line="153"/> <source>Delete picture</source> <translation>Supprimer la photo</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="152"/> + <location filename="../SnapmaticWidget.ui" line="155"/> <source>Delete</source> <translation>Supprimer</translation> </message> <message> - <location filename="../SnapmaticWidget.cpp" line="163"/> + <location filename="../SnapmaticWidget.cpp" line="144"/> <source>Are you sure to delete %1 from your Snapmatic pictures?</source> <translation>Supprimer %1 ?</translation> </message> <message> - <location filename="../SnapmaticWidget.cpp" line="172"/> + <location filename="../SnapmaticWidget.cpp" line="153"/> <source>Failed at deleting %1 from your Snapmatic pictures</source> <translation>Impossible de supprimer %1</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1083"/> + <location filename="../ProfileInterface.cpp" line="1178"/> <source>Edi&t</source> <translation>Édi&ter</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1086"/> + <location filename="../ProfileInterface.cpp" line="1181"/> <source>Show &In-game</source> <translation>&Visible en jeu</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1090"/> + <location filename="../ProfileInterface.cpp" line="1185"/> <source>Hide &In-game</source> <translation>&Invisible en jeu</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1092"/> + <location filename="../ProfileInterface.cpp" line="1187"/> <source>&Edit Properties...</source> <translation>Modifier les &propriétés...</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1093"/> + <location filename="../ProfileInterface.cpp" line="1188"/> <source>&Export</source> <translation>&Exporter</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1094"/> <source>Export as &JPG picture...</source> - <translation>Exporter comme image &JPG...</translation> + <translation type="vanished">Exporter comme image &JPG...</translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1189"/> + <source>Export as &Picture...</source> + <translation type="unfinished"></translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1095"/> <source>Export as &GTA Snapmatic...</source> - <translation>Exporter comme &GTA Snapmatic...</translation> + <translation type="vanished">Exporter comme &GTA Snapmatic...</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1096"/> + <location filename="../ProfileInterface.cpp" line="1190"/> + <source>Export as &Snapmatic...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1191"/> <source>&View</source> <translation>&Voir</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1099"/> + <location filename="../ProfileInterface.cpp" line="1194"/> <source>&Remove</source> <translation>S&upprimer</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1103"/> - <location filename="../ProfileInterface.cpp" line="1114"/> + <location filename="../ProfileInterface.cpp" line="1196"/> <source>&Select</source> <translation>&Sélectionner</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1104"/> + <location filename="../ProfileInterface.cpp" line="1197"/> <source>&Deselect</source> <translation>&Déselectionner</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1105"/> - <location filename="../ProfileInterface.cpp" line="1115"/> + <location filename="../ProfileInterface.cpp" line="1200"/> <source>Select &All</source> <translation>Sélectionner &tout</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1108"/> + <location filename="../ProfileInterface.cpp" line="1204"/> <source>&Deselect All</source> <translation>&Déselectionner tout</translation> </message> @@ -1436,31 +1659,42 @@ Appuyer sur 1 pour le mode par défaut</translation> </message> <message> <location filename="../UserInterface.ui" line="131"/> + <source>Reload profile overview</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="134"/> <source>&Reload</source> <translation>&Rafraîchir</translation> </message> <message> - <location filename="../UserInterface.ui" line="147"/> + <location filename="../UserInterface.ui" line="150"/> + <source>Close %1</source> + <extracomment>Close %1 <- (gta5view/gta5sync) - %1 will be replaced automatically</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="153"/> <source>&Close</source> <translation>Fer&mer</translation> </message> <message> - <location filename="../UserInterface.ui" line="173"/> + <location filename="../UserInterface.ui" line="179"/> <source>&File</source> <translation>&Fichier</translation> </message> <message> - <location filename="../UserInterface.ui" line="183"/> + <location filename="../UserInterface.ui" line="189"/> <source>&Help</source> <translation>Ai&de</translation> </message> <message> - <location filename="../UserInterface.ui" line="189"/> + <location filename="../UserInterface.ui" line="195"/> <source>&Edit</source> <translation>&Éditer</translation> </message> <message> - <location filename="../UserInterface.ui" line="195"/> + <location filename="../UserInterface.ui" line="201"/> <source>&Profile</source> <translation>&Profil</translation> </message> @@ -1469,182 +1703,184 @@ Appuyer sur 1 pour le mode par défaut</translation> <translation type="vanished">&À propos de gta5sync</translation> </message> <message> - <location filename="../UserInterface.ui" line="223"/> + <location filename="../UserInterface.ui" line="229"/> <source>Ctrl+P</source> <translation>Ctrl+P</translation> </message> <message> - <location filename="../UserInterface.ui" line="228"/> + <location filename="../UserInterface.ui" line="234"/> <source>&Exit</source> <translation>&Quitter</translation> </message> <message> - <location filename="../UserInterface.ui" line="231"/> + <location filename="../UserInterface.ui" line="237"/> <source>Exit</source> <translation>Quitter</translation> </message> <message> - <location filename="../UserInterface.ui" line="234"/> + <location filename="../UserInterface.ui" line="240"/> <source>Ctrl+Q</source> <translation>Ctrl+Q</translation> </message> <message> - <location filename="../UserInterface.ui" line="239"/> + <location filename="../UserInterface.ui" line="245"/> <source>Close &Profile</source> <translation>Fermer le &profil</translation> </message> <message> - <location filename="../UserInterface.ui" line="242"/> + <location filename="../UserInterface.ui" line="248"/> <source>Ctrl+End</source> <translation>Ctrl + Fin</translation> </message> <message> - <location filename="../UserInterface.ui" line="247"/> + <location filename="../UserInterface.ui" line="253"/> <source>&Settings</source> <translation>Paramètre&s</translation> </message> <message> - <location filename="../UserInterface.ui" line="250"/> + <location filename="../UserInterface.ui" line="256"/> <source>Ctrl+S</source> <translation>Ctrl+S</translation> </message> <message> - <location filename="../UserInterface.ui" line="255"/> + <location filename="../UserInterface.ui" line="261"/> <source>Select &All</source> <translation>Sélectionner &tout</translation> </message> <message> - <location filename="../UserInterface.ui" line="258"/> + <location filename="../UserInterface.ui" line="264"/> <source>Ctrl+A</source> <translation>Ctrl+A</translation> </message> <message> - <location filename="../UserInterface.ui" line="263"/> + <location filename="../UserInterface.ui" line="269"/> <source>&Deselect All</source> <translation>&Désélectionner tout</translation> </message> <message> - <location filename="../UserInterface.ui" line="266"/> + <location filename="../UserInterface.ui" line="272"/> <source>Ctrl+D</source> <translation>Ctrl+D</translation> </message> <message> - <location filename="../UserInterface.ui" line="271"/> + <location filename="../UserInterface.ui" line="277"/> <source>&Export selected...</source> <translation>&Exporter la sélection...</translation> </message> <message> - <location filename="../UserInterface.ui" line="274"/> + <location filename="../UserInterface.ui" line="280"/> <source>Ctrl+E</source> <translation>Ctrl+E</translation> </message> <message> - <location filename="../UserInterface.ui" line="279"/> + <location filename="../UserInterface.ui" line="285"/> <source>&Remove selected</source> <translation>&Supprimer la sélection</translation> </message> <message> - <location filename="../UserInterface.ui" line="282"/> + <location filename="../UserInterface.ui" line="288"/> <source>Ctrl+Del</source> <translation>Ctrl+Del</translation> </message> <message> - <location filename="../UserInterface.ui" line="287"/> + <location filename="../UserInterface.ui" line="293"/> <source>&Import files...</source> <translation>&Importer...</translation> </message> <message> - <location filename="../UserInterface.ui" line="290"/> + <location filename="../UserInterface.ui" line="296"/> <source>Ctrl+I</source> <translation>Ctrl+I</translation> </message> <message> - <location filename="../UserInterface.ui" line="295"/> + <location filename="../UserInterface.ui" line="301"/> <source>&Open File...</source> <translation>&Ouvrir...</translation> </message> <message> - <location filename="../UserInterface.ui" line="298"/> + <location filename="../UserInterface.ui" line="304"/> <source>Ctrl+O</source> <translation>Ctrl+O</translation> </message> <message> - <location filename="../UserInterface.ui" line="303"/> - <location filename="../UserInterface.cpp" line="151"/> + <location filename="../UserInterface.ui" line="309"/> + <location filename="../UserInterface.cpp" line="163"/> <source>Select &GTA V Folder...</source> <translation>Modifier l'emplacement de &GTA V...</translation> </message> <message> - <location filename="../UserInterface.ui" line="306"/> - <location filename="../OptionsDialog.cpp" line="452"/> - <location filename="../UserInterface.cpp" line="99"/> - <location filename="../UserInterface.cpp" line="495"/> + <location filename="../UserInterface.ui" line="312"/> + <location filename="../OptionsDialog.cpp" line="445"/> + <location filename="../UserInterface.cpp" line="104"/> + <location filename="../UserInterface.cpp" line="513"/> <source>Select GTA V Folder...</source> <translation>Modifier l'emplacement de GTA V...</translation> </message> <message> - <location filename="../UserInterface.ui" line="309"/> + <location filename="../UserInterface.ui" line="315"/> <source>Ctrl+G</source> <translation>Ctrl+G</translation> </message> <message> - <location filename="../UserInterface.ui" line="314"/> + <location filename="../UserInterface.ui" line="320"/> <source>Show In-gam&e</source> <translation>Rendre visible &en jeu</translation> </message> <message> - <location filename="../UserInterface.ui" line="317"/> + <location filename="../UserInterface.ui" line="323"/> <source>Shift+E</source> <translation>Shift+E</translation> </message> <message> - <location filename="../UserInterface.ui" line="199"/> + <location filename="../UserInterface.ui" line="205"/> <source>&Selection visibility</source> <translation>&Visibilité de la sélection</translation> </message> <message> - <location filename="../UserInterface.ui" line="322"/> + <location filename="../UserInterface.ui" line="328"/> <source>Hi&de In-game</source> <translation>Ren&dre invisible en jeu</translation> </message> <message> - <location filename="../UserInterface.ui" line="325"/> + <location filename="../UserInterface.ui" line="331"/> <source>Shift+D</source> <translation>Shift+D</translation> </message> <message> <location filename="../UserInterface.ui" line="20"/> - <location filename="../UserInterface.cpp" line="60"/> + <location filename="../UserInterface.cpp" line="62"/> <source>%2 - %1</source> <translation>%2 - %1</translation> </message> <message> - <location filename="../UserInterface.ui" line="220"/> - <location filename="../UserInterface.cpp" line="59"/> + <location filename="../UserInterface.ui" line="226"/> + <location filename="../UserInterface.cpp" line="60"/> + <location filename="../UserInterface.cpp" line="542"/> <source>&About %1</source> <translation>&À propos de %1</translation> </message> <message> - <location filename="../UserInterface.cpp" line="62"/> - <location filename="../UserInterface.cpp" line="220"/> + <location filename="../UserInterface.cpp" line="64"/> + <location filename="../UserInterface.cpp" line="234"/> + <location filename="../UserInterface.cpp" line="550"/> <source>Select Profile</source> <translation>Sélectionner un profil</translation> </message> <message> - <location filename="../UserInterface.cpp" line="346"/> + <location filename="../UserInterface.cpp" line="360"/> <source>Open File...</source> <translation>Ouvrir...</translation> </message> <message> - <location filename="../UserInterface.cpp" line="393"/> - <location filename="../UserInterface.cpp" line="409"/> - <location filename="../UserInterface.cpp" line="436"/> - <location filename="../UserInterface.cpp" line="441"/> + <location filename="../UserInterface.cpp" line="407"/> + <location filename="../UserInterface.cpp" line="423"/> + <location filename="../UserInterface.cpp" line="450"/> + <location filename="../UserInterface.cpp" line="455"/> <source>Open File</source> <translation>Ouvrir</translation> </message> <message> - <location filename="../UserInterface.cpp" line="436"/> + <location filename="../UserInterface.cpp" line="450"/> <source>Can't open %1 because of not valid file format</source> <translation>Impossible d'ouvrir %1, format invalide</translation> </message> diff --git a/res/gta5sync_ru.qm b/res/gta5sync_ru.qm index 6a271c0e64bef67eda16b519391756c41112d962..ebb1842d4ba233af9c2e6d19771f73ac68e93d5c 100644 GIT binary patch delta 2192 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 P;0R7K`Z{9D_B#I`RApyK delta 3630 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 diff --git a/res/gta5sync_ru.ts b/res/gta5sync_ru.ts index 3a3e584..1518d41 100644 --- a/res/gta5sync_ru.ts +++ b/res/gta5sync_ru.ts @@ -71,43 +71,63 @@ Running with Qt %6<br/> <translation type="obsolete">Закрыть</translation> </message> <message> - <location filename="../AboutDialog.cpp" line="40"/> <source>Using %1 %2</source> <comment>Exp. Using libmyfuck</comment> - <translation>Использует %1 %2</translation> + <translation type="vanished">Использует %1 %2</translation> + </message> + <message> + <source>Translated by %1</source> + <comment>Exp. Translated by Syping</comment> + <translation type="vanished">Перевёл %1</translation> + </message> + <message> + <source>NAME_OF_TRANSLATOR</source> + <comment>Your Name (The person behind your screen looking at this text!)</comment> + <translation type="vanished">VADemon</translation> + </message> + <message> + <source>TRANSLATOR_PROFILE</source> + <comment>mailto: http:// https:// Exp. https://github.com/Syping/</comment> + <translation type="vanished">https://github.com/VADemon/</translation> </message> <message> <location filename="../AboutDialog.cpp" line="41"/> - <source>Translated by %1</source> - <comment>Exp. Translated by Syping</comment> - <translation>Перевёл %1</translation> - </message> - <message> - <location filename="../AboutDialog.cpp" line="42"/> - <source>NAME_OF_TRANSLATOR</source> - <comment>Your Name (The person behind your screen looking at this text!)</comment> - <translation>VADemon</translation> + <source>Using %1 %2</source> + <extracomment>Using specific library, example Using libmyfuck</extracomment> + <translation>Использует %1 %2</translation> </message> <message> <location filename="../AboutDialog.cpp" line="43"/> + <source>Translated by %1</source> + <extracomment>Translated by translator, example Translated by Syping</extracomment> + <translation>Перевёл %1</translation> + </message> + <message> + <location filename="../AboutDialog.cpp" line="45"/> + <source>NAME_OF_TRANSLATOR</source> + <extracomment>Enter your name there</extracomment> + <translation>VADemon</translation> + </message> + <message> + <location filename="../AboutDialog.cpp" line="47"/> <source>TRANSLATOR_PROFILE</source> - <comment>mailto: http:// https:// Exp. https://github.com/Syping/</comment> + <extracomment>Enter your proilfe there, example a GitHub profile, E-Mail with "mailto: afucker@sumfuck.com" or a webpage</extracomment> <translation>https://github.com/VADemon/</translation> </message> <message> - <location filename="../AboutDialog.cpp" line="64"/> + <location filename="../AboutDialog.cpp" line="80"/> <source>A project for viewing Grand Theft Auto V Snapmatic<br/> Pictures and Savegames</source> <translation>Проект для просмотра Grand Theft Auto V Snapmatic<br/> картинок и сохранений</translation> </message> <message> - <location filename="../AboutDialog.cpp" line="68"/> + <location filename="../AboutDialog.cpp" line="84"/> <source>Copyright &copy; <a href="%1">%2</a> %3</source> <translation>Copyright &copy; <a href="%1">%2</a> %3</translation> </message> <message> - <location filename="../AboutDialog.cpp" line="70"/> + <location filename="../AboutDialog.cpp" line="86"/> <source>%1 is licensed under <a href="https://www.gnu.org/licenses/gpl-3.0.html#content">GNU GPLv3</a></source> <translation>%1 под лицензией <a href="https://www.gnu.org/licenses/gpl-3.0.html#content">GNU GPLv3</a></translation> </message> @@ -116,17 +136,47 @@ Pictures and Savegames</source> <translation type="vanished">Copyright &copy; <a href="%1">%2</a> %3<br/>%4 под лицензией <a href="https://www.gnu.org/licenses/gpl-3.0.html#content">GNU GPLv3</a></translation> </message> <message> - <location filename="../AboutDialog.cpp" line="62"/> + <location filename="../AboutDialog.cpp" line="78"/> <source>A project for viewing and sync Grand Theft Auto V Snapmatic<br/> Pictures and Savegames</source> <translation>Проект для просмотра и синхронизирования <br/> Grand Theft Auto V Snapmatic картинок и сохранений</translation> </message> + <message> + <location filename="../config.h" line="62"/> + <source>Release</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../config.h" line="68"/> + <source>Release Candidate</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../config.h" line="74"/> + <source>Daily Build</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../config.h" line="80"/> + <source>Developer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../config.h" line="86"/> + <source>Beta</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../config.h" line="92"/> + <source>Alpha</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>CrewDatabase</name> <message> - <location filename="../CrewDatabase.cpp" line="64"/> + <location filename="../CrewDatabase.cpp" line="102"/> <source>No Crew</source> <translation>Вне банды</translation> </message> @@ -208,31 +258,88 @@ Grand Theft Auto V Snapmatic картинок и сохранений</translati <translation>Настройки</translation> </message> <message> - <location filename="../ImportDialog.ui" line="96"/> <source>&Keep Aspect Ratio</source> - <translation>О&ставить соотношение сторон</translation> + <translation type="vanished">О&ставить соотношение сторон</translation> </message> <message> - <location filename="../ImportDialog.ui" line="103"/> <source>&Ignore Aspect Ratio</source> - <translation>&Игнорировать соотношение сторон</translation> + <translation type="vanished">&Игнорировать соотношение сторон</translation> </message> <message> - <location filename="../ImportDialog.ui" line="110"/> <source>&Avatar</source> - <translation>&Аватар</translation> + <translation type="vanished">&Аватар</translation> </message> <message> - <location filename="../ImportDialog.ui" line="154"/> + <source>Keep Aspect Ratio</source> + <translation type="vanished">Оставить соотношение сторон</translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="148"/> + <source>Ignore Aspect Ratio</source> + <translation>Игнорировать соотношение сторон</translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="135"/> + <source>Avatar</source> + <translation>Аватар</translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="98"/> + <location filename="../ImportDialog.cpp" line="57"/> + <location filename="../ImportDialog.cpp" line="216"/> + <source>Background Colour: <span style="color: %1">%1</span></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="105"/> + <source>...</source> + <translation type="unfinished">...</translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="194"/> + <source>Import picture</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="197"/> <source>&OK</source> <translation>&ОК</translation> </message> <message> - <location filename="../ImportDialog.ui" line="167"/> + <location filename="../ImportDialog.ui" line="210"/> + <source>Discard picture</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ImportDialog.ui" line="213"/> <source>&Cancel</source> <translatorcomment>Я не уверен насчет горячих клавиш...</translatorcomment> <translation>От&мена</translation> </message> + <message> + <location filename="../ImportDialog.cpp" line="173"/> + <source>Are you sure to use a square image outside of the Avatar Zone? +When you want to use it as Avatar the image will be detached!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ImportDialog.cpp" line="173"/> + <source>Snapmatic Avatar Zone</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ImportDialog.cpp" line="212"/> + <source>Select Colour...</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MapPreviewDialog</name> + <message> + <location filename="../MapPreviewDialog.ui" line="26"/> + <source>Snapmatic Map Viewer</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>OptionsDialog</name> @@ -385,56 +492,78 @@ Grand Theft Auto V Snapmatic картинок и сохранений</translati </message> <message> <location filename="../OptionsDialog.ui" line="463"/> + <source>Apply changes</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="466"/> <source>&OK</source> <extracomment>OK, Cancel, Apply</extracomment> <translation>&ОК</translation> </message> <message> - <location filename="../OptionsDialog.ui" line="476"/> + <location filename="../OptionsDialog.ui" line="479"/> + <source>Discard changes</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.ui" line="482"/> <source>&Cancel</source> <extracomment>OK, Cancel, Apply</extracomment> <translation>От&мена</translation> </message> <message> - <location filename="../OptionsDialog.cpp" line="133"/> <source>System</source> <comment>System like PC System</comment> <translatorcomment>может быть надо прилагательное</translatorcomment> + <translation type="vanished">Система</translation> + </message> + <message> + <source>%1 (%2 if available)</source> + <comment>System like PC System = %1, System Language like Deutsch = %2</comment> + <translation type="vanished">%1 (%2 если имеется)</translation> + </message> + <message> + <location filename="../OptionsDialog.cpp" line="132"/> + <source>%1 (Next Closest Language)</source> + <comment>First language a person can talk with a different person/application. "Native" or "Not Native".</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../OptionsDialog.cpp" line="132"/> + <source>System</source> + <comment>System in context of System default</comment> <translation>Система</translation> </message> <message> - <location filename="../OptionsDialog.cpp" line="133"/> - <source>%1 (%2 if available)</source> - <comment>System like PC System = %1, System Language like Deutsch = %2</comment> - <translation>%1 (%2 если имеется)</translation> - </message> - <message> - <location filename="../OptionsDialog.cpp" line="292"/> - <location filename="../OptionsDialog.cpp" line="296"/> + <location filename="../OptionsDialog.cpp" line="289"/> <source>%1</source> <comment>%1</comment> <translation>%1</translation> </message> <message> - <location filename="../OptionsDialog.cpp" line="292"/> + <location filename="../OptionsDialog.cpp" line="289"/> + <source>The new Custom Folder will initialise after you restart %1.</source> + <translation type="unfinished"></translation> + </message> + <message> <source>The new Custom Folder will initialize after you restart %1.</source> - <translation>Другая папка будет загружена после перезапуска %1.</translation> + <translation type="vanished">Другая папка будет загружена после перезапуска %1.</translation> </message> <message> - <location filename="../OptionsDialog.cpp" line="296"/> <source>The language change will take effect after you restart %1.</source> - <translation>Язык изменится после перезапуска %1.</translation> + <translation type="vanished">Язык изменится после перезапуска %1.</translation> </message> <message> - <location filename="../OptionsDialog.cpp" line="306"/> + <location filename="../OptionsDialog.cpp" line="299"/> <source>No Profile</source> <comment>No Profile, as default</comment> <translation>Нет профиля</translation> </message> <message> - <location filename="../OptionsDialog.cpp" line="314"/> - <location filename="../OptionsDialog.cpp" line="318"/> - <location filename="../OptionsDialog.cpp" line="320"/> + <location filename="../OptionsDialog.cpp" line="307"/> + <location filename="../OptionsDialog.cpp" line="311"/> + <location filename="../OptionsDialog.cpp" line="313"/> <source>Profile: %1</source> <translation>Профиль: %1</translation> </message> @@ -457,7 +586,7 @@ Grand Theft Auto V Snapmatic картинок и сохранений</translati <span style=" font-weight:600;">ID группы: </span>%5</translation> </message> <message> - <location filename="../PictureDialog.ui" line="104"/> + <location filename="../PictureDialog.ui" line="117"/> <source><span style=" font-weight:600;">Title: </span>%6<br/> <span style=" font-weight:600;">Location: </span>%7 (%1, %2, %3)<br/> <span style=" font-weight:600;">Players: </span>%4 (Crew %5)<br/> @@ -468,23 +597,36 @@ Grand Theft Auto V Snapmatic картинок и сохранений</translati <span style=" font-weight:600;">Сделано: </span>%8</translation> </message> <message> - <location filename="../PictureDialog.ui" line="164"/> <source>Export picture</source> - <translation>Экспорт картинки</translation> + <translation type="vanished">Экспорт картинки</translation> + </message> + <message> + <location filename="../PictureDialog.ui" line="180"/> + <source>&Manage</source> + <translation type="unfinished"></translation> </message> <message> - <location filename="../PictureDialog.ui" line="167"/> <source>&Export</source> - <translation>&Экспорт</translation> + <translation type="vanished">&Экспорт</translation> </message> <message> - <location filename="../PictureDialog.ui" line="189"/> + <location filename="../PictureDialog.ui" line="177"/> + <source>Manage picture</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureDialog.ui" line="199"/> + <source>Close viewer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureDialog.ui" line="202"/> <source>&Close</source> <translation>&Закрыть</translation> </message> <message> - <location filename="../PictureExport.cpp" line="89"/> - <location filename="../PictureExport.cpp" line="221"/> + <location filename="../PictureExport.cpp" line="91"/> + <location filename="../PictureExport.cpp" line="223"/> <source>Export</source> <translation>Экспортировать</translation> </message> @@ -493,22 +635,43 @@ Grand Theft Auto V Snapmatic картинок и сохранений</translati <translation type="obsolete">Копировать</translation> </message> <message> - <location filename="../PictureDialog.ui" line="186"/> <source>Close</source> - <translation>Закрыть</translation> + <translation type="vanished">Закрыть</translation> </message> <message> - <location filename="../PictureDialog.cpp" line="141"/> <source>Export as &JPG picture...</source> - <translation>Эксп&ортировать как картинку JPG...</translation> + <translation type="vanished">Эксп&ортировать как картинку JPG...</translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="145"/> + <source>Export as &Picture...</source> + <translation type="unfinished"></translation> </message> <message> - <location filename="../PictureDialog.cpp" line="142"/> <source>Export as &GTA Snapmatic...</source> - <translation>Экс&портировать как GTA Snapmatic...</translation> + <translation type="vanished">Экс&портировать как GTA Snapmatic...</translation> </message> <message> - <location filename="../PictureDialog.cpp" line="358"/> + <location filename="../PictureDialog.cpp" line="146"/> + <source>Export as &Snapmatic...</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Edi&t</source> + <translation type="obsolete">&Правка</translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="148"/> + <source>Open &Map View...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="150"/> + <source>&Edit Properties...</source> + <translation type="unfinished">&Изменить свойства...</translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="373"/> <source>Key 1 - Avatar Preview Mode Key 2 - Toggle Overlay Arrow Keys - Navigate</source> @@ -517,101 +680,130 @@ Arrow Keys - Navigate</source> Стрелки - Навигация</translation> </message> <message> - <location filename="../PictureDialog.cpp" line="417"/> - <location filename="../PictureDialog.cpp" line="489"/> + <location filename="../PictureDialog.cpp" line="433"/> + <location filename="../PictureDialog.cpp" line="476"/> <source>Snapmatic Picture Viewer</source> <translation>Просмотрщик фотографий Snapmatic</translation> </message> <message> - <location filename="../PictureDialog.cpp" line="417"/> - <location filename="../PictureDialog.cpp" line="489"/> + <location filename="../PictureDialog.cpp" line="433"/> + <location filename="../PictureDialog.cpp" line="476"/> <source>Failed at %1</source> <translation>Ошибка при %1</translation> </message> <message> - <location filename="../PictureDialog.cpp" line="572"/> + <location filename="../PictureDialog.cpp" line="475"/> + <location filename="../PictureDialog.cpp" line="589"/> + <source>No Crew</source> + <translation>Вне банды</translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="475"/> + <location filename="../PictureDialog.cpp" line="614"/> + <source>No Players</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureDialog.cpp" line="560"/> <source>Avatar Preview Mode Press 1 for Default View</source> <translation>Режим просмотра аватарок Нажмите 1 для стандартного просмотра</translation> </message> <message> - <location filename="../PictureDialog.cpp" line="478"/> - <location filename="../PictureDialog.cpp" line="488"/> <source>No player</source> - <translation>Игроков нет</translation> + <translation type="vanished">Игроков нет</translation> </message> <message> - <location filename="../PictureDialog.cpp" line="481"/> - <location filename="../PictureDialog.cpp" line="488"/> <source>No crew</source> - <translation>Без группы</translation> + <translation type="vanished">Без группы</translation> </message> <message> - <location filename="../PictureDialog.cpp" line="488"/> + <location filename="../PictureDialog.cpp" line="475"/> <source>Unknown Location</source> <translation>Неизвестное место</translation> </message> <message> - <location filename="../PictureExport.cpp" line="88"/> <source>Export as JPG picture...</source> - <translation>Экспортировать картинкой JPG...</translation> + <translation type="vanished">Экспортировать картинкой JPG...</translation> </message> <message> - <location filename="../PictureExport.cpp" line="92"/> <source>JPEG picture (*.jpg)</source> - <translation>Картинка JPEG (*.jpg)</translation> + <translation type="vanished">Картинка JPEG (*.jpg)</translation> </message> <message> - <location filename="../PictureExport.cpp" line="93"/> + <location filename="../PictureExport.cpp" line="95"/> <source>Portable Network Graphics (*.png)</source> <translation>Картинка Portable Network Graphics (*.png)</translation> </message> <message> - <location filename="../PictureExport.cpp" line="143"/> - <location filename="../PictureExport.cpp" line="147"/> - <location filename="../PictureExport.cpp" line="181"/> - <location filename="../PictureExport.cpp" line="187"/> <source>Export as JPG picture</source> - <translation>Экспортировать как картинку JPG</translation> + <translation type="vanished">Экспортировать как картинку JPG</translation> </message> <message> - <location filename="../PictureExport.cpp" line="143"/> - <location filename="../PictureExport.cpp" line="246"/> + <location filename="../PictureExport.cpp" line="145"/> + <location filename="../PictureExport.cpp" line="260"/> <source>Overwrite %1 with current Snapmatic picture?</source> <translation>Перезаписать %1 текущей картинкой Snapmatic?</translation> </message> <message> - <location filename="../PictureExport.cpp" line="246"/> - <location filename="../PictureExport.cpp" line="250"/> - <location filename="../PictureExport.cpp" line="265"/> - <location filename="../PictureExport.cpp" line="286"/> - <location filename="../PictureExport.cpp" line="291"/> - <location filename="../PictureExport.cpp" line="297"/> <source>Export as GTA Snapmatic</source> - <translation>Экспортировать как GTA Snapmatic</translation> + <translation type="vanished">Экспортировать как GTA Snapmatic</translation> </message> <message> - <location filename="../PictureExport.cpp" line="147"/> - <location filename="../PictureExport.cpp" line="250"/> + <location filename="../PictureExport.cpp" line="149"/> + <location filename="../PictureExport.cpp" line="264"/> <source>Failed to overwrite %1 with current Snapmatic picture</source> <translation>Не удалось перезаписать %1 картинкой Snapmatic</translation> </message> <message> - <location filename="../PictureExport.cpp" line="181"/> - <location filename="../PictureExport.cpp" line="265"/> - <location filename="../PictureExport.cpp" line="286"/> + <location filename="../PictureExport.cpp" line="90"/> + <source>Export as Picture...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="94"/> + <source>JPEG Graphics (*.jpg *.jpeg)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="145"/> + <location filename="../PictureExport.cpp" line="149"/> + <location filename="../PictureExport.cpp" line="183"/> + <location filename="../PictureExport.cpp" line="189"/> + <source>Export as Picture</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="183"/> + <location filename="../PictureExport.cpp" line="279"/> + <location filename="../PictureExport.cpp" line="288"/> <source>Failed to export current Snapmatic picture</source> <translation>Не удалось экспортировать текущую картинку Snapmatic</translation> </message> <message> - <location filename="../PictureExport.cpp" line="291"/> + <location filename="../PictureExport.cpp" line="222"/> + <source>Export as Snapmatic...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="260"/> + <location filename="../PictureExport.cpp" line="264"/> + <location filename="../PictureExport.cpp" line="279"/> + <location filename="../PictureExport.cpp" line="288"/> + <location filename="../PictureExport.cpp" line="293"/> + <location filename="../PictureExport.cpp" line="299"/> + <source>Export as Snapmatic</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../PictureExport.cpp" line="293"/> <source>Exported Snapmatic to "%1" because of using the .auto extension.</source> <translation>Snapmatic был экспортирован как "%1" из-за расширеня файла.</translation> </message> <message> - <location filename="../PictureExport.cpp" line="187"/> - <location filename="../PictureExport.cpp" line="297"/> + <location filename="../PictureExport.cpp" line="189"/> + <location filename="../PictureExport.cpp" line="299"/> <source>No valid file is selected</source> <translation>Выбранный файл неверен</translation> </message> @@ -620,22 +812,21 @@ Press 1 for Default View</source> <translation type="obsolete">Скопировать картинку</translation> </message> <message> - <location filename="../PictureExport.cpp" line="220"/> <source>Export as GTA Snapmatic...</source> - <translation>Экспортировать как GTA Snapmatic...</translation> + <translation type="vanished">Экспортировать как GTA Snapmatic...</translation> </message> <message> - <location filename="../PictureExport.cpp" line="224"/> + <location filename="../PictureExport.cpp" line="226"/> <source>GTA V Export (*.g5e)</source> <translation>GTA V Export (*.g5e)</translation> </message> <message> - <location filename="../PictureExport.cpp" line="225"/> + <location filename="../PictureExport.cpp" line="227"/> <source>GTA V Raw Export (*.auto)</source> <translation>GTA V Экспорт Исходника (*.auto)</translation> </message> <message> - <location filename="../PictureExport.cpp" line="226"/> + <location filename="../PictureExport.cpp" line="228"/> <source>Snapmatic pictures (PGTA*)</source> <translation>Картинки Snapmatic (PGTA*)</translation> </message> @@ -661,27 +852,31 @@ Press 1 for Default View</source> <translation>Загружается файл %1 из %2</translation> </message> <message> - <location filename="../ProfileInterface.ui" line="169"/> + <location filename="../ProfileInterface.ui" line="172"/> <source>%1 %2</source> <translation>%1 %2</translation> </message> <message> - <location filename="../ProfileInterface.ui" line="195"/> - <source>Import exported file</source> - <translation>Импортировать экспортированный файл</translation> + <location filename="../ProfileInterface.ui" line="198"/> + <source>Import file</source> + <translation type="unfinished"></translation> </message> <message> - <location filename="../ProfileInterface.ui" line="198"/> + <source>Import exported file</source> + <translation type="vanished">Импортировать экспортированный файл</translation> + </message> + <message> + <location filename="../ProfileInterface.ui" line="201"/> <source>&Import...</source> <translation>&Импортировать...</translation> </message> <message> - <location filename="../ProfileInterface.ui" line="214"/> + <location filename="../ProfileInterface.ui" line="217"/> <source>Close profile</source> <translation>Закрыть профиль</translation> </message> <message> - <location filename="../ProfileInterface.ui" line="217"/> + <location filename="../ProfileInterface.ui" line="220"/> <source>&Close</source> <translation>&Закрыть</translation> </message> @@ -694,29 +889,30 @@ Press 1 for Default View</source> <translation type="obsolete">Закрыть профиль</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="114"/> + <location filename="../ProfileInterface.cpp" line="129"/> <source>Loading...</source> <translation>Загрузка...</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="390"/> - <location filename="../ProfileInterface.cpp" line="427"/> + <location filename="../ProfileInterface.cpp" line="426"/> + <location filename="../ProfileInterface.cpp" line="491"/> <source>Import...</source> <translation>Импортировать...</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="391"/> - <location filename="../ProfileInterface.cpp" line="481"/> - <location filename="../ProfileInterface.cpp" line="486"/> - <location filename="../ProfileInterface.cpp" line="513"/> - <location filename="../ProfileInterface.cpp" line="529"/> - <location filename="../ProfileInterface.cpp" line="679"/> - <location filename="../ProfileInterface.cpp" line="684"/> - <location filename="../ProfileInterface.cpp" line="702"/> - <location filename="../ProfileInterface.cpp" line="707"/> - <location filename="../ProfileInterface.cpp" line="718"/> + <location filename="../ProfileInterface.cpp" line="427"/> + <location filename="../ProfileInterface.cpp" line="470"/> + <location filename="../ProfileInterface.cpp" line="522"/> + <location filename="../ProfileInterface.cpp" line="542"/> + <location filename="../ProfileInterface.cpp" line="558"/> + <location filename="../ProfileInterface.cpp" line="674"/> <location filename="../ProfileInterface.cpp" line="755"/> - <location filename="../ProfileInterface.cpp" line="761"/> + <location filename="../ProfileInterface.cpp" line="760"/> + <location filename="../ProfileInterface.cpp" line="778"/> + <location filename="../ProfileInterface.cpp" line="783"/> + <location filename="../ProfileInterface.cpp" line="794"/> + <location filename="../ProfileInterface.cpp" line="831"/> + <location filename="../ProfileInterface.cpp" line="837"/> <source>Import</source> <translation>Импортировать</translation> </message> @@ -725,31 +921,31 @@ Press 1 for Default View</source> <translation type="vanished">Все файлы профиля (SGTA* PGTA*)</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="396"/> - <location filename="../UserInterface.cpp" line="351"/> + <location filename="../ProfileInterface.cpp" line="444"/> + <location filename="../UserInterface.cpp" line="365"/> <source>Savegames files (SGTA*)</source> <translation>Файлы сохранения (SGTA*)</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="397"/> - <location filename="../UserInterface.cpp" line="352"/> + <location filename="../ProfileInterface.cpp" line="445"/> + <location filename="../UserInterface.cpp" line="366"/> <source>Snapmatic pictures (PGTA*)</source> <translation>Картинка Snapmatic (PGTA*)</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="399"/> - <location filename="../UserInterface.cpp" line="353"/> + <location filename="../ProfileInterface.cpp" line="447"/> + <location filename="../UserInterface.cpp" line="367"/> <source>All files (**)</source> <translation>Все файлы (**)</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="428"/> - <location filename="../ProfileInterface.cpp" line="443"/> + <location filename="../ProfileInterface.cpp" line="492"/> + <location filename="../ProfileInterface.cpp" line="507"/> <source>Import file %1 of %2 files</source> <translation>Импортируются файлы %1 из %2</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="481"/> + <location filename="../ProfileInterface.cpp" line="522"/> <source>Import failed with... %1</source> @@ -758,107 +954,129 @@ Press 1 for Default View</source> %1</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="513"/> - <location filename="../UserInterface.cpp" line="393"/> + <location filename="../ProfileInterface.cpp" line="542"/> + <location filename="../UserInterface.cpp" line="407"/> <source>Failed to read Snapmatic picture</source> <translation>Не удалось загрузить картинку Snapmatic</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="529"/> - <location filename="../UserInterface.cpp" line="409"/> + <location filename="../ProfileInterface.cpp" line="558"/> + <location filename="../UserInterface.cpp" line="423"/> <source>Failed to read Savegame file</source> <translation>Не удалось загрузить файл сохранения</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="679"/> <source>Can't import %1 because of not valid file format</source> - <translation>Не получилось импортировать %1 из-за неправильного формата файла</translation> + <translation type="vanished">Не получилось импортировать %1 из-за неправильного формата файла</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="486"/> - <location filename="../ProfileInterface.cpp" line="684"/> - <location filename="../UserInterface.cpp" line="441"/> + <location filename="../ProfileInterface.cpp" line="470"/> + <location filename="../ProfileInterface.cpp" line="760"/> + <location filename="../UserInterface.cpp" line="455"/> <source>No valid file is selected</source> <translation>Выбранный файл неверен</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="62"/> + <location filename="../ProfileInterface.cpp" line="65"/> <source>Enabled pictures: %1 of %2</source> <translation>Включенные картинки: %1 из %2</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="394"/> <source>Importable files (*.g5e *.jpg *.png SGTA* PGTA*)</source> - <translation>Подходящие для импорта файлы (*.g5e *.jpg *.png SGTA* PGTA*)</translation> + <translation type="vanished">Подходящие для импорта файлы (*.g5e *.jpg *.png SGTA* PGTA*)</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="398"/> <source>All image files (*.jpg *.png)</source> - <translation>Все изображения (*.jpg *.png)</translation> + <translation type="vanished">Все изображения (*.jpg *.png)</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="702"/> + <location filename="../ProfileInterface.cpp" line="442"/> + <source>Importable files (%1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="446"/> + <source>All image files (%1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="674"/> + <source>Can't import %1 because file can't be parsed properly</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="755"/> + <source>Can't import %1 because file format can't be detected</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="778"/> <source>Failed to import the Snapmatic picture, file not begin with PGTA or end with .g5e</source> <translation>Не удалось импортировать картинку Snapmatic, название не начинается с PGTA или не заканчивается с .g5e</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="707"/> + <location filename="../ProfileInterface.cpp" line="783"/> <source>Failed to import the Snapmatic picture, the picture is already in the game</source> <translation>Не удалось импортировать картинку Snapmatic, картинка уже в игре</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="718"/> + <location filename="../ProfileInterface.cpp" line="794"/> <source>Failed to import the Snapmatic picture, can't copy the file into profile</source> <translation>Не удалось импортировать картинку Snapmatic, не получилось скопировать файл в профиль</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="755"/> + <location filename="../ProfileInterface.cpp" line="831"/> <source>Failed to import the Savegame, can't copy the file into profile</source> <translation>Не удалось импортировать сохранение, не получилось скопировать файл в профиль</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="761"/> + <location filename="../ProfileInterface.cpp" line="837"/> <source>Failed to import the Savegame, no Savegame slot is left</source> <translation>Не удалось импортировать сохранение, нет пустых ячеек под сохранения</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="847"/> - <location filename="../ProfileInterface.cpp" line="865"/> + <location filename="../ProfileInterface.cpp" line="923"/> + <location filename="../ProfileInterface.cpp" line="941"/> <source>JPG pictures and GTA Snapmatic</source> <translation>Картинки JPG и GTA Snapmatic</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="848"/> - <location filename="../ProfileInterface.cpp" line="870"/> + <location filename="../ProfileInterface.cpp" line="924"/> + <location filename="../ProfileInterface.cpp" line="946"/> <source>JPG pictures only</source> <translation>Только картинки JPG</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="849"/> - <location filename="../ProfileInterface.cpp" line="874"/> + <location filename="../ProfileInterface.cpp" line="925"/> + <location filename="../ProfileInterface.cpp" line="950"/> <source>GTA Snapmatic only</source> <translation>Только GTA Snapmatic</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="959"/> - <location filename="../ProfileInterface.cpp" line="1001"/> + <location filename="../ProfileInterface.cpp" line="984"/> + <source>Initialising export...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1037"/> + <location filename="../ProfileInterface.cpp" line="1079"/> <source>No Snapmatic pictures or Savegames files are selected</source> <translation>Не выделены ни один Snapmatic или сохранение</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="967"/> - <location filename="../ProfileInterface.cpp" line="995"/> - <location filename="../ProfileInterface.cpp" line="1001"/> + <location filename="../ProfileInterface.cpp" line="1045"/> + <location filename="../ProfileInterface.cpp" line="1073"/> + <location filename="../ProfileInterface.cpp" line="1079"/> <source>Remove selected</source> <translation>Снять выделение</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="967"/> + <location filename="../ProfileInterface.cpp" line="1045"/> <source>You really want remove the selected Snapmatic picutres and Savegame files?</source> <translation>Точно ли хочешь удалить выбранные картинки Snapmatic и файлы сохранений?</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="995"/> + <location filename="../ProfileInterface.cpp" line="1073"/> <source>Failed at remove the complete selected Snapmatic pictures and/or Savegame files</source> <translation>Не удалось удалить полностью выбранные картинки Snapmatic и/или файлы сохранений</translation> </message> @@ -879,30 +1097,29 @@ Press 1 for Default View</source> <translation type="obsolete">Не получилось имортировать копию сохранения, потому что не осталось свободных под них слотов</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="824"/> - <location filename="../ProfileInterface.cpp" line="862"/> - <location filename="../ProfileInterface.cpp" line="939"/> - <location filename="../ProfileInterface.cpp" line="959"/> + <location filename="../ProfileInterface.cpp" line="900"/> + <location filename="../ProfileInterface.cpp" line="938"/> + <location filename="../ProfileInterface.cpp" line="1017"/> + <location filename="../ProfileInterface.cpp" line="1037"/> <source>Export selected</source> <translation>Экспортировать выделенное</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="862"/> + <location filename="../ProfileInterface.cpp" line="938"/> <source>%1Export Snapmatic pictures%2<br><br>JPG pictures make it possible to open the picture with a Image Viewer<br>GTA Snapmatic make it possible to import the picture into the game<br><br>Export as:</source> <translation>%1Эскпортировать картинки Snapmatic%2<br><br>Картинки JPG можно открыть любым просмотрщиком<br>Картинки формата GTA Snapmatic можно снова импортировать в игру<br><br>Экспортировать как:</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="905"/> + <location filename="../ProfileInterface.cpp" line="983"/> <source>Export selected...</source> <translation>Экпортировать выделенное...</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="906"/> <source>Initializing export...</source> - <translation>Подготавливаю эскпорт...</translation> + <translation type="vanished">Подготавливаю эскпорт...</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="939"/> + <location filename="../ProfileInterface.cpp" line="1017"/> <source>Export failed with... %1</source> @@ -911,20 +1128,20 @@ Press 1 for Default View</source> %1</translation> </message> <message> - <location filename="../ExportThread.cpp" line="96"/> - <location filename="../ExportThread.cpp" line="135"/> - <location filename="../ExportThread.cpp" line="156"/> + <location filename="../ExportThread.cpp" line="97"/> + <location filename="../ExportThread.cpp" line="136"/> + <location filename="../ExportThread.cpp" line="157"/> <source>Export file %1 of %2 files</source> <translation>Экспортируется файл %1 из %2</translation> </message> <message> - <location filename="../UserInterface.cpp" line="349"/> + <location filename="../UserInterface.cpp" line="363"/> <source>All profile files (*.g5e SGTA* PGTA*)</source> <translation>Все файлы профиля (*.g5e SGTA* PGTA*)</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="395"/> - <location filename="../UserInterface.cpp" line="350"/> + <location filename="../ProfileInterface.cpp" line="443"/> + <location filename="../UserInterface.cpp" line="364"/> <source>GTA V Export (*.g5e)</source> <translation>GTA V Export (*.g5e)</translation> </message> @@ -932,12 +1149,12 @@ Press 1 for Default View</source> <context> <name>QApplication</name> <message> - <location filename="../main.cpp" line="68"/> + <location filename="../main.cpp" line="66"/> <source>Font</source> <translation>Шрифт</translation> </message> <message> - <location filename="../main.cpp" line="68"/> + <location filename="../main.cpp" line="66"/> <source>Selected Font: %1</source> <translation>Выбранный шрифт: %1</translation> </message> @@ -951,17 +1168,17 @@ Press 1 for Default View</source> <translation>Просмотрщик сохранений</translation> </message> <message> - <location filename="../SavegameDialog.ui" line="29"/> + <location filename="../SavegameDialog.ui" line="23"/> <source><span style=" font-weight:600;">Savegame</span><br><br>%1</source> <translation><span style=" font-weight:600;">Сохранение</span><br><br>%1</translation> </message> <message> - <location filename="../SavegameDialog.ui" line="63"/> + <location filename="../SavegameDialog.ui" line="70"/> <source>&Export</source> <translation>&Экспорт</translation> </message> <message> - <location filename="../SavegameDialog.ui" line="76"/> + <location filename="../SavegameDialog.ui" line="83"/> <source>&Close</source> <translation>&Закрыть</translation> </message> @@ -991,17 +1208,17 @@ Press 1 for Default View</source> <translation type="vanished">Третий путь (100%) - 00/00/00 00:00:00</translation> </message> <message> - <location filename="../SavegameWidget.ui" line="80"/> + <location filename="../SavegameWidget.ui" line="83"/> <source>View savegame</source> <translation>Просмотреть сохранение</translation> </message> <message> - <location filename="../SavegameWidget.ui" line="83"/> + <location filename="../SavegameWidget.ui" line="86"/> <source>View</source> <translation>Просмотр</translation> </message> <message> - <location filename="../SavegameWidget.ui" line="99"/> + <location filename="../SavegameWidget.ui" line="102"/> <location filename="../SavegameCopy.cpp" line="48"/> <source>Export</source> <translation>Экспорт</translation> @@ -1011,14 +1228,14 @@ Press 1 for Default View</source> <translation type="obsolete">Копировать</translation> </message> <message> - <location filename="../SavegameWidget.ui" line="118"/> + <location filename="../SavegameWidget.ui" line="121"/> <source>Delete</source> <translation>Удалить</translation> </message> <message> - <location filename="../SavegameWidget.ui" line="115"/> - <location filename="../SavegameWidget.cpp" line="139"/> - <location filename="../SavegameWidget.cpp" line="152"/> + <location filename="../SavegameWidget.ui" line="118"/> + <location filename="../SavegameWidget.cpp" line="131"/> + <location filename="../SavegameWidget.cpp" line="144"/> <source>Delete savegame</source> <translation>Удалить сохранение</translation> </message> @@ -1028,84 +1245,84 @@ Press 1 for Default View</source> <translation>Экспортировать сохранение...</translation> </message> <message> - <location filename="../SavegameWidget.ui" line="64"/> + <location filename="../SavegameWidget.ui" line="67"/> <source>SAVE %3 - %1<br>%2</source> <translation>СОХРАНЕНИЕ %3 - %1<br>%2</translation> </message> <message> - <location filename="../SavegameWidget.cpp" line="101"/> - <location filename="../SavegameWidget.cpp" line="102"/> + <location filename="../SavegameWidget.cpp" line="89"/> + <location filename="../SavegameWidget.cpp" line="90"/> <source>WRONG FORMAT</source> <translation>НЕВЕРНЫЙ ФОРМАТ</translation> </message> <message> - <location filename="../SavegameWidget.cpp" line="64"/> + <location filename="../SavegameWidget.cpp" line="60"/> + <location filename="../SavegameWidget.cpp" line="117"/> <source>AUTOSAVE - %1 %2</source> <translation>АВТОСОХРАНЕНИЕ - %1 %2</translation> </message> <message> - <location filename="../SavegameWidget.cpp" line="65"/> + <location filename="../SavegameWidget.cpp" line="61"/> + <location filename="../SavegameWidget.cpp" line="118"/> <source>SAVE %3 - %1 %2</source> <translation>СОХРАНЕНИЕ %3 - %1 %2</translation> </message> <message> - <location filename="../SavegameWidget.cpp" line="125"/> + <location filename="../SavegameWidget.cpp" line="111"/> <source>UNKNOWN</source> <translation>НЕИЗВЕСТНО</translation> </message> <message> - <location filename="../SavegameWidget.cpp" line="139"/> + <location filename="../SavegameWidget.cpp" line="131"/> <source>Are you sure to delete %1 from your savegames?</source> <translation>Вы уверены, что хотите удалить сохранение %1?</translation> </message> <message> - <location filename="../SavegameWidget.cpp" line="152"/> + <location filename="../SavegameWidget.cpp" line="144"/> <source>Failed at deleting %1 from your savegames</source> <translation>Не удалось удалить сохранение %1</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1124"/> + <location filename="../ProfileInterface.cpp" line="1225"/> <source>&View</source> <translation>&Просмотр</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1126"/> + <location filename="../ProfileInterface.cpp" line="1227"/> <source>&Remove</source> <translation>&Удалить</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1130"/> - <location filename="../ProfileInterface.cpp" line="1141"/> + <location filename="../ProfileInterface.cpp" line="1229"/> <source>&Select</source> <translation>&Выбрать</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1131"/> + <location filename="../ProfileInterface.cpp" line="1230"/> <source>&Deselect</source> <translation>Сн&ять выбор</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1132"/> - <location filename="../ProfileInterface.cpp" line="1142"/> + <location filename="../ProfileInterface.cpp" line="1233"/> <source>Select &All</source> <translation>В&ыбрать все</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1135"/> + <location filename="../ProfileInterface.cpp" line="1237"/> <source>&Deselect All</source> <translation>Снять выбо&р со всех</translation> </message> <message> - <location filename="../SavegameWidget.ui" line="96"/> + <location filename="../SavegameWidget.ui" line="99"/> <source>Copy savegame</source> <translation>Копировать сохранение</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1125"/> + <location filename="../ProfileInterface.cpp" line="1226"/> <source>&Export</source> <translation>&Экспортировать</translation> </message> @@ -1165,7 +1382,7 @@ Press 1 for Default View</source> <message> <location filename="../SnapmaticEditor.ui" line="14"/> <location filename="../SnapmaticEditor.ui" line="81"/> - <location filename="../SnapmaticEditor.cpp" line="244"/> + <location filename="../SnapmaticEditor.cpp" line="245"/> <source>Snapmatic Properties</source> <translation>Свойства Snapmatic</translation> </message> @@ -1206,7 +1423,7 @@ Press 1 for Default View</source> </message> <message> <location filename="../SnapmaticEditor.ui" line="113"/> - <location filename="../SnapmaticEditor.cpp" line="199"/> + <location filename="../SnapmaticEditor.cpp" line="200"/> <source>Crew: %1 (%2)</source> <translation>Банда: %1 (%2)</translation> </message> @@ -1216,20 +1433,20 @@ Press 1 for Default View</source> <translation>Meme</translation> </message> <message> - <location filename="../SnapmaticEditor.cpp" line="294"/> + <location filename="../SnapmaticEditor.cpp" line="295"/> <source>Snapmatic Title</source> <translation>Заголовок Snapmatic</translation> </message> <message> <location filename="../SnapmaticEditor.ui" line="126"/> - <location filename="../SnapmaticEditor.cpp" line="184"/> + <location filename="../SnapmaticEditor.cpp" line="185"/> <source>Title: %1 (%2)</source> <translation>Заголовок: %1 (%2)</translation> </message> <message> <location filename="../SnapmaticEditor.ui" line="136"/> - <location filename="../SnapmaticEditor.cpp" line="188"/> - <location filename="../SnapmaticEditor.cpp" line="192"/> + <location filename="../SnapmaticEditor.cpp" line="189"/> + <location filename="../SnapmaticEditor.cpp" line="193"/> <source>Appropriate: %1</source> <translation>Разумные: %1</translation> </message> @@ -1259,40 +1476,40 @@ Press 1 for Default View</source> <translation>&Отмена</translation> </message> <message> - <location filename="../SnapmaticEditor.cpp" line="183"/> - <location filename="../SnapmaticEditor.cpp" line="198"/> + <location filename="../SnapmaticEditor.cpp" line="184"/> + <location filename="../SnapmaticEditor.cpp" line="199"/> <source>Edit</source> <translation>Правка</translation> </message> <message> - <location filename="../SnapmaticEditor.cpp" line="188"/> + <location filename="../SnapmaticEditor.cpp" line="189"/> <source>Yes</source> <comment>Yes, should work fine</comment> <translation>Да</translation> </message> <message> - <location filename="../SnapmaticEditor.cpp" line="192"/> + <location filename="../SnapmaticEditor.cpp" line="193"/> <source>No</source> <comment>No, could lead to issues</comment> <translation>Нет</translation> </message> <message> - <location filename="../SnapmaticEditor.cpp" line="244"/> + <location filename="../SnapmaticEditor.cpp" line="245"/> <source>Patching of Snapmatic Properties failed because of I/O Error</source> <translation>Не удалось измененить свойства Snapmatic из-за проблемы ввода/вывода</translation> </message> <message> - <location filename="../SnapmaticEditor.cpp" line="294"/> + <location filename="../SnapmaticEditor.cpp" line="295"/> <source>New Snapmatic title:</source> <translation>Новый заголовок Snapmatic:</translation> </message> <message> - <location filename="../SnapmaticEditor.cpp" line="319"/> + <location filename="../SnapmaticEditor.cpp" line="324"/> <source>Snapmatic Crew</source> <translation>Банда на Snapmatic</translation> </message> <message> - <location filename="../SnapmaticEditor.cpp" line="319"/> + <location filename="../SnapmaticEditor.cpp" line="324"/> <source>New Snapmatic crew:</source> <translation>Новая банда на Snapmatic:</translation> </message> @@ -1300,7 +1517,7 @@ Press 1 for Default View</source> <context> <name>SnapmaticPicture</name> <message> - <location filename="../SnapmaticPicture.cpp" line="367"/> + <location filename="../SnapmaticPicture.cpp" line="411"/> <source>PHOTO - %1</source> <translation>ФОТО - %1</translation> </message> @@ -1313,126 +1530,132 @@ Press 1 for Default View</source> <translation>Виджет Snapmatic</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="82"/> + <location filename="../SnapmaticWidget.ui" line="85"/> <source>PHOTO - 00/00/00 00:00:00</source> <translation>ФОТО - 00/00/00 00:00:00</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="98"/> + <location filename="../SnapmaticWidget.ui" line="101"/> <source>View picture</source> <translation>Просмотр картинки</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="101"/> + <location filename="../SnapmaticWidget.ui" line="104"/> <source>View</source> <translation>Просмотр</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="120"/> + <location filename="../SnapmaticWidget.ui" line="123"/> <source>Copy</source> <translation>Копировать</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="136"/> + <location filename="../SnapmaticWidget.ui" line="139"/> <source>Export</source> <translation>Экспорт</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="152"/> + <location filename="../SnapmaticWidget.ui" line="155"/> <source>Delete</source> <translation>Удалить</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="149"/> - <location filename="../SnapmaticWidget.cpp" line="163"/> - <location filename="../SnapmaticWidget.cpp" line="172"/> + <location filename="../SnapmaticWidget.ui" line="152"/> + <location filename="../SnapmaticWidget.cpp" line="144"/> + <location filename="../SnapmaticWidget.cpp" line="153"/> <source>Delete picture</source> <translation>Удалить картинку</translation> </message> <message> - <location filename="../SnapmaticWidget.cpp" line="163"/> + <location filename="../SnapmaticWidget.cpp" line="144"/> <source>Are you sure to delete %1 from your Snapmatic pictures?</source> <translation>Уверены, что хотите удалить %1 из коллекции картинок Snapmatic?</translation> </message> <message> - <location filename="../SnapmaticWidget.cpp" line="172"/> + <location filename="../SnapmaticWidget.cpp" line="153"/> <source>Failed at deleting %1 from your Snapmatic pictures</source> <translation>Не удалось удалить %1 из колелкции картинок Snapmatic </translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1083"/> + <location filename="../ProfileInterface.cpp" line="1178"/> <source>Edi&t</source> <translation>&Правка</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1086"/> + <location filename="../ProfileInterface.cpp" line="1181"/> <source>Show &In-game</source> <translation>Показывать в &игре</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1090"/> + <location filename="../ProfileInterface.cpp" line="1185"/> <source>Hide &In-game</source> <translation>Ск&рыть в игре</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1092"/> + <location filename="../ProfileInterface.cpp" line="1187"/> <source>&Edit Properties...</source> <translation>&Изменить свойства...</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1093"/> + <location filename="../ProfileInterface.cpp" line="1188"/> <source>&Export</source> <translation>&Экспорт</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1094"/> <source>Export as &JPG picture...</source> - <translation>Эксп&ортировать как картинку JPG...</translation> + <translation type="vanished">Эксп&ортировать как картинку JPG...</translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1189"/> + <source>Export as &Picture...</source> + <translation type="unfinished"></translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1095"/> <source>Export as &GTA Snapmatic...</source> - <translation>Экс&портировать как GTA Snapmatic...</translation> + <translation type="vanished">Экс&портировать как GTA Snapmatic...</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1096"/> + <location filename="../ProfileInterface.cpp" line="1190"/> + <source>Export as &Snapmatic...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ProfileInterface.cpp" line="1191"/> <source>&View</source> <translation>По&казать</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1099"/> + <location filename="../ProfileInterface.cpp" line="1194"/> <source>&Remove</source> <translation>У&далить</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1103"/> - <location filename="../ProfileInterface.cpp" line="1114"/> + <location filename="../ProfileInterface.cpp" line="1196"/> <source>&Select</source> <translation>&Выделить</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1104"/> + <location filename="../ProfileInterface.cpp" line="1197"/> <source>&Deselect</source> <translation>Сн&ять выделение</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1105"/> - <location filename="../ProfileInterface.cpp" line="1115"/> + <location filename="../ProfileInterface.cpp" line="1200"/> <source>Select &All</source> <translation>В&ыбрать все</translation> </message> <message> - <location filename="../ProfileInterface.cpp" line="1108"/> + <location filename="../ProfileInterface.cpp" line="1204"/> <source>&Deselect All</source> <translation>Снять выбо&р со всех</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="117"/> + <location filename="../SnapmaticWidget.ui" line="120"/> <source>Copy picture</source> <translation>Скопировать картинку</translation> </message> <message> - <location filename="../SnapmaticWidget.ui" line="133"/> + <location filename="../SnapmaticWidget.ui" line="136"/> <source>Export picture</source> <translation>Экспорт картинки</translation> </message> @@ -1454,123 +1677,134 @@ Press 1 for Default View</source> <translation>%1 %2</translation> </message> <message> - <location filename="../UserInterface.ui" line="173"/> + <location filename="../UserInterface.ui" line="131"/> + <source>Reload profile overview</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="150"/> + <source>Close %1</source> + <extracomment>Close %1 <- (gta5view/gta5sync) - %1 will be replaced automatically</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../UserInterface.ui" line="179"/> <source>&File</source> <translation>&Файл</translation> </message> <message> - <location filename="../UserInterface.ui" line="183"/> + <location filename="../UserInterface.ui" line="189"/> <source>&Help</source> <translation>&Справка</translation> </message> <message> - <location filename="../UserInterface.ui" line="189"/> + <location filename="../UserInterface.ui" line="195"/> <source>&Edit</source> <translation>&Правка</translation> </message> <message> - <location filename="../UserInterface.ui" line="195"/> + <location filename="../UserInterface.ui" line="201"/> <source>&Profile</source> <translation>П&рофиль</translation> </message> <message> - <location filename="../UserInterface.ui" line="228"/> + <location filename="../UserInterface.ui" line="234"/> <source>&Exit</source> <translation>В&ыход</translation> </message> <message> - <location filename="../UserInterface.ui" line="231"/> + <location filename="../UserInterface.ui" line="237"/> <source>Exit</source> <translation>Выход</translation> </message> <message> - <location filename="../UserInterface.ui" line="239"/> + <location filename="../UserInterface.ui" line="245"/> <source>Close &Profile</source> <translation>Закрыть п&рофиль</translation> </message> <message> - <location filename="../UserInterface.ui" line="242"/> + <location filename="../UserInterface.ui" line="248"/> <source>Ctrl+End</source> <translation>Ctrl+End</translation> </message> <message> - <location filename="../UserInterface.ui" line="247"/> + <location filename="../UserInterface.ui" line="253"/> <source>&Settings</source> <translation>&Настройки</translation> </message> <message> - <location filename="../UserInterface.ui" line="282"/> + <location filename="../UserInterface.ui" line="288"/> <source>Ctrl+Del</source> <translation>Ctrl+Del</translation> </message> <message> - <location filename="../UserInterface.ui" line="287"/> + <location filename="../UserInterface.ui" line="293"/> <source>&Import files...</source> <translation>&Импортировать файлы...</translation> </message> <message> - <location filename="../UserInterface.ui" line="290"/> + <location filename="../UserInterface.ui" line="296"/> <source>Ctrl+I</source> <translation>Ctrl+I</translation> </message> <message> - <location filename="../UserInterface.ui" line="303"/> - <location filename="../UserInterface.cpp" line="151"/> + <location filename="../UserInterface.ui" line="309"/> + <location filename="../UserInterface.cpp" line="163"/> <source>Select &GTA V Folder...</source> <translation>Выбрать &папку GTA V...</translation> </message> <message> - <location filename="../UserInterface.ui" line="309"/> + <location filename="../UserInterface.ui" line="315"/> <source>Ctrl+G</source> <translation>Ctrl+G</translation> </message> <message> - <location filename="../UserInterface.ui" line="314"/> + <location filename="../UserInterface.ui" line="320"/> <source>Show In-gam&e</source> <translation>Показывать в и&гре</translation> </message> <message> - <location filename="../UserInterface.ui" line="317"/> + <location filename="../UserInterface.ui" line="323"/> <source>Shift+E</source> <translation>Shift+E</translation> </message> <message> - <location filename="../UserInterface.ui" line="322"/> + <location filename="../UserInterface.ui" line="328"/> <source>Hi&de In-game</source> <translation>Скры&ть в игре</translation> </message> <message> - <location filename="../UserInterface.ui" line="325"/> + <location filename="../UserInterface.ui" line="331"/> <source>Shift+D</source> <translation>Shift+D</translation> </message> <message> - <location filename="../UserInterface.ui" line="147"/> + <location filename="../UserInterface.ui" line="153"/> <source>&Close</source> <translation>&Закрыть</translation> </message> <message> - <location filename="../UserInterface.ui" line="199"/> + <location filename="../UserInterface.ui" line="205"/> <source>&Selection visibility</source> <translation>В&идимость выделение</translation> </message> <message> - <location filename="../UserInterface.ui" line="255"/> + <location filename="../UserInterface.ui" line="261"/> <source>Select &All</source> <translation>В&ыбрать все</translation> </message> <message> - <location filename="../UserInterface.ui" line="263"/> + <location filename="../UserInterface.ui" line="269"/> <source>&Deselect All</source> <translation>Снять выбо&р со всех</translation> </message> <message> - <location filename="../UserInterface.ui" line="271"/> + <location filename="../UserInterface.ui" line="277"/> <source>&Export selected...</source> <translation>&Экпортировать выделенное...</translation> </message> <message> - <location filename="../UserInterface.ui" line="279"/> + <location filename="../UserInterface.ui" line="285"/> <source>&Remove selected</source> <translation>&Удалить выделенное</translation> </message> @@ -1587,7 +1821,7 @@ Press 1 for Default View</source> <translation type="obsolete">О программе gta5sync</translation> </message> <message> - <location filename="../UserInterface.ui" line="258"/> + <location filename="../UserInterface.ui" line="264"/> <source>Ctrl+A</source> <translation>Ctrl+A</translation> </message> @@ -1596,81 +1830,83 @@ Press 1 for Default View</source> <translation type="obsolete">Закрыть</translation> </message> <message> - <location filename="../UserInterface.ui" line="234"/> + <location filename="../UserInterface.ui" line="240"/> <source>Ctrl+Q</source> <translation>Ctrl+Q</translation> </message> <message> - <location filename="../UserInterface.ui" line="223"/> + <location filename="../UserInterface.ui" line="229"/> <source>Ctrl+P</source> <translation>Ctrl+P</translation> </message> <message> - <location filename="../UserInterface.ui" line="295"/> + <location filename="../UserInterface.ui" line="301"/> <source>&Open File...</source> <translation>&Открыть файл...</translation> </message> <message> - <location filename="../UserInterface.ui" line="298"/> + <location filename="../UserInterface.ui" line="304"/> <source>Ctrl+O</source> <translation>Ctrl+O</translation> </message> <message> - <location filename="../UserInterface.ui" line="250"/> + <location filename="../UserInterface.ui" line="256"/> <source>Ctrl+S</source> <translation>Ctrl+S</translation> </message> <message> - <location filename="../UserInterface.ui" line="274"/> + <location filename="../UserInterface.ui" line="280"/> <source>Ctrl+E</source> <translation>Ctrl+E</translation> </message> <message> - <location filename="../UserInterface.ui" line="266"/> + <location filename="../UserInterface.ui" line="272"/> <source>Ctrl+D</source> <translation>Ctrl+D</translation> </message> <message> - <location filename="../UserInterface.cpp" line="62"/> - <location filename="../UserInterface.cpp" line="220"/> + <location filename="../UserInterface.cpp" line="64"/> + <location filename="../UserInterface.cpp" line="234"/> + <location filename="../UserInterface.cpp" line="550"/> <source>Select Profile</source> <translation>Выбор профиля</translation> </message> <message> - <location filename="../UserInterface.ui" line="306"/> - <location filename="../OptionsDialog.cpp" line="452"/> - <location filename="../UserInterface.cpp" line="99"/> - <location filename="../UserInterface.cpp" line="495"/> + <location filename="../UserInterface.ui" line="312"/> + <location filename="../OptionsDialog.cpp" line="445"/> + <location filename="../UserInterface.cpp" line="104"/> + <location filename="../UserInterface.cpp" line="513"/> <source>Select GTA V Folder...</source> <translation>Выбрать папку GTA V...</translation> </message> <message> <location filename="../UserInterface.ui" line="20"/> - <location filename="../UserInterface.cpp" line="60"/> + <location filename="../UserInterface.cpp" line="62"/> <source>%2 - %1</source> <translation>%2 - %1</translation> </message> <message> - <location filename="../UserInterface.ui" line="220"/> - <location filename="../UserInterface.cpp" line="59"/> + <location filename="../UserInterface.ui" line="226"/> + <location filename="../UserInterface.cpp" line="60"/> + <location filename="../UserInterface.cpp" line="542"/> <source>&About %1</source> <translation>&О %1</translation> </message> <message> - <location filename="../UserInterface.cpp" line="346"/> + <location filename="../UserInterface.cpp" line="360"/> <source>Open File...</source> <translation>Открыть файл...</translation> </message> <message> - <location filename="../UserInterface.cpp" line="393"/> - <location filename="../UserInterface.cpp" line="409"/> - <location filename="../UserInterface.cpp" line="436"/> - <location filename="../UserInterface.cpp" line="441"/> + <location filename="../UserInterface.cpp" line="407"/> + <location filename="../UserInterface.cpp" line="423"/> + <location filename="../UserInterface.cpp" line="450"/> + <location filename="../UserInterface.cpp" line="455"/> <source>Open File</source> <translation>Открыть файл</translation> </message> <message> - <location filename="../UserInterface.cpp" line="436"/> + <location filename="../UserInterface.cpp" line="450"/> <source>Can't open %1 because of not valid file format</source> <translation>Не удалось открыть %1 из-за неверного формата файла</translation> </message> @@ -1679,7 +1915,7 @@ Press 1 for Default View</source> <translation type="obsolete">gta5sync</translation> </message> <message> - <location filename="../UserInterface.ui" line="131"/> + <location filename="../UserInterface.ui" line="134"/> <source>&Reload</source> <translation>Пере&загрузить</translation> </message> diff --git a/res/mappreview.jpg b/res/mappreview.jpg new file mode 100644 index 0000000000000000000000000000000000000000..00496923d32fe9af67c6dfe55df3d105359cb1ab GIT binary patch literal 207939 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%0D5q4Vta9Ob0n+GyXDDWFG$oKoGne}40jk5TovFt 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 Kap9-_hyU5!Uw`5N literal 0 HcmV?d00001 diff --git a/res/pointmaker-16.png b/res/pointmaker-16.png new file mode 100644 index 0000000000000000000000000000000000000000..3244d6e50852fecd18bee7486b92df4616572b22 GIT binary patch literal 352 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucLCF%=h?3y^w370~qEv>0#LT=By}Z;C1rt33 zJwtQjy!pvMMHf6>978Pp?@r#$d&oe<HFn7d4#|e5j~X|+CK+mINHkAUVr|{|{1>Za ziqdrjS(kf%AM{W1(sY~eDRacthV`&mT1LgPa=k;FcXXL;V7+I#>0f$#`6CrMr%UW- zE_`^<%M+=8@=)xSg>n_Mgf`uqemnZHSjFOo9NP`|Hq|$pbDg->9x9W1_OE9ne<5cg z%O1gRioc}JEA};*bJg^^%Y93FqV@4XFViN?ZfRzgTh+G{+pe{oOj-Ho+vz8h96wx} s-nm{QQB|k2_GiNWgtj*I>oK1CK3=UelKSUY0R6_`>FVdQ&MBb@0Ls0HJpcdz literal 0 HcmV?d00001 diff --git a/res/pointmaker-24.png b/res/pointmaker-24.png new file mode 100644 index 0000000000000000000000000000000000000000..d3373572cd99c4f7552b25915299ef3d427c0a12 GIT binary patch literal 444 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucLCF%=h?3y^w370~qEv>0#LT=By}Z;C1rt33 zJwtQjy!pvMQ*}ID978<3-%hhGVlotPc^dtLp{1I|$;pZD!ETE$hBYEUCKDgyOy-^U zGnUMHx_tw;WXRrCQ?Fd!`%A&Y^11Ps$gcQ}!X<Z@cyB#*T_2~sbY?_%#s`io=c?u% ztkL6Bs_)9*C|d8a?tp~UmMa0T<vzzX*zMUlbA5~4tdn~KoOR{ir5az<c)Ll5V@)=b zV#?cl+ZLJ~HO#N$l1tqAVViKmYl+t21E-lk=($fk+qFpZ!BfVH>BrVy{-jY6dSC3o z0pm(`o=<!dDr|2mD=v!jzAp;>^W%XrP{W&56>n3Yhrep;(+_M-K6v=7`N!`IetW!( za6WdXWmeX^xLEEF6I^){yVg9mmF{QDjTQSIVRHZ11I4);o=S0U{r2pvu~}65%?iH; k*@ui57VQ17U3Gc=zsfh4?tGeZ8W^|?p00i_>zopr0J}1}ZU6uP literal 0 HcmV?d00001 diff --git a/res/pointmaker-32.png b/res/pointmaker-32.png new file mode 100644 index 0000000000000000000000000000000000000000..610efd47adb3d48e6bd0ce240fb6e8c377148a95 GIT binary patch literal 611 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DjSL74G){)!Z!pk#?_L`iUdT1k0gQ7S`0VrE{6US4X6f{C7i zo}syM-uz^ssh2%n977`9k4{$%Vm1_MQ`XY53`tF8Wje?x;PLJNqn3az3%i5D1W^yZ zMhAuI|G7Qy-G2Md$695fas0CPU!T?{PQDv?$bhH&#b&|kLXr5UCzb)HWuE0dt4e=1 zSurP=`TiIE3)$AMrC1f$u&n+zIos*|)f1Kz?YoU0dfn+1|EQVtQxc@%(&6tS7N?XR zO%OBqb$b0#)k~@`9QE%<zj5cj&~B^G`hAJEv;TX6k3KKL_uXzx-fDQa;p9{cwemez zlP3LLRd{pyg6~g!9&FqD{6fGDA(@-g@09(t+$pk^#r>P=cH4(hasPPw-gxJEXS`@C z=i)XgIcVL=Dz)pu+(S&fu^;>r8{70MmTz!y7T*&bv0x$hJx!ep7g*nmh#{1_{y5h- zuY0p_R+IAYN!ELwADO*ig{s9S{hfz{{cJe8qCmp8<BtD(*ve8~BmK{#^PyY79j2;u z|DttYxbGj<Q&sMFieKdf^uq2>L9@gP3+(x}FFICsp*e2fb_<d9(FdaTENkNUeRSc& zCvipHLBIg<`zBMc#$W7#nBgv=sSC>|x-aMV`t;prN^>M*)lpmf!n3N5^6&Wagx`hA qNj&YWWV>S2zVnO3U*{~IhwK%z?};{QD9#6_0R~T3KbLh*2~7aojsqY7 literal 0 HcmV?d00001 diff --git a/res/pointmaker-8.png b/res/pointmaker-8.png new file mode 100644 index 0000000000000000000000000000000000000000..a116c729441fee61f374d8ff9a07921195fd4c0c GIT binary patch literal 244 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucLCF%=h?3y^w370~qEv>0#LT=By}Z;C1rt33 zJwtQjy!pvMMJb*xjv*Sst$iDL8w_|@)-Oq7x}hz5cv*s=S_7k8y+M!&m(t#(|Fts8 zoffHW%6aCecBw4ZDY(XP(QN0o^tQ{kZ=5Y(a>vj7%Wjh<-;lb#*6`rAL#BF}=XGSZ h2Iz_Wsm$~jGM|^3FxPOY(@vm$44$rjF6*2UngCLkOlSZA literal 0 HcmV?d00001 diff --git a/res/qtbase_en_GB.qm b/res/qtbase_en_GB.qm new file mode 100644 index 0000000000000000000000000000000000000000..f88ef8869e2c72f1c18f44a93d77208331255171 GIT binary patch literal 941 zcma)4&npB`9RKbvyV`asQqrcUc$bmlD5;$xyG53fv**pjFlM&-QIbDElyXoGE_)|e zi4=#8a^xZ>7Z*8`;yX)fGi%JZdEfVa-|zc;zCYgJvDS9|vcG%NnK_>=oju3^Py}gf z4IokiY0uYXkjihUpJ8Hs6CipNJ>2o_&e+}N1=_cD`BfF~LEZMf?^hD@ea-04HRNC3 z(OybEoerS;HPw6dh<YwnEM1~LNJ~Q}=x@;hVwo78^Z<n{Xeb0+uy9qt1E;cIsaO^m zc<zA>P6J+mIR33Pt7*iwh~hb}wL%ojuxuxRp44PzKddvuT8Q`z8Dx-wA*K!-5jmp$ zMod$gIXWl&52Ox6s?IJLtC4=ERTJz3zn@|fbkr8Y90*9iDlSfQ)8k`7VOS+aDO4(4 z#u`<u(guNIR`>9Sw3!xkzD!i^Q-Ad@jK7{v2`z}eD$9DRGWQ=*Gt3B$YRXchxX1`! zWTq*?<KwbHJrN4qrFgbu*@U^IyRV0I_a_Usa2ztCD*l_|%;drd?MBX{fmAq*b{v4f YM<#F#ZjAw?RAC72)@uC*!bBsHPg^MGW&i*H literal 0 HcmV?d00001 diff --git a/res/tr_g5p.qrc b/res/tr_g5p.qrc index 393f585..1ff8d2e 100644 --- a/res/tr_g5p.qrc +++ b/res/tr_g5p.qrc @@ -1,5 +1,6 @@ <RCC> <qresource prefix="/tr"> + <file>gta5sync_en_US.qm</file> <file>gta5sync_de.qm</file> <file>gta5sync_fr.qm</file> <file>gta5sync_ru.qm</file> diff --git a/res/tr_qt5.qrc b/res/tr_qt5.qrc index f34728d..4adfa51 100644 --- a/res/tr_qt5.qrc +++ b/res/tr_qt5.qrc @@ -1,5 +1,6 @@ <RCC> <qresource prefix="/tr"> + <file>qtbase_en_GB.qm</file> <file>qtbase_de.qm</file> <file>qtbase_fr.qm</file> <file>qtbase_ru.qm</file> diff --git a/uimod/UiModLabel.cpp b/uimod/UiModLabel.cpp index 0051a7a..27c6a7d 100755 --- a/uimod/UiModLabel.cpp +++ b/uimod/UiModLabel.cpp @@ -1,75 +1,75 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "UiModLabel.h" -#include <QPaintEvent> -#include <QMouseEvent> - -UiModLabel::UiModLabel(const QString &text, QWidget *parent) : QLabel(parent) -{ - setText(text); -} - -UiModLabel::UiModLabel(QWidget *parent, const QString &text) : QLabel(parent) -{ - setText(text); -} - -UiModLabel::UiModLabel(QWidget *parent) : QLabel(parent) -{ -} - -UiModLabel::~UiModLabel() -{ -} - -void UiModLabel::paintEvent(QPaintEvent *ev) -{ - QLabel::paintEvent(ev); - emit labelPainted(); -} - -void UiModLabel::mouseMoveEvent(QMouseEvent *ev) -{ - QLabel::mouseMoveEvent(ev); - emit mouseMoved(); -} - -void UiModLabel::mousePressEvent(QMouseEvent *ev) -{ - QLabel::mousePressEvent(ev); - emit mousePressed(ev->button()); -} - -void UiModLabel::mouseReleaseEvent(QMouseEvent *ev) -{ - QLabel::mouseReleaseEvent(ev); - emit mouseReleased(ev->button()); -} - -void UiModLabel::mouseDoubleClickEvent(QMouseEvent *ev) -{ - QLabel::mouseDoubleClickEvent(ev); - emit mouseDoubleClicked(ev->button()); -} - -void UiModLabel::resizeEvent(QResizeEvent *ev) -{ - QLabel::resizeEvent(ev); - emit resized(ev->size()); -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "UiModLabel.h" +#include <QPaintEvent> +#include <QMouseEvent> + +UiModLabel::UiModLabel(const QString &text, QWidget *parent) : QLabel(parent) +{ + setText(text); +} + +UiModLabel::UiModLabel(QWidget *parent, const QString &text) : QLabel(parent) +{ + setText(text); +} + +UiModLabel::UiModLabel(QWidget *parent) : QLabel(parent) +{ +} + +UiModLabel::~UiModLabel() +{ +} + +void UiModLabel::paintEvent(QPaintEvent *ev) +{ + QLabel::paintEvent(ev); + emit labelPainted(); +} + +void UiModLabel::mouseMoveEvent(QMouseEvent *ev) +{ + QLabel::mouseMoveEvent(ev); + emit mouseMoved(); +} + +void UiModLabel::mousePressEvent(QMouseEvent *ev) +{ + QLabel::mousePressEvent(ev); + emit mousePressed(ev->button()); +} + +void UiModLabel::mouseReleaseEvent(QMouseEvent *ev) +{ + QLabel::mouseReleaseEvent(ev); + emit mouseReleased(ev->button()); +} + +void UiModLabel::mouseDoubleClickEvent(QMouseEvent *ev) +{ + QLabel::mouseDoubleClickEvent(ev); + emit mouseDoubleClicked(ev->button()); +} + +void UiModLabel::resizeEvent(QResizeEvent *ev) +{ + QLabel::resizeEvent(ev); + emit resized(ev->size()); +} diff --git a/uimod/UiModLabel.h b/uimod/UiModLabel.h index 545ee27..7d35e87 100755 --- a/uimod/UiModLabel.h +++ b/uimod/UiModLabel.h @@ -1,53 +1,53 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2016-2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef UIMODLABEL_H -#define UIMODLABEL_H - -#include <QWidget> -#include <QString> -#include <QLabel> -#include <QSize> - -class UiModLabel : public QLabel -{ - Q_OBJECT -public: - UiModLabel(const QString &text, QWidget *parent = 0); - UiModLabel(QWidget *parent, const QString &text); - UiModLabel(QWidget *parent = 0); - ~UiModLabel(); - -protected: - void mouseMoveEvent(QMouseEvent *ev); - void mousePressEvent(QMouseEvent *ev); - void mouseReleaseEvent(QMouseEvent *ev); - void mouseDoubleClickEvent(QMouseEvent *ev); - void paintEvent(QPaintEvent *ev); - void resizeEvent(QResizeEvent *ev); - -signals: - void mouseMoved(); - void mousePressed(Qt::MouseButton button); - void mouseReleased(Qt::MouseButton button); - void mouseDoubleClicked(Qt::MouseButton button); - void labelPainted(); - void resized(QSize newSize); -}; - -#endif // UIMODLABEL_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2016-2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef UIMODLABEL_H +#define UIMODLABEL_H + +#include <QWidget> +#include <QString> +#include <QLabel> +#include <QSize> + +class UiModLabel : public QLabel +{ + Q_OBJECT +public: + UiModLabel(const QString &text, QWidget *parent = 0); + UiModLabel(QWidget *parent, const QString &text); + UiModLabel(QWidget *parent = 0); + ~UiModLabel(); + +protected: + void mouseMoveEvent(QMouseEvent *ev); + void mousePressEvent(QMouseEvent *ev); + void mouseReleaseEvent(QMouseEvent *ev); + void mouseDoubleClickEvent(QMouseEvent *ev); + void paintEvent(QPaintEvent *ev); + void resizeEvent(QResizeEvent *ev); + +signals: + void mouseMoved(); + void mousePressed(Qt::MouseButton button); + void mouseReleased(Qt::MouseButton button); + void mouseDoubleClicked(Qt::MouseButton button); + void labelPainted(); + void resized(QSize newSize); +}; + +#endif // UIMODLABEL_H diff --git a/uimod/UiModWidget.cpp b/uimod/UiModWidget.cpp index f9dd61f..b517463 100644 --- a/uimod/UiModWidget.cpp +++ b/uimod/UiModWidget.cpp @@ -1,76 +1,76 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#include "UiModWidget.h" -#include <QStyleOption> -#include <QDropEvent> -#include <QMimeData> -#include <QPainter> -#include <QDebug> -#include <QUrl> - -UiModWidget::UiModWidget(QWidget *parent) : QWidget(parent) -{ - filesMode = false; -} - -UiModWidget::~UiModWidget() -{ -} - -void UiModWidget::setFilesMode(bool filesModeEnabled) -{ - filesMode = filesModeEnabled; -} - -void UiModWidget::dragEnterEvent(QDragEnterEvent *dragEnterEvent) -{ - if (filesMode && dragEnterEvent->mimeData()->hasUrls()) - { - QStringList pathList; - QList<QUrl> urlList = dragEnterEvent->mimeData()->urls(); - - foreach(const QUrl ¤tUrl, urlList) - { - if (currentUrl.isLocalFile()) - { - pathList.append(currentUrl.toLocalFile()); - } - } - - if (!pathList.isEmpty()) - { - dragEnterEvent->acceptProposedAction(); - } - } -} - -void UiModWidget::dropEvent(QDropEvent *dropEvent) -{ - dropEvent->acceptProposedAction(); - emit dropped(dropEvent->mimeData()); -} - -void UiModWidget::paintEvent(QPaintEvent *paintEvent) -{ - Q_UNUSED(paintEvent) - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "UiModWidget.h" +#include <QStyleOption> +#include <QDropEvent> +#include <QMimeData> +#include <QPainter> +#include <QDebug> +#include <QUrl> + +UiModWidget::UiModWidget(QWidget *parent) : QWidget(parent) +{ + filesMode = false; +} + +UiModWidget::~UiModWidget() +{ +} + +void UiModWidget::setFilesMode(bool filesModeEnabled) +{ + filesMode = filesModeEnabled; +} + +void UiModWidget::dragEnterEvent(QDragEnterEvent *dragEnterEvent) +{ + if (filesMode && dragEnterEvent->mimeData()->hasUrls()) + { + QStringList pathList; + QList<QUrl> urlList = dragEnterEvent->mimeData()->urls(); + + foreach(const QUrl ¤tUrl, urlList) + { + if (currentUrl.isLocalFile()) + { + pathList.append(currentUrl.toLocalFile()); + } + } + + if (!pathList.isEmpty()) + { + dragEnterEvent->acceptProposedAction(); + } + } +} + +void UiModWidget::dropEvent(QDropEvent *dropEvent) +{ + dropEvent->acceptProposedAction(); + emit dropped(dropEvent->mimeData()); +} + +void UiModWidget::paintEvent(QPaintEvent *paintEvent) +{ + Q_UNUSED(paintEvent) + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +} diff --git a/uimod/UiModWidget.h b/uimod/UiModWidget.h index 3858425..d30637d 100644 --- a/uimod/UiModWidget.h +++ b/uimod/UiModWidget.h @@ -1,47 +1,47 @@ -/***************************************************************************** -* gta5sync GRAND THEFT AUTO V SYNC -* Copyright (C) 2017 Syping -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*****************************************************************************/ - -#ifndef UIMODWIDGET_H -#define UIMODWIDGET_H - -#include <QMimeData> -#include <QWidget> -#include <QString> -#include <QSize> - -class UiModWidget : public QWidget -{ - Q_OBJECT -public: - UiModWidget(QWidget *parent = 0); - void setFilesMode(bool enabled); - ~UiModWidget(); - -protected: - void dragEnterEvent(QDragEnterEvent *dragEnterEvent); - void dropEvent(QDropEvent *dropEvent); - void paintEvent(QPaintEvent *paintEvent); - -private: - bool filesMode; - -signals: - void dropped(const QMimeData *mimeData); -}; - -#endif // UIMODWIDGET_H +/***************************************************************************** +* gta5sync GRAND THEFT AUTO V SYNC +* Copyright (C) 2017 Syping +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef UIMODWIDGET_H +#define UIMODWIDGET_H + +#include <QMimeData> +#include <QWidget> +#include <QString> +#include <QSize> + +class UiModWidget : public QWidget +{ + Q_OBJECT +public: + UiModWidget(QWidget *parent = 0); + void setFilesMode(bool enabled); + ~UiModWidget(); + +protected: + void dragEnterEvent(QDragEnterEvent *dragEnterEvent); + void dropEvent(QDropEvent *dropEvent); + void paintEvent(QPaintEvent *paintEvent); + +private: + bool filesMode; + +signals: + void dropped(const QMimeData *mimeData); +}; + +#endif // UIMODWIDGET_H