rdr2view initial
This commit is contained in:
commit
b3a4c3ef5f
198 changed files with 62708 additions and 0 deletions
28
.gitattributes
vendored
Normal file
28
.gitattributes
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# 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
|
||||||
|
*.nsi text eol=crlf
|
||||||
|
*.exe.manifest text eol=crlf
|
||||||
|
|
||||||
|
# Binary files
|
||||||
|
*.png binary
|
||||||
|
*.jpg binary
|
||||||
|
*.qm binary
|
||||||
|
*.ico binary
|
||||||
|
*.icns binary
|
||||||
|
*.xcf binary
|
||||||
|
*.r5e binary
|
35
.gitignore
vendored
Normal file
35
.gitignore
vendored
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
# Compiled Object files
|
||||||
|
*.slo
|
||||||
|
*.lo
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Compiled Dynamic libraries
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
*.dll
|
||||||
|
|
||||||
|
# Fortran module files
|
||||||
|
*.mod
|
||||||
|
|
||||||
|
# Compiled Static libraries
|
||||||
|
*.lai
|
||||||
|
*.la
|
||||||
|
*.a
|
||||||
|
*.lib
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
|
||||||
|
# Qt project user file
|
||||||
|
*.pro.user
|
||||||
|
|
||||||
|
# Gettext translation files
|
||||||
|
*.po
|
||||||
|
*.pot
|
135
AboutDialog.cpp
Normal file
135
AboutDialog.cpp
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 Profile Viewer
|
||||||
|
* Copyright (C) 2016-2019 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 <QDesktopServices>
|
||||||
|
#include <QStringBuilder>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#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 = AppEnv::getBuildDateTime();
|
||||||
|
QString buildStr = GTA5SYNC_BUILDSTRING;
|
||||||
|
#ifndef GTA5SYNC_BUILDTYPE_REL
|
||||||
|
#ifdef GTA5SYNC_COMMIT
|
||||||
|
if (!appVersion.contains("-")) { appVersion = appVersion % "-" % GTA5SYNC_COMMIT; }
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Translator Comments
|
||||||
|
//: Translated by translator, example Translated by Syping
|
||||||
|
QString translatedByStr = tr("Translated by %1");
|
||||||
|
//: Insert your name here and profile here in following scheme, First Translator,First Profile\\nSecond Translator\\nThird Translator,Second Profile
|
||||||
|
QString translatorVal = tr("TRANSLATOR");
|
||||||
|
QStringList translatorContent;
|
||||||
|
if (translatorVal != "TRANSLATOR")
|
||||||
|
{
|
||||||
|
const QStringList translatorList = translatorVal.split('\n');
|
||||||
|
for (const QString &translatorStr : translatorList)
|
||||||
|
{
|
||||||
|
QStringList translatorStrList = translatorStr.split(',');
|
||||||
|
QString translatorName = translatorStrList.at(0);
|
||||||
|
translatorStrList.removeFirst();
|
||||||
|
QString translatorProfile = translatorStrList.join(QString());
|
||||||
|
if (!translatorProfile.isEmpty())
|
||||||
|
{
|
||||||
|
translatorContent += QString("<a href=\"%1\">%2</a>").arg(translatorProfile, translatorName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
translatorContent += translatorName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Project Description
|
||||||
|
QString projectDes = tr("A project for viewing Red Dead Redemption 2 Snapmatic<br/>\nPictures and Savegames");
|
||||||
|
|
||||||
|
// 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 (!translatorContent.isEmpty())
|
||||||
|
{
|
||||||
|
copyrightDesA = copyrightDes1 % "<br/>" % translatedByStr.arg(translatorContent.join(", ")) % "<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));
|
||||||
|
|
||||||
|
// Set Icon for Close Button
|
||||||
|
if (QIcon::hasThemeIcon("dialog-close"))
|
||||||
|
{
|
||||||
|
ui->cmdClose->setIcon(QIcon::fromTheme("dialog-close"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("gtk-close"))
|
||||||
|
{
|
||||||
|
ui->cmdClose->setIcon(QIcon::fromTheme("gtk-close"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// DPI calculation
|
||||||
|
qreal screenRatio = AppEnv::screenRatio();
|
||||||
|
if (!translatorContent.isEmpty())
|
||||||
|
{
|
||||||
|
resize(375 * screenRatio, 270 * screenRatio);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resize(375 * screenRatio, 260 * screenRatio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AboutDialog::~AboutDialog()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AboutDialog::on_labAbout_linkActivated(const QString &link)
|
||||||
|
{
|
||||||
|
if (link.left(12) == "g5e://about?")
|
||||||
|
{
|
||||||
|
QStringList aboutStrList = QString(link).remove(0, 12).split(":");
|
||||||
|
QMessageBox::information(this, QString::fromUtf8(QByteArray::fromBase64(aboutStrList.at(0).toUtf8())), QString::fromUtf8(QByteArray::fromBase64(aboutStrList.at(1).toUtf8())));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QDesktopServices::openUrl(QUrl(link));
|
||||||
|
}
|
||||||
|
}
|
45
AboutDialog.h
Normal file
45
AboutDialog.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 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:
|
||||||
|
void on_labAbout_linkActivated(const QString &link);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::AboutDialog *ui;
|
||||||
|
QString aboutStr;
|
||||||
|
QString titleStr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ABOUTDIALOG_H
|
102
AboutDialog.ui
Normal file
102
AboutDialog.ui
Normal file
|
@ -0,0 +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="textInteractionFlags">
|
||||||
|
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set>
|
||||||
|
</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>
|
520
AppEnv.cpp
Normal file
520
AppEnv.cpp
Normal file
|
@ -0,0 +1,520 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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/>.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#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()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build Stuff
|
||||||
|
|
||||||
|
QString AppEnv::getBuildDateTime()
|
||||||
|
{
|
||||||
|
return GTA5SYNC_BUILDDATETIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString AppEnv::getBuildCode()
|
||||||
|
{
|
||||||
|
return GTA5SYNC_BUILDCODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Folder Stuff
|
||||||
|
|
||||||
|
QString AppEnv::getGameFolder(bool *ok)
|
||||||
|
{
|
||||||
|
QDir dir;
|
||||||
|
QString GTAV_FOLDER = QString::fromUtf8(qgetenv("RDR2_FOLDER"));
|
||||||
|
if (GTAV_FOLDER != "")
|
||||||
|
{
|
||||||
|
dir.setPath(GTAV_FOLDER);
|
||||||
|
if (dir.exists())
|
||||||
|
{
|
||||||
|
if (ok != NULL) *ok = true;
|
||||||
|
qputenv("RDR2_FOLDER", dir.absolutePath().toUtf8());
|
||||||
|
return dir.absolutePath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString GTAV_defaultFolder = StandardPaths::documentsLocation() % QDir::separator() % "Rockstar Games" % QDir::separator() % "Red Dead Redemption 2";
|
||||||
|
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("RDR2_FOLDER", dir.absolutePath().toUtf8());
|
||||||
|
return dir.absolutePath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dir.setPath(GTAV_defaultFolder);
|
||||||
|
if (dir.exists())
|
||||||
|
{
|
||||||
|
if (ok != 0) *ok = true;
|
||||||
|
qputenv("RDR2_FOLDER", dir.absolutePath().toUtf8());
|
||||||
|
return dir.absolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!forceDir)
|
||||||
|
{
|
||||||
|
dir.setPath(GTAV_returnFolder);
|
||||||
|
if (dir.exists())
|
||||||
|
{
|
||||||
|
if (ok != 0) *ok = true;
|
||||||
|
qputenv("RDR2_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("RDR2_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()
|
||||||
|
{
|
||||||
|
#if QT_VERSION >= 0x050400
|
||||||
|
#ifdef GTA5SYNC_WIN
|
||||||
|
QString kernelVersion = QSysInfo::kernelVersion();
|
||||||
|
const QStringList &kernelVersionList = kernelVersion.split(".");
|
||||||
|
if (kernelVersionList.length() > 2)
|
||||||
|
{
|
||||||
|
kernelVersion = kernelVersionList.at(0) % "." % kernelVersionList.at(1);
|
||||||
|
}
|
||||||
|
QString runArch = QSysInfo::buildCpuArchitecture();
|
||||||
|
if (runArch == "x86_64")
|
||||||
|
{
|
||||||
|
runArch = "Win64; x64";
|
||||||
|
}
|
||||||
|
else if (runArch == "i686")
|
||||||
|
{
|
||||||
|
const QString &curArch = QSysInfo::currentCpuArchitecture();
|
||||||
|
if (curArch == "x86_64")
|
||||||
|
{
|
||||||
|
runArch = "WOW64";
|
||||||
|
}
|
||||||
|
else if (curArch == "i686")
|
||||||
|
{
|
||||||
|
runArch = "Win32; x86";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QString("Mozilla/5.0 (Windows NT %1; %2) %3/%4").arg(kernelVersion, runArch, GTA5SYNC_APPSTR, GTA5SYNC_APPVER).toUtf8();
|
||||||
|
#else
|
||||||
|
return QString("Mozilla/5.0 (%1; %2) %3/%4").arg(QSysInfo::kernelType(), QSysInfo::kernelVersion(), GTA5SYNC_APPSTR, GTA5SYNC_APPVER).toUtf8();
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
return QString("Mozilla/5.0 %1/%2").arg(GTA5SYNC_APPSTR, GTA5SYNC_APPVER).toUtf8();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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&pageSize=5000").arg(crewID, pageNumber));
|
||||||
|
}
|
||||||
|
|
||||||
|
QUrl AppEnv::getPlayerFetchingUrl(QString crewID, int pageNumber)
|
||||||
|
{
|
||||||
|
return getPlayerFetchingUrl(crewID, QString::number(pageNumber));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Game Stuff
|
||||||
|
|
||||||
|
GameVersion AppEnv::getGameVersion()
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_WIN
|
||||||
|
QString argumentValue;
|
||||||
|
#ifdef _WIN64
|
||||||
|
argumentValue = "\\WOW6432Node";
|
||||||
|
#endif
|
||||||
|
QSettings registrySettingsSc(QString("HKEY_LOCAL_MACHINE\\SOFTWARE%1\\Rockstar Games\\Red Dead Redemption 2").arg(argumentValue), QSettings::NativeFormat);
|
||||||
|
QString installFolderSc = registrySettingsSc.value("InstallFolder", "").toString();
|
||||||
|
QDir installFolderScDir(installFolderSc);
|
||||||
|
bool scVersionInstalled = false;
|
||||||
|
if (!installFolderSc.isEmpty() && installFolderScDir.exists())
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "gameVersionFoundSocialClubVersion";
|
||||||
|
#endif
|
||||||
|
scVersionInstalled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSettings registrySettingsSteam(QString("HKEY_LOCAL_MACHINE\\SOFTWARE%1\\Rockstar Games\\RDR2").arg(argumentValue), QSettings::NativeFormat);
|
||||||
|
QString installFolderSteam = registrySettingsSteam.value("installfoldersteam", "").toString();
|
||||||
|
if (installFolderSteam.right(5) == "\\GTAV")
|
||||||
|
{
|
||||||
|
installFolderSteam = installFolderSteam.remove(installFolderSteam.length() - 5, 5);
|
||||||
|
}
|
||||||
|
QDir installFolderSteamDir(installFolderSteam);
|
||||||
|
bool steamVersionInstalled = false;
|
||||||
|
if (!installFolderSteam.isEmpty() && installFolderSteamDir.exists())
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "gameVersionFoundSteamVersion";
|
||||||
|
#endif
|
||||||
|
steamVersionInstalled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scVersionInstalled && steamVersionInstalled)
|
||||||
|
{
|
||||||
|
return GameVersion::BothVersions;
|
||||||
|
}
|
||||||
|
else if (scVersionInstalled)
|
||||||
|
{
|
||||||
|
return GameVersion::SocialClubVersion;
|
||||||
|
}
|
||||||
|
else if (steamVersionInstalled)
|
||||||
|
{
|
||||||
|
return GameVersion::SteamVersion;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return GameVersion::NoVersion;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return GameVersion::NoVersion;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
GameLanguage AppEnv::getGameLanguage(GameVersion gameVersion)
|
||||||
|
{
|
||||||
|
if (gameVersion == GameVersion::SocialClubVersion)
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_WIN
|
||||||
|
QString argumentValue;
|
||||||
|
#ifdef _WIN64
|
||||||
|
argumentValue = "\\WOW6432Node";
|
||||||
|
#endif
|
||||||
|
QSettings registrySettingsSc(QString("HKEY_LOCAL_MACHINE\\SOFTWARE%1\\Rockstar Games\\Red Dead Redemption 2").arg(argumentValue), QSettings::NativeFormat);
|
||||||
|
QString languageSc = registrySettingsSc.value("Language", "").toString();
|
||||||
|
return gameLanguageFromString(languageSc);
|
||||||
|
#else
|
||||||
|
return GameLanguage::Undefined;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (gameVersion == GameVersion::SteamVersion)
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_WIN
|
||||||
|
QString argumentValue;
|
||||||
|
#ifdef _WIN64
|
||||||
|
argumentValue = "\\WOW6432Node";
|
||||||
|
#endif
|
||||||
|
QSettings registrySettingsSteam(QString("HKEY_LOCAL_MACHINE\\SOFTWARE%1\\Rockstar Games\\Red Dead Redemption 2 Steam").arg(argumentValue), QSettings::NativeFormat);
|
||||||
|
QString languageSteam = registrySettingsSteam.value("Language", "").toString();
|
||||||
|
return gameLanguageFromString(languageSteam);
|
||||||
|
#else
|
||||||
|
return GameLanguage::Undefined;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return GameLanguage::Undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GameLanguage AppEnv::gameLanguageFromString(QString gameLanguage)
|
||||||
|
{
|
||||||
|
if (gameLanguage == "en-US")
|
||||||
|
{
|
||||||
|
return GameLanguage::English;
|
||||||
|
}
|
||||||
|
else if (gameLanguage == "fr-FR")
|
||||||
|
{
|
||||||
|
return GameLanguage::French;
|
||||||
|
}
|
||||||
|
else if (gameLanguage == "it-IT")
|
||||||
|
{
|
||||||
|
return GameLanguage::Italian;
|
||||||
|
}
|
||||||
|
else if (gameLanguage == "de-DE")
|
||||||
|
{
|
||||||
|
return GameLanguage::German;
|
||||||
|
}
|
||||||
|
else if (gameLanguage == "es-ES")
|
||||||
|
{
|
||||||
|
return GameLanguage::Spanish;
|
||||||
|
}
|
||||||
|
else if (gameLanguage == "es-MX")
|
||||||
|
{
|
||||||
|
return GameLanguage::Mexican;
|
||||||
|
}
|
||||||
|
else if (gameLanguage == "pt-BR")
|
||||||
|
{
|
||||||
|
return GameLanguage::Brasilian;
|
||||||
|
}
|
||||||
|
else if (gameLanguage == "ru-RU")
|
||||||
|
{
|
||||||
|
return GameLanguage::Russian;
|
||||||
|
}
|
||||||
|
else if (gameLanguage == "pl-PL")
|
||||||
|
{
|
||||||
|
return GameLanguage::Polish;
|
||||||
|
}
|
||||||
|
else if (gameLanguage == "ja-JP")
|
||||||
|
{
|
||||||
|
return GameLanguage::Japanese;
|
||||||
|
}
|
||||||
|
else if (gameLanguage == "zh-CHS")
|
||||||
|
{
|
||||||
|
return GameLanguage::SChinese;
|
||||||
|
}
|
||||||
|
else if (gameLanguage == "zh-CHT")
|
||||||
|
{
|
||||||
|
return GameLanguage::TChinese;
|
||||||
|
}
|
||||||
|
else if (gameLanguage == "ko-KR")
|
||||||
|
{
|
||||||
|
return GameLanguage::Koreana;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return GameLanguage::Undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString AppEnv::gameLanguageToString(GameLanguage gameLanguage)
|
||||||
|
{
|
||||||
|
if (gameLanguage == GameLanguage::English)
|
||||||
|
{
|
||||||
|
return "en-US";
|
||||||
|
}
|
||||||
|
else if (gameLanguage == GameLanguage::French)
|
||||||
|
{
|
||||||
|
return "fr-FR";
|
||||||
|
}
|
||||||
|
else if (gameLanguage == GameLanguage::Italian)
|
||||||
|
{
|
||||||
|
return "it-IT";
|
||||||
|
}
|
||||||
|
else if (gameLanguage == GameLanguage::German)
|
||||||
|
{
|
||||||
|
return "de-DE";
|
||||||
|
}
|
||||||
|
else if (gameLanguage == GameLanguage::Spanish)
|
||||||
|
{
|
||||||
|
return "es-ES";
|
||||||
|
}
|
||||||
|
else if (gameLanguage == GameLanguage::Mexican)
|
||||||
|
{
|
||||||
|
return "es-MX";
|
||||||
|
}
|
||||||
|
else if (gameLanguage == GameLanguage::Brasilian)
|
||||||
|
{
|
||||||
|
return "pt-BR";
|
||||||
|
}
|
||||||
|
else if (gameLanguage == GameLanguage::Russian)
|
||||||
|
{
|
||||||
|
return "ru-RU";
|
||||||
|
}
|
||||||
|
else if (gameLanguage == GameLanguage::Polish)
|
||||||
|
{
|
||||||
|
return "pl-PL";
|
||||||
|
}
|
||||||
|
else if (gameLanguage == GameLanguage::Japanese)
|
||||||
|
{
|
||||||
|
return "ja-JP";
|
||||||
|
}
|
||||||
|
else if (gameLanguage == GameLanguage::SChinese)
|
||||||
|
{
|
||||||
|
return "zh-CHS";
|
||||||
|
}
|
||||||
|
else if (gameLanguage == GameLanguage::TChinese)
|
||||||
|
{
|
||||||
|
return "zh-CHT";
|
||||||
|
}
|
||||||
|
else if (gameLanguage == GameLanguage::Koreana)
|
||||||
|
{
|
||||||
|
return "ko-KR";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return "Undefinied";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AppEnv::setGameLanguage(GameVersion gameVersion, GameLanguage gameLanguage)
|
||||||
|
{
|
||||||
|
bool socialClubVersion = false;
|
||||||
|
bool steamVersion = false;
|
||||||
|
if (gameVersion == GameVersion::SocialClubVersion)
|
||||||
|
{
|
||||||
|
socialClubVersion = true;
|
||||||
|
}
|
||||||
|
else if (gameVersion == GameVersion::SteamVersion)
|
||||||
|
{
|
||||||
|
steamVersion = true;
|
||||||
|
}
|
||||||
|
else if (gameVersion == GameVersion::BothVersions)
|
||||||
|
{
|
||||||
|
socialClubVersion = true;
|
||||||
|
steamVersion = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (socialClubVersion)
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_WIN
|
||||||
|
QString argumentValue;
|
||||||
|
#ifdef _WIN64
|
||||||
|
argumentValue = "\\WOW6432Node";
|
||||||
|
#endif
|
||||||
|
QSettings registrySettingsSc(QString("HKEY_LOCAL_MACHINE\\SOFTWARE%1\\Rockstar Games\\Red Dead Redemption 2").arg(argumentValue), QSettings::NativeFormat);
|
||||||
|
if (gameLanguage != GameLanguage::Undefined)
|
||||||
|
{
|
||||||
|
registrySettingsSc.setValue("Language", gameLanguageToString(gameLanguage));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
registrySettingsSc.remove("Language");
|
||||||
|
}
|
||||||
|
registrySettingsSc.sync();
|
||||||
|
if (registrySettingsSc.status() != QSettings::NoError)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
Q_UNUSED(gameLanguage)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (steamVersion)
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_WIN
|
||||||
|
QString argumentValue;
|
||||||
|
#ifdef _WIN64
|
||||||
|
argumentValue = "\\WOW6432Node";
|
||||||
|
#endif
|
||||||
|
QSettings registrySettingsSteam(QString("HKEY_LOCAL_MACHINE\\SOFTWARE%1\\Rockstar Games\\Red Dead Redemption 2 Steam").arg(argumentValue), QSettings::NativeFormat);
|
||||||
|
if (gameLanguage != GameLanguage::Undefined)
|
||||||
|
{
|
||||||
|
registrySettingsSteam.setValue("Language", gameLanguageToString(gameLanguage));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
registrySettingsSteam.remove("Language");
|
||||||
|
}
|
||||||
|
registrySettingsSteam.sync();
|
||||||
|
if (registrySettingsSteam.status() != QSettings::NoError)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
Q_UNUSED(gameLanguage)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Screen Stuff
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal AppEnv::screenRatioPR()
|
||||||
|
{
|
||||||
|
#if QT_VERSION >= 0x050600
|
||||||
|
return QGuiApplication::primaryScreen()->devicePixelRatio();
|
||||||
|
#else
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
}
|
62
AppEnv.h
Normal file
62
AppEnv.h
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 Profile Viewer
|
||||||
|
* Copyright (C) 2016-2018 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>
|
||||||
|
|
||||||
|
enum class GameVersion : int { NoVersion = 0, SocialClubVersion = 1, SteamVersion = 2, BothVersions = 3 };
|
||||||
|
enum class GameLanguage : int { Undefined = 0, English = 1, French = 2, Italian = 3, German = 4, Spanish = 5, Mexican = 6, Brasilian = 7, Russian = 8, Polish = 9, Japanese = 10, SChinese = 11, TChinese = 12, Koreana = 13 };
|
||||||
|
|
||||||
|
class AppEnv
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AppEnv();
|
||||||
|
|
||||||
|
// Build Stuff
|
||||||
|
static QString getBuildDateTime();
|
||||||
|
static QString getBuildCode();
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// Game Stuff
|
||||||
|
static GameVersion getGameVersion();
|
||||||
|
static GameLanguage getGameLanguage(GameVersion gameVersion);
|
||||||
|
static GameLanguage gameLanguageFromString(QString gameLanguage);
|
||||||
|
static QString gameLanguageToString(GameLanguage gameLanguage);
|
||||||
|
static bool setGameLanguage(GameVersion gameVersion, GameLanguage gameLanguage);
|
||||||
|
|
||||||
|
// Screen Stuff
|
||||||
|
static qreal screenRatio();
|
||||||
|
static qreal screenRatioPR();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // APPENV_H
|
176
CrewDatabase.cpp
Normal file
176
CrewDatabase.cpp
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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/>.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#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 % "/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(QString crewID)
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&mutex);
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "getCrewName" << crewID;
|
||||||
|
#endif
|
||||||
|
QString crewStr = crewDB->value(crewID, crewID).toString();
|
||||||
|
if (crewID == "0") crewStr = tr("No Crew", "");
|
||||||
|
return crewStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
54
CrewDatabase.h
Normal file
54
CrewDatabase.h
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 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(QString crewID);
|
||||||
|
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
|
244
DatabaseThread.cpp
Normal file
244
DatabaseThread.cpp
Normal file
|
@ -0,0 +1,244 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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/>.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#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
|
||||||
|
#define maxLoadFails 3
|
||||||
|
|
||||||
|
DatabaseThread::DatabaseThread(CrewDatabase *crewDB, QObject *parent) : QThread(parent), crewDB(crewDB)
|
||||||
|
{
|
||||||
|
continueLastCrew = true;
|
||||||
|
threadRunning = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DatabaseThread::run()
|
||||||
|
{
|
||||||
|
QEventLoop threadLoop;
|
||||||
|
|
||||||
|
QObject::connect(this, SIGNAL(threadTerminated()), &threadLoop, SLOT(quit()));
|
||||||
|
|
||||||
|
while (threadRunning)
|
||||||
|
{
|
||||||
|
if (threadRunning)
|
||||||
|
{
|
||||||
|
QTimer::singleShot(300000, &threadLoop, SLOT(quit()));
|
||||||
|
threadLoop.exec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DatabaseThread::scanCrewReference(const QStringList &crewList, const int &requestDelay)
|
||||||
|
{
|
||||||
|
for (QString crewID : crewList)
|
||||||
|
{
|
||||||
|
if (threadRunning && crewID != QLatin1String("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");
|
||||||
|
netRequest.setRawHeader("Accept-Charset", "utf-8");
|
||||||
|
netRequest.setRawHeader("Accept-Language", "en-US,en;q=0.9");
|
||||||
|
netRequest.setRawHeader("Connection", "keep-alive");
|
||||||
|
|
||||||
|
QNetworkReply *netReply = netManager->get(netRequest);
|
||||||
|
|
||||||
|
QEventLoop *downloadLoop = new QEventLoop();
|
||||||
|
QObject::connect(netReply, SIGNAL(finished()), downloadLoop, SLOT(quit()));
|
||||||
|
if (!continueLastCrew) { QObject::connect(this, SIGNAL(threadTerminated()), downloadLoop, SLOT(quit())); }
|
||||||
|
QTimer::singleShot(30000, downloadLoop, SLOT(quit()));
|
||||||
|
downloadLoop->exec();
|
||||||
|
downloadLoop->disconnect();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
netReply->abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (threadRunning)
|
||||||
|
{
|
||||||
|
QEventLoop *waitingLoop = new QEventLoop();
|
||||||
|
QTimer::singleShot(requestDelay, waitingLoop, SLOT(quit()));
|
||||||
|
if (!continueLastCrew) { QObject::connect(this, SIGNAL(threadTerminated()), waitingLoop, SLOT(quit())); }
|
||||||
|
waitingLoop->exec();
|
||||||
|
waitingLoop->disconnect();
|
||||||
|
delete waitingLoop;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete netReply;
|
||||||
|
delete netManager;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DatabaseThread::scanCrewMembersList(const QStringList &crewList, const int &maxPages, const int &requestDelay)
|
||||||
|
{
|
||||||
|
for (QString crewID : crewList)
|
||||||
|
{
|
||||||
|
if (threadRunning && crewID != QLatin1String("0"))
|
||||||
|
{
|
||||||
|
int currentFail = 0;
|
||||||
|
int currentPage = 0;
|
||||||
|
int foundPlayers = 0;
|
||||||
|
int totalPlayers = 1000;
|
||||||
|
|
||||||
|
while(foundPlayers < totalPlayers && currentPage < maxPages && (continueLastCrew ? true : threadRunning))
|
||||||
|
{
|
||||||
|
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", "application/json");
|
||||||
|
netRequest.setRawHeader("Accept-Charset", "utf-8");
|
||||||
|
netRequest.setRawHeader("Accept-Language", "en-US,en;q=0.9");
|
||||||
|
netRequest.setRawHeader("Connection", "keep-alive");
|
||||||
|
|
||||||
|
QNetworkReply *netReply = netManager->get(netRequest);
|
||||||
|
|
||||||
|
QEventLoop *downloadLoop = new QEventLoop();
|
||||||
|
QObject::connect(netReply, SIGNAL(finished()), downloadLoop, SLOT(quit()));
|
||||||
|
if (!continueLastCrew) { QObject::connect(this, SIGNAL(threadTerminated()), downloadLoop, SLOT(quit())); }
|
||||||
|
QTimer::singleShot(30000, downloadLoop, SLOT(quit()));
|
||||||
|
downloadLoop->exec();
|
||||||
|
downloadLoop->disconnect();
|
||||||
|
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"))
|
||||||
|
{
|
||||||
|
const QList<QVariant> memberList = crewMap["Members"].toList();
|
||||||
|
for (QVariant memberVariant : memberList)
|
||||||
|
{
|
||||||
|
QMap<QString, QVariant> memberMap = memberVariant.toMap();
|
||||||
|
if (memberMap.contains("RockstarId") && memberMap.contains("Name"))
|
||||||
|
{
|
||||||
|
int RockstarId = memberMap["RockstarId"].toInt();
|
||||||
|
QString memberName = memberMap["Name"].toString();
|
||||||
|
if (!memberName.isEmpty() && RockstarId != 0)
|
||||||
|
{
|
||||||
|
foundPlayers++;
|
||||||
|
emit playerNameFound(RockstarId, memberName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPage++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentFail++;
|
||||||
|
if (currentFail == maxLoadFails)
|
||||||
|
{
|
||||||
|
currentFail = 0;
|
||||||
|
currentPage++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete netReply;
|
||||||
|
delete netManager;
|
||||||
|
|
||||||
|
if (foundPlayers < totalPlayers && currentPage < maxPages && (continueLastCrew ? true : threadRunning))
|
||||||
|
{
|
||||||
|
QEventLoop *waitingLoop = new QEventLoop();
|
||||||
|
QTimer::singleShot(requestDelay, waitingLoop, SLOT(quit()));
|
||||||
|
if (!continueLastCrew) { QObject::connect(this, SIGNAL(threadTerminated()), waitingLoop, SLOT(quit())); }
|
||||||
|
waitingLoop->exec();
|
||||||
|
waitingLoop->disconnect();
|
||||||
|
delete waitingLoop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DatabaseThread::deleteCompatibleCrews(QStringList *crewList)
|
||||||
|
{
|
||||||
|
for (QString crewNID : *crewList)
|
||||||
|
{
|
||||||
|
if (crewDB->isCompatibleCrew(crewNID))
|
||||||
|
{
|
||||||
|
crewList->removeAll(crewNID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList DatabaseThread::deleteCompatibleCrews(const QStringList &crewList)
|
||||||
|
{
|
||||||
|
QStringList crewListR = crewList;
|
||||||
|
for (QString crewNID : crewListR)
|
||||||
|
{
|
||||||
|
if (crewDB->isCompatibleCrew(crewNID))
|
||||||
|
{
|
||||||
|
crewListR.removeAll(crewNID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return crewListR;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DatabaseThread::terminateThread()
|
||||||
|
{
|
||||||
|
threadRunning = false;
|
||||||
|
emit threadTerminated();
|
||||||
|
}
|
56
DatabaseThread.h
Normal file
56
DatabaseThread.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 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 terminateThread();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CrewDatabase *crewDB;
|
||||||
|
void scanCrewMembersList(const QStringList &crewList, const int &maxPages, const int &requestDelay);
|
||||||
|
void scanCrewReference(const QStringList &crewList, const int &requestDelay);
|
||||||
|
void deleteCompatibleCrews(QStringList *crewList);
|
||||||
|
QStringList deleteCompatibleCrews(const QStringList &crewList);
|
||||||
|
bool continueLastCrew;
|
||||||
|
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 threadTerminated();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DATABASETHREAD_H
|
48
ExportDialog.cpp
Normal file
48
ExportDialog.cpp
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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/>.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
46
ExportDialog.h
Normal file
46
ExportDialog.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 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
|
226
ExportDialog.ui
Normal file
226
ExportDialog.ui
Normal file
|
@ -0,0 +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>
|
185
ExportThread.cpp
Normal file
185
ExportThread.cpp
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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/>.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#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;
|
||||||
|
for (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) != ".r5e")
|
||||||
|
{
|
||||||
|
exportFileName += ".r5e";
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
56
ExportThread.h
Normal file
56
ExportThread.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 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
|
78
GlobalString.cpp
Normal file
78
GlobalString.cpp
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 Profile Viewer
|
||||||
|
* Copyright (C) 2016-2018 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");
|
||||||
|
for (QString globalStr : globalFile.childKeys())
|
||||||
|
{
|
||||||
|
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 != nullptr) *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()
|
||||||
|
{
|
||||||
|
return Translator->getCurrentAreaLanguage();
|
||||||
|
}
|
35
GlobalString.h
Normal file
35
GlobalString.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 GLOBALSTRING_H
|
||||||
|
#define GLOBALSTRING_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
|
class GlobalString
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GlobalString();
|
||||||
|
static QString getString(QString valueStr, bool *ok = nullptr);
|
||||||
|
static QString getLanguageFile();
|
||||||
|
static QString getLanguage();
|
||||||
|
static QMap<QString, QString> getGlobalMap();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // GLOBALSTRING_H
|
50
IconLoader.cpp
Normal file
50
IconLoader.cpp
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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/>.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
32
IconLoader.h
Normal file
32
IconLoader.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 ICONLOADER_H
|
||||||
|
#define ICONLOADER_H
|
||||||
|
|
||||||
|
#include <QIcon>
|
||||||
|
|
||||||
|
class IconLoader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IconLoader();
|
||||||
|
static QIcon loadingAppIcon();
|
||||||
|
static QIcon loadingPointmakerIcon();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ICONLOADER_H
|
205
ImageEditorDialog.cpp
Normal file
205
ImageEditorDialog.cpp
Normal file
|
@ -0,0 +1,205 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 Profile Viewer
|
||||||
|
* Copyright (C) 2017-2018 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 "ImageEditorDialog.h"
|
||||||
|
#include "ui_ImageEditorDialog.h"
|
||||||
|
#include "ProfileInterface.h"
|
||||||
|
#include "SidebarGenerator.h"
|
||||||
|
#include "StandardPaths.h"
|
||||||
|
#include "ImportDialog.h"
|
||||||
|
#include "AppEnv.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include <QStringBuilder>
|
||||||
|
#include <QImageReader>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
ImageEditorDialog::ImageEditorDialog(SnapmaticPicture *picture, QString profileName, QWidget *parent) :
|
||||||
|
QDialog(parent), smpic(picture), profileName(profileName),
|
||||||
|
ui(new Ui::ImageEditorDialog)
|
||||||
|
{
|
||||||
|
// Set Window Flags
|
||||||
|
setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint);
|
||||||
|
|
||||||
|
ui->setupUi(this);
|
||||||
|
ui->cmdClose->setDefault(true);
|
||||||
|
ui->cmdClose->setFocus();
|
||||||
|
|
||||||
|
// Set Icon for Close Button
|
||||||
|
if (QIcon::hasThemeIcon("dialog-close"))
|
||||||
|
{
|
||||||
|
ui->cmdClose->setIcon(QIcon::fromTheme("dialog-close"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("gtk-close"))
|
||||||
|
{
|
||||||
|
ui->cmdClose->setIcon(QIcon::fromTheme("gtk-close"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Icon for Import Button
|
||||||
|
if (QIcon::hasThemeIcon("document-import"))
|
||||||
|
{
|
||||||
|
ui->cmdReplace->setIcon(QIcon::fromTheme("document-import"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Icon for Overwrite Button
|
||||||
|
if (QIcon::hasThemeIcon("document-save"))
|
||||||
|
{
|
||||||
|
ui->cmdSave->setIcon(QIcon::fromTheme("document-save"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("gtk-save"))
|
||||||
|
{
|
||||||
|
ui->cmdSave->setIcon(QIcon::fromTheme("gtk-save"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// DPI calculation
|
||||||
|
qreal screenRatio = AppEnv::screenRatio();
|
||||||
|
|
||||||
|
snapmaticResolutionLW = 516 * screenRatio; // 430
|
||||||
|
snapmaticResolutionLH = 288 * screenRatio; // 240
|
||||||
|
ui->labPicture->setMinimumSize(snapmaticResolutionLW, snapmaticResolutionLH);
|
||||||
|
|
||||||
|
imageIsChanged = false;
|
||||||
|
pictureCache = picture->getImage();
|
||||||
|
ui->labPicture->setPixmap(QPixmap::fromImage(pictureCache).scaled(snapmaticResolutionLW, snapmaticResolutionLH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
||||||
|
|
||||||
|
setMaximumSize(sizeHint());
|
||||||
|
setMinimumSize(sizeHint());
|
||||||
|
setFixedSize(sizeHint());
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageEditorDialog::~ImageEditorDialog()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageEditorDialog::on_cmdClose_clicked()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageEditorDialog::on_cmdReplace_clicked()
|
||||||
|
{
|
||||||
|
QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||||
|
settings.beginGroup("FileDialogs");
|
||||||
|
bool dontUseNativeDialog = settings.value("DontUseNativeDialog", false).toBool();
|
||||||
|
settings.beginGroup("ImportReplace");
|
||||||
|
|
||||||
|
fileDialogPreOpen: //Work?
|
||||||
|
QFileDialog fileDialog(this);
|
||||||
|
fileDialog.setFileMode(QFileDialog::ExistingFile);
|
||||||
|
fileDialog.setViewMode(QFileDialog::Detail);
|
||||||
|
fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
|
||||||
|
fileDialog.setOption(QFileDialog::DontUseNativeDialog, dontUseNativeDialog);
|
||||||
|
fileDialog.setWindowFlags(fileDialog.windowFlags()^Qt::WindowContextHelpButtonHint);
|
||||||
|
fileDialog.setWindowTitle(ProfileInterface::tr("Import..."));
|
||||||
|
fileDialog.setLabelText(QFileDialog::Accept, ProfileInterface::tr("Import"));
|
||||||
|
|
||||||
|
// Getting readable Image formats
|
||||||
|
QString imageFormatsStr = " ";
|
||||||
|
for (QByteArray imageFormat : QImageReader::supportedImageFormats())
|
||||||
|
{
|
||||||
|
imageFormatsStr += QString("*.") % QString::fromUtf8(imageFormat).toLower() % " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList filters;
|
||||||
|
filters << ProfileInterface::tr("All image files (%1)").arg(imageFormatsStr.trimmed());
|
||||||
|
filters << ProfileInterface::tr("All files (**)");
|
||||||
|
fileDialog.setNameFilters(filters);
|
||||||
|
|
||||||
|
QList<QUrl> sidebarUrls = SidebarGenerator::generateSidebarUrls(fileDialog.sidebarUrls());
|
||||||
|
|
||||||
|
fileDialog.setSidebarUrls(sidebarUrls);
|
||||||
|
fileDialog.setDirectory(settings.value(profileName % "+Directory", StandardPaths::documentsLocation()).toString());
|
||||||
|
fileDialog.restoreGeometry(settings.value(profileName % "+Geometry", "").toByteArray());
|
||||||
|
|
||||||
|
if (fileDialog.exec())
|
||||||
|
{
|
||||||
|
QStringList selectedFiles = fileDialog.selectedFiles();
|
||||||
|
if (selectedFiles.length() == 1)
|
||||||
|
{
|
||||||
|
QString selectedFile = selectedFiles.at(0);
|
||||||
|
QString selectedFileName = QFileInfo(selectedFile).fileName();
|
||||||
|
|
||||||
|
QFile snapmaticFile(selectedFile);
|
||||||
|
if (!snapmaticFile.open(QFile::ReadOnly))
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, ProfileInterface::tr("Import"), ProfileInterface::tr("Can't import %1 because file can't be open").arg("\""+selectedFileName+"\""));
|
||||||
|
goto fileDialogPreOpen;
|
||||||
|
}
|
||||||
|
QImage *importImage = new QImage();
|
||||||
|
QImageReader snapmaticImageReader;
|
||||||
|
snapmaticImageReader.setDecideFormatFromContent(true);
|
||||||
|
snapmaticImageReader.setDevice(&snapmaticFile);
|
||||||
|
if (!snapmaticImageReader.read(importImage))
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, ProfileInterface::tr("Import"), ProfileInterface::tr("Can't import %1 because file can't be parsed properly").arg("\""+selectedFileName+"\""));
|
||||||
|
delete importImage;
|
||||||
|
goto fileDialogPreOpen;
|
||||||
|
}
|
||||||
|
ImportDialog *importDialog = new ImportDialog(profileName, this);
|
||||||
|
importDialog->setImage(importImage);
|
||||||
|
importDialog->setModal(true);
|
||||||
|
importDialog->show();
|
||||||
|
importDialog->exec();
|
||||||
|
if (importDialog->isImportAgreed())
|
||||||
|
{
|
||||||
|
pictureCache = importDialog->image();
|
||||||
|
ui->labPicture->setPixmap(QPixmap::fromImage(pictureCache).scaled(snapmaticResolutionLW, snapmaticResolutionLH, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||||
|
imageIsChanged = true;
|
||||||
|
}
|
||||||
|
delete importDialog;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.setValue(profileName % "+Geometry", fileDialog.saveGeometry());
|
||||||
|
settings.setValue(profileName % "+Directory", fileDialog.directory().absolutePath());
|
||||||
|
settings.endGroup();
|
||||||
|
settings.endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageEditorDialog::on_cmdSave_clicked()
|
||||||
|
{
|
||||||
|
if (imageIsChanged)
|
||||||
|
{
|
||||||
|
const QByteArray previousPicture = smpic->getPictureStream();
|
||||||
|
bool success = smpic->setImage(pictureCache);
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
QString currentFilePath = smpic->getPictureFilePath();
|
||||||
|
QString originalFilePath = smpic->getOriginalPictureFilePath();
|
||||||
|
QString backupFileName = originalFilePath % ".bak";
|
||||||
|
if (!QFile::exists(backupFileName))
|
||||||
|
{
|
||||||
|
QFile::copy(currentFilePath, backupFileName);
|
||||||
|
}
|
||||||
|
if (!smpic->exportPicture(currentFilePath))
|
||||||
|
{
|
||||||
|
smpic->setPictureStream(previousPicture);
|
||||||
|
QMessageBox::warning(this, tr("Snapmatic Image Editor"), tr("Patching of Snapmatic Image failed because of I/O Error"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
smpic->emitCustomSignal("PictureUpdated");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Snapmatic Image Editor"), tr("Patching of Snapmatic Image failed because of Image Error"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close();
|
||||||
|
}
|
52
ImageEditorDialog.h
Normal file
52
ImageEditorDialog.h
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 IMAGEEDITORDIALOG_H
|
||||||
|
#define IMAGEEDITORDIALOG_H
|
||||||
|
|
||||||
|
#include "SnapmaticPicture.h"
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class ImageEditorDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ImageEditorDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ImageEditorDialog(SnapmaticPicture *picture, QString profileName, QWidget *parent = 0);
|
||||||
|
~ImageEditorDialog();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_cmdClose_clicked();
|
||||||
|
void on_cmdReplace_clicked();
|
||||||
|
void on_cmdSave_clicked();
|
||||||
|
|
||||||
|
private:
|
||||||
|
SnapmaticPicture *smpic;
|
||||||
|
QString profileName;
|
||||||
|
Ui::ImageEditorDialog *ui;
|
||||||
|
int snapmaticResolutionLW;
|
||||||
|
int snapmaticResolutionLH;
|
||||||
|
bool imageIsChanged;
|
||||||
|
QImage pictureCache;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // IMAGEEDITORDIALOG_H
|
108
ImageEditorDialog.ui
Normal file
108
ImageEditorDialog.ui
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>ImageEditorDialog</class>
|
||||||
|
<widget class="QDialog" name="ImageEditorDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>516</width>
|
||||||
|
<height>337</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Overwrite Image...</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="vlInterface">
|
||||||
|
<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="QLabel" name="labPicture">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>516</width>
|
||||||
|
<height>288</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="buttomFrame">
|
||||||
|
<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="vlButtons">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="hlButtons">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="cmdReplace">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Import picture</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Import...</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="cmdSave">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Apply changes</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Overwrite</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="cmdClose">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Discard changes</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Close</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
838
ImportDialog.cpp
Normal file
838
ImportDialog.cpp
Normal file
|
@ -0,0 +1,838 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 Profile Viewer
|
||||||
|
* Copyright (C) 2017-2019 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 "SidebarGenerator.h"
|
||||||
|
#include "StandardPaths.h"
|
||||||
|
#include "imagecropper.h"
|
||||||
|
#include "AppEnv.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include <QStringBuilder>
|
||||||
|
#include <QInputDialog>
|
||||||
|
#include <QImageReader>
|
||||||
|
#include <QColorDialog>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QImage>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QStyle>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QRgb>
|
||||||
|
|
||||||
|
// IMAGES VALUES
|
||||||
|
#define snapmaticResolutionW 960
|
||||||
|
#define snapmaticResolutionH 536
|
||||||
|
#define snapmaticAvatarResolution 470
|
||||||
|
#define snapmaticAvatarPlacementW 145
|
||||||
|
#define snapmaticAvatarPlacementH 66
|
||||||
|
|
||||||
|
ImportDialog::ImportDialog(QString profileName, QWidget *parent) :
|
||||||
|
QDialog(parent), profileName(profileName),
|
||||||
|
ui(new Ui::ImportDialog)
|
||||||
|
{
|
||||||
|
// Set Window Flags
|
||||||
|
setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint);
|
||||||
|
|
||||||
|
ui->setupUi(this);
|
||||||
|
ui->cmdOK->setDefault(true);
|
||||||
|
ui->cmdOK->setFocus();
|
||||||
|
importAgreed = false;
|
||||||
|
settingsLocked = false;
|
||||||
|
watermarkAvatar = true;
|
||||||
|
watermarkPicture = false;
|
||||||
|
insideAvatarZone = false;
|
||||||
|
avatarAreaImage = QImage(":/img/avatarareaimport.png");
|
||||||
|
selectedColour = QColor::fromRgb(0, 0, 0, 255);
|
||||||
|
|
||||||
|
// Set Icon for OK Button
|
||||||
|
if (QIcon::hasThemeIcon("dialog-ok"))
|
||||||
|
{
|
||||||
|
ui->cmdOK->setIcon(QIcon::fromTheme("dialog-ok"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("gtk-ok"))
|
||||||
|
{
|
||||||
|
ui->cmdOK->setIcon(QIcon::fromTheme("gtk-ok"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Icon for Cancel Button
|
||||||
|
if (QIcon::hasThemeIcon("dialog-cancel"))
|
||||||
|
{
|
||||||
|
ui->cmdCancel->setIcon(QIcon::fromTheme("dialog-cancel"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("gtk-cancel"))
|
||||||
|
{
|
||||||
|
ui->cmdCancel->setIcon(QIcon::fromTheme("gtk-cancel"));
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->cbIgnore->setChecked(false);
|
||||||
|
ui->labColour->setText(tr("Background Colour: <span style=\"color: %1\">%1</span>").arg(selectedColour.name()));
|
||||||
|
ui->labBackgroundImage->setText(tr("Background Image:"));
|
||||||
|
ui->cmdBackgroundWipe->setVisible(false);
|
||||||
|
|
||||||
|
// Set Import Settings
|
||||||
|
QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||||
|
settings.beginGroup("Import");
|
||||||
|
QString currentProfile = settings.value("Profile", "Default").toString();
|
||||||
|
settings.endGroup();
|
||||||
|
processSettings(currentProfile);
|
||||||
|
|
||||||
|
// DPI calculation
|
||||||
|
qreal screenRatio = AppEnv::screenRatio();
|
||||||
|
snapmaticResolutionLW = 516 * screenRatio; // 430
|
||||||
|
snapmaticResolutionLH = 288 * screenRatio; // 240
|
||||||
|
ui->labPicture->setMinimumSize(snapmaticResolutionLW, snapmaticResolutionLH);
|
||||||
|
|
||||||
|
ui->vlButtom->setSpacing(6 * screenRatio);
|
||||||
|
#ifndef Q_OS_MAC
|
||||||
|
ui->vlButtom->setContentsMargins(9 * screenRatio, 6 * screenRatio, 9 * screenRatio, 9 * screenRatio);
|
||||||
|
#else
|
||||||
|
if (QApplication::style()->objectName() == "macintosh")
|
||||||
|
{
|
||||||
|
ui->vlButtom->setContentsMargins(9 * screenRatio, 9 * screenRatio, 9 * screenRatio, 9 * screenRatio);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->vlButtom->setContentsMargins(9 * screenRatio, 6 * screenRatio, 9 * screenRatio, 9 * screenRatio);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Options menu
|
||||||
|
optionsMenu = new QMenu(this);
|
||||||
|
optionsMenu->addAction(tr("&Import new Picture..."), this, SLOT(importNewPicture()));
|
||||||
|
optionsMenu->addAction(tr("&Crop Picture..."), this, SLOT(cropPicture()));
|
||||||
|
optionsMenu->addSeparator();
|
||||||
|
optionsMenu->addAction(tr("&Load Settings..."), this, SLOT(loadImportSettings()));
|
||||||
|
optionsMenu->addAction(tr("&Save Settings..."), this, SLOT(saveImportSettings()));
|
||||||
|
ui->cmdOptions->setMenu(optionsMenu);
|
||||||
|
|
||||||
|
setMaximumSize(sizeHint());
|
||||||
|
setMinimumSize(sizeHint());
|
||||||
|
setFixedSize(sizeHint());
|
||||||
|
}
|
||||||
|
|
||||||
|
ImportDialog::~ImportDialog()
|
||||||
|
{
|
||||||
|
delete optionsMenu;
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportDialog::processImage()
|
||||||
|
{
|
||||||
|
if (workImage.isNull()) return;
|
||||||
|
QImage snapmaticImage = workImage;
|
||||||
|
QPixmap snapmaticPixmap(snapmaticResolutionW, snapmaticResolutionH);
|
||||||
|
snapmaticPixmap.fill(selectedColour);
|
||||||
|
QPainter snapmaticPainter(&snapmaticPixmap);
|
||||||
|
qreal screenRatioPR = AppEnv::screenRatioPR();
|
||||||
|
if (!backImage.isNull())
|
||||||
|
{
|
||||||
|
if (!ui->cbStretch->isChecked())
|
||||||
|
{
|
||||||
|
int diffWidth = 0;
|
||||||
|
int diffHeight = 0;
|
||||||
|
if (backImage.width() != snapmaticResolutionW)
|
||||||
|
{
|
||||||
|
diffWidth = snapmaticResolutionW - backImage.width();
|
||||||
|
diffWidth = diffWidth / 2;
|
||||||
|
}
|
||||||
|
else if (backImage.height() != snapmaticResolutionH)
|
||||||
|
{
|
||||||
|
diffHeight = snapmaticResolutionH - backImage.height();
|
||||||
|
diffHeight = diffHeight / 2;
|
||||||
|
}
|
||||||
|
snapmaticPainter.drawImage(0 + diffWidth, 0 + diffHeight, backImage);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
snapmaticPainter.drawImage(0, 0, QImage(backImage).scaled(snapmaticResolutionW, snapmaticResolutionH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
||||||
|
}
|
||||||
|
if (ui->cbAvatar->isChecked() && ui->cbForceAvatarColour->isChecked())
|
||||||
|
{
|
||||||
|
snapmaticPainter.fillRect(snapmaticAvatarPlacementW, snapmaticAvatarPlacementH, snapmaticAvatarResolution, snapmaticAvatarResolution, selectedColour);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
if (ui->cbWatermark->isChecked()) { processWatermark(&snapmaticPainter); }
|
||||||
|
imageTitle = tr("Custom Avatar", "Custom Avatar Description in SC, don't use Special Character!");
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
if (ui->cbWatermark->isChecked()) { processWatermark(&snapmaticPainter); }
|
||||||
|
imageTitle = tr("Custom Picture", "Custom Picture Description in SC, don't use Special Character!");
|
||||||
|
}
|
||||||
|
snapmaticPainter.end();
|
||||||
|
newImage = snapmaticPixmap.toImage();
|
||||||
|
#if QT_VERSION >= 0x050600
|
||||||
|
snapmaticPixmap.setDevicePixelRatio(screenRatioPR);
|
||||||
|
#endif
|
||||||
|
ui->labPicture->setPixmap(snapmaticPixmap.scaled(snapmaticResolutionLW * screenRatioPR, snapmaticResolutionLH * screenRatioPR, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportDialog::processWatermark(QPainter *snapmaticPainter)
|
||||||
|
{
|
||||||
|
bool blackWatermark = false;
|
||||||
|
bool redWatermark = false;
|
||||||
|
if (selectedColour.red() > 127)
|
||||||
|
{
|
||||||
|
if (selectedColour.green() > 127 || selectedColour.blue() > 127)
|
||||||
|
{
|
||||||
|
redWatermark = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
redWatermark = true;
|
||||||
|
}
|
||||||
|
if (selectedColour.lightness() > 127)
|
||||||
|
{
|
||||||
|
blackWatermark = true;
|
||||||
|
}
|
||||||
|
// draw watermark
|
||||||
|
if (redWatermark)
|
||||||
|
{
|
||||||
|
snapmaticPainter->drawImage(0, 0, QImage(":/img/watermark_2r.png"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QImage viewWatermark = QImage(":/img/watermark_2b.png");
|
||||||
|
if (!blackWatermark)
|
||||||
|
{
|
||||||
|
viewWatermark.invertPixels(QImage::InvertRgb);
|
||||||
|
}
|
||||||
|
snapmaticPainter->drawImage(0, 0, viewWatermark);
|
||||||
|
}
|
||||||
|
QImage textWatermark = QImage(":/img/watermark_1b.png");
|
||||||
|
if (!blackWatermark)
|
||||||
|
{
|
||||||
|
textWatermark.invertPixels(QImage::InvertRgb);
|
||||||
|
}
|
||||||
|
snapmaticPainter->drawImage(0, 0, textWatermark);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportDialog::processSettings(QString settingsProfile, bool setDefault)
|
||||||
|
{
|
||||||
|
QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||||
|
settings.beginGroup("Import");
|
||||||
|
if (setDefault)
|
||||||
|
{
|
||||||
|
settings.setValue("Profile", settingsProfile);
|
||||||
|
}
|
||||||
|
if (settingsProfile == "Default")
|
||||||
|
{
|
||||||
|
watermarkAvatar = true;
|
||||||
|
watermarkPicture = false;
|
||||||
|
selectedColour = QColor::fromRgb(0, 0, 0, 255);
|
||||||
|
backImage = QImage();
|
||||||
|
ui->cbStretch->setChecked(false);
|
||||||
|
ui->cbForceAvatarColour->setChecked(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
settings.beginGroup(settingsProfile);
|
||||||
|
watermarkAvatar = settings.value("WatermarkAvatar", true).toBool();
|
||||||
|
watermarkPicture = settings.value("WatermarkPicture", false).toBool();
|
||||||
|
backImage = qvariant_cast<QImage>(settings.value("BackgroundImage", QImage()));
|
||||||
|
selectedColour = qvariant_cast<QColor>(settings.value("SelectedColour", QColor::fromRgb(0, 0, 0, 255)));
|
||||||
|
ui->cbStretch->setChecked(settings.value("BackgroundStretch", false).toBool());
|
||||||
|
ui->cbForceAvatarColour->setChecked(settings.value("ForceAvatarColour", false).toBool());
|
||||||
|
settings.endGroup();
|
||||||
|
}
|
||||||
|
if (!workImage.isNull())
|
||||||
|
{
|
||||||
|
if (ui->cbAvatar->isChecked())
|
||||||
|
{
|
||||||
|
ui->cbWatermark->setChecked(watermarkAvatar);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->cbWatermark->setChecked(watermarkPicture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ui->labColour->setText(tr("Background Colour: <span style=\"color: %1\">%1</span>").arg(selectedColour.name()));
|
||||||
|
if (!backImage.isNull())
|
||||||
|
{
|
||||||
|
ui->labBackgroundImage->setText(tr("Background Image: %1").arg(tr("Storage", "Background Image: Storage")));
|
||||||
|
ui->cmdBackgroundWipe->setVisible(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->labBackgroundImage->setText(tr("Background Image:"));
|
||||||
|
ui->cmdBackgroundWipe->setVisible(false);
|
||||||
|
}
|
||||||
|
settings.endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportDialog::saveSettings(QString settingsProfile)
|
||||||
|
{
|
||||||
|
QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||||
|
settings.beginGroup("Import");
|
||||||
|
settings.beginGroup(settingsProfile);
|
||||||
|
settings.setValue("WatermarkAvatar", watermarkAvatar);
|
||||||
|
settings.setValue("WatermarkPicture", watermarkPicture);
|
||||||
|
settings.setValue("BackgroundImage", backImage);
|
||||||
|
settings.setValue("SelectedColour", selectedColour);
|
||||||
|
settings.setValue("BackgroundStretch", ui->cbStretch->isChecked());
|
||||||
|
settings.setValue("ForceAvatarColour", ui->cbForceAvatarColour->isChecked());
|
||||||
|
settings.endGroup();
|
||||||
|
settings.setValue("Profile", settingsProfile);
|
||||||
|
settings.endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportDialog::cropPicture()
|
||||||
|
{
|
||||||
|
qreal screenRatio = AppEnv::screenRatio();
|
||||||
|
|
||||||
|
QDialog cropDialog(this);
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
cropDialog.setObjectName(QStringLiteral("CropDialog"));
|
||||||
|
#else
|
||||||
|
cropDialog.setObjectName(QString::fromUtf8("CropDialog"));
|
||||||
|
#endif
|
||||||
|
cropDialog.setWindowTitle(tr("Crop Picture..."));
|
||||||
|
cropDialog.setWindowFlags(cropDialog.windowFlags()^Qt::WindowContextHelpButtonHint);
|
||||||
|
cropDialog.setModal(true);
|
||||||
|
|
||||||
|
QVBoxLayout cropLayout;
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
cropLayout.setObjectName(QStringLiteral("CropLayout"));
|
||||||
|
#else
|
||||||
|
cropLayout.setObjectName(QString::fromUtf8("CropLayout"));
|
||||||
|
#endif
|
||||||
|
cropLayout.setContentsMargins(0, 0, 0, 0);
|
||||||
|
cropLayout.setSpacing(0);
|
||||||
|
cropDialog.setLayout(&cropLayout);
|
||||||
|
|
||||||
|
ImageCropper imageCropper(&cropDialog);
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
imageCropper.setObjectName(QStringLiteral("ImageCropper"));
|
||||||
|
#else
|
||||||
|
imageCropper.setObjectName(QString::fromUtf8("ImageCropper"));
|
||||||
|
#endif
|
||||||
|
imageCropper.setBackgroundColor(Qt::black);
|
||||||
|
imageCropper.setCroppingRectBorderColor(QColor(255, 255, 255, 127));
|
||||||
|
imageCropper.setImage(QPixmap::fromImage(workImage, Qt::AutoColor));
|
||||||
|
imageCropper.setProportion(QSize(1, 1));
|
||||||
|
imageCropper.setFixedSize(workImage.size());
|
||||||
|
cropLayout.addWidget(&imageCropper);
|
||||||
|
|
||||||
|
QHBoxLayout buttonLayout;
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
cropLayout.setObjectName(QStringLiteral("ButtonLayout"));
|
||||||
|
#else
|
||||||
|
cropLayout.setObjectName(QString::fromUtf8("ButtonLayout"));
|
||||||
|
#endif
|
||||||
|
cropLayout.addLayout(&buttonLayout);
|
||||||
|
|
||||||
|
QPushButton cropButton(&cropDialog);
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
cropButton.setObjectName(QStringLiteral("CropButton"));
|
||||||
|
#else
|
||||||
|
cropButton.setObjectName(QString::fromUtf8("CropButton"));
|
||||||
|
#endif
|
||||||
|
cropButton.setMinimumSize(0, 40 * screenRatio);
|
||||||
|
cropButton.setText(tr("&Crop"));
|
||||||
|
cropButton.setToolTip(tr("Crop Picture"));
|
||||||
|
QObject::connect(&cropButton, SIGNAL(clicked(bool)), &cropDialog, SLOT(accept()));
|
||||||
|
|
||||||
|
buttonLayout.addWidget(&cropButton);
|
||||||
|
|
||||||
|
cropDialog.show();
|
||||||
|
cropDialog.setFixedSize(cropDialog.sizeHint());
|
||||||
|
if (cropDialog.exec() == QDialog::Accepted)
|
||||||
|
{
|
||||||
|
QImage *croppedImage = new QImage(imageCropper.cropImage().toImage());
|
||||||
|
setImage(croppedImage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportDialog::importNewPicture()
|
||||||
|
{
|
||||||
|
QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||||
|
settings.beginGroup("FileDialogs");
|
||||||
|
bool dontUseNativeDialog = settings.value("DontUseNativeDialog", false).toBool();
|
||||||
|
settings.beginGroup("ImportCopy");
|
||||||
|
|
||||||
|
fileDialogPreOpen: //Work?
|
||||||
|
QFileDialog fileDialog(this);
|
||||||
|
fileDialog.setFileMode(QFileDialog::ExistingFile);
|
||||||
|
fileDialog.setViewMode(QFileDialog::Detail);
|
||||||
|
fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
|
||||||
|
fileDialog.setOption(QFileDialog::DontUseNativeDialog, dontUseNativeDialog);
|
||||||
|
fileDialog.setWindowFlags(fileDialog.windowFlags()^Qt::WindowContextHelpButtonHint);
|
||||||
|
fileDialog.setWindowTitle(QApplication::translate("ProfileInterface", "Import..."));
|
||||||
|
fileDialog.setLabelText(QFileDialog::Accept, QApplication::translate("ProfileInterface", "Import"));
|
||||||
|
|
||||||
|
// Getting readable Image formats
|
||||||
|
QString imageFormatsStr = " ";
|
||||||
|
for (QByteArray imageFormat : QImageReader::supportedImageFormats())
|
||||||
|
{
|
||||||
|
imageFormatsStr += QString("*.") % QString::fromUtf8(imageFormat).toLower() % " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList filters;
|
||||||
|
filters << QApplication::translate("ProfileInterface", "All image files (%1)").arg(imageFormatsStr.trimmed());
|
||||||
|
filters << QApplication::translate("ProfileInterface", "All files (**)");
|
||||||
|
fileDialog.setNameFilters(filters);
|
||||||
|
|
||||||
|
QList<QUrl> sidebarUrls = SidebarGenerator::generateSidebarUrls(fileDialog.sidebarUrls());
|
||||||
|
|
||||||
|
fileDialog.setSidebarUrls(sidebarUrls);
|
||||||
|
fileDialog.setDirectory(settings.value(profileName % "+Directory", StandardPaths::documentsLocation()).toString());
|
||||||
|
fileDialog.restoreGeometry(settings.value(profileName % "+Geometry", "").toByteArray());
|
||||||
|
|
||||||
|
if (fileDialog.exec())
|
||||||
|
{
|
||||||
|
QStringList selectedFiles = fileDialog.selectedFiles();
|
||||||
|
if (selectedFiles.length() == 1)
|
||||||
|
{
|
||||||
|
QString selectedFile = selectedFiles.at(0);
|
||||||
|
QString selectedFileName = QFileInfo(selectedFile).fileName();
|
||||||
|
|
||||||
|
QFile snapmaticFile(selectedFile);
|
||||||
|
if (!snapmaticFile.open(QFile::ReadOnly))
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, QApplication::translate("ProfileInterface", "Import"), QApplication::translate("ProfileInterface", "Can't import %1 because file can't be open").arg("\""+selectedFileName+"\""));
|
||||||
|
goto fileDialogPreOpen;
|
||||||
|
}
|
||||||
|
QImage *importImage = new QImage();
|
||||||
|
QImageReader snapmaticImageReader;
|
||||||
|
snapmaticImageReader.setDecideFormatFromContent(true);
|
||||||
|
snapmaticImageReader.setDevice(&snapmaticFile);
|
||||||
|
if (!snapmaticImageReader.read(importImage))
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, QApplication::translate("ProfileInterface", "Import"), QApplication::translate("ProfileInterface", "Can't import %1 because file can't be parsed properly").arg("\""+selectedFileName+"\""));
|
||||||
|
delete importImage;
|
||||||
|
goto fileDialogPreOpen;
|
||||||
|
}
|
||||||
|
setImage(importImage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.setValue(profileName % "+Geometry", fileDialog.saveGeometry());
|
||||||
|
settings.setValue(profileName % "+Directory", fileDialog.directory().absolutePath());
|
||||||
|
settings.endGroup();
|
||||||
|
settings.endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportDialog::loadImportSettings()
|
||||||
|
{
|
||||||
|
if (settingsLocked)
|
||||||
|
{
|
||||||
|
QMessageBox::information(this, tr("Load Settings..."), tr("Please import a new picture first"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool ok;
|
||||||
|
QStringList profileList;
|
||||||
|
profileList << tr("Default", "Default as Default Profile")
|
||||||
|
<< tr("Profile %1", "Profile %1 as Profile 1").arg("1")
|
||||||
|
<< tr("Profile %1", "Profile %1 as Profile 1").arg("2")
|
||||||
|
<< tr("Profile %1", "Profile %1 as Profile 1").arg("3")
|
||||||
|
<< tr("Profile %1", "Profile %1 as Profile 1").arg("4")
|
||||||
|
<< tr("Profile %1", "Profile %1 as Profile 1").arg("5");
|
||||||
|
QString sProfile = QInputDialog::getItem(this, tr("Load Settings..."), tr("Please select your settings profile"), profileList, 0, false, &ok, windowFlags());
|
||||||
|
if (ok)
|
||||||
|
{
|
||||||
|
QString pProfile;
|
||||||
|
if (sProfile == tr("Default", "Default as Default Profile"))
|
||||||
|
{
|
||||||
|
pProfile = "Default";
|
||||||
|
}
|
||||||
|
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("1"))
|
||||||
|
{
|
||||||
|
pProfile = "Profile 1";
|
||||||
|
}
|
||||||
|
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("2"))
|
||||||
|
{
|
||||||
|
pProfile = "Profile 2";
|
||||||
|
}
|
||||||
|
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("3"))
|
||||||
|
{
|
||||||
|
pProfile = "Profile 3";
|
||||||
|
}
|
||||||
|
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("4"))
|
||||||
|
{
|
||||||
|
pProfile = "Profile 4";
|
||||||
|
}
|
||||||
|
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("5"))
|
||||||
|
{
|
||||||
|
pProfile = "Profile 5";
|
||||||
|
}
|
||||||
|
processSettings(pProfile, true);
|
||||||
|
processImage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportDialog::saveImportSettings()
|
||||||
|
{
|
||||||
|
if (settingsLocked)
|
||||||
|
{
|
||||||
|
QMessageBox::information(this, tr("Save Settings..."), tr("Please import a new picture first"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool ok;
|
||||||
|
QStringList profileList;
|
||||||
|
profileList << tr("Profile %1", "Profile %1 as Profile 1").arg("1")
|
||||||
|
<< tr("Profile %1", "Profile %1 as Profile 1").arg("2")
|
||||||
|
<< tr("Profile %1", "Profile %1 as Profile 1").arg("3")
|
||||||
|
<< tr("Profile %1", "Profile %1 as Profile 1").arg("4")
|
||||||
|
<< tr("Profile %1", "Profile %1 as Profile 1").arg("5");
|
||||||
|
QString sProfile = QInputDialog::getItem(this, tr("Save Settings..."), tr("Please select your settings profile"), profileList, 0, false, &ok, windowFlags());
|
||||||
|
if (ok)
|
||||||
|
{
|
||||||
|
QString pProfile;
|
||||||
|
if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("1"))
|
||||||
|
{
|
||||||
|
pProfile = "Profile 1";
|
||||||
|
}
|
||||||
|
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("2"))
|
||||||
|
{
|
||||||
|
pProfile = "Profile 2";
|
||||||
|
}
|
||||||
|
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("3"))
|
||||||
|
{
|
||||||
|
pProfile = "Profile 3";
|
||||||
|
}
|
||||||
|
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("4"))
|
||||||
|
{
|
||||||
|
pProfile = "Profile 4";
|
||||||
|
}
|
||||||
|
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("5"))
|
||||||
|
{
|
||||||
|
pProfile = "Profile 5";
|
||||||
|
}
|
||||||
|
saveSettings(pProfile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage ImportDialog::image()
|
||||||
|
{
|
||||||
|
return newImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportDialog::setImage(QImage *image_)
|
||||||
|
{
|
||||||
|
workImage = QImage();
|
||||||
|
if (image_->width() == image_->height())
|
||||||
|
{
|
||||||
|
insideAvatarZone = true;
|
||||||
|
ui->cbAvatar->setChecked(true);
|
||||||
|
if (image_->height() > snapmaticResolutionH)
|
||||||
|
{
|
||||||
|
workImage = image_->scaled(snapmaticResolutionH, snapmaticResolutionH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||||
|
delete image_;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
workImage = *image_;
|
||||||
|
delete image_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (image_->width() > snapmaticResolutionW && image_->width() > image_->height())
|
||||||
|
{
|
||||||
|
insideAvatarZone = false;
|
||||||
|
ui->cbAvatar->setChecked(false);
|
||||||
|
workImage = image_->scaledToWidth(snapmaticResolutionW, Qt::SmoothTransformation);
|
||||||
|
delete image_;
|
||||||
|
}
|
||||||
|
else if (image_->height() > snapmaticResolutionH && image_->height() > image_->width())
|
||||||
|
{
|
||||||
|
insideAvatarZone = false;
|
||||||
|
ui->cbAvatar->setChecked(false);
|
||||||
|
workImage = image_->scaledToHeight(snapmaticResolutionH, Qt::SmoothTransformation);
|
||||||
|
delete image_;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
insideAvatarZone = false;
|
||||||
|
ui->cbAvatar->setChecked(false);
|
||||||
|
workImage = *image_;
|
||||||
|
delete image_;
|
||||||
|
}
|
||||||
|
processImage();
|
||||||
|
lockSettings(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportDialog::lockSettings(bool lock)
|
||||||
|
{
|
||||||
|
ui->cbAvatar->setDisabled(lock);
|
||||||
|
ui->cbForceAvatarColour->setDisabled(lock);
|
||||||
|
ui->cbIgnore->setDisabled(lock);
|
||||||
|
ui->cbStretch->setDisabled(lock);
|
||||||
|
ui->cbWatermark->setDisabled(lock);
|
||||||
|
ui->cmdBackgroundChange->setDisabled(lock);
|
||||||
|
ui->cmdBackgroundWipe->setDisabled(lock);
|
||||||
|
ui->cmdColourChange->setDisabled(lock);
|
||||||
|
ui->labBackgroundImage->setDisabled(lock);
|
||||||
|
ui->labColour->setDisabled(lock);
|
||||||
|
ui->gbSettings->setDisabled(lock);
|
||||||
|
ui->gbBackground->setDisabled(lock);
|
||||||
|
ui->cmdOK->setDisabled(lock);
|
||||||
|
settingsLocked = lock;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportDialog::enableOverwriteMode()
|
||||||
|
{
|
||||||
|
setWindowTitle(QApplication::translate("ImageEditorDialog", "Overwrite Image..."));
|
||||||
|
ui->cmdOK->setText(QApplication::translate("ImageEditorDialog", "&Overwrite"));
|
||||||
|
ui->cmdOK->setToolTip(QApplication::translate("ImageEditorDialog", "Apply changes"));
|
||||||
|
ui->cmdCancel->setText(QApplication::translate("ImageEditorDialog", "&Close"));
|
||||||
|
ui->cmdCancel->setToolTip(QApplication::translate("ImageEditorDialog", "Discard changes"));
|
||||||
|
ui->cmdCancel->setDefault(true);
|
||||||
|
ui->cmdCancel->setFocus();
|
||||||
|
lockSettings(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImportDialog::isImportAgreed()
|
||||||
|
{
|
||||||
|
return importAgreed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImportDialog::areSettingsLocked()
|
||||||
|
{
|
||||||
|
return settingsLocked;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.isNull() && 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();
|
||||||
|
watermarkBlock = true;
|
||||||
|
if (insideAvatarZone)
|
||||||
|
{
|
||||||
|
ui->cbWatermark->setChecked(watermarkAvatar);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->cbWatermark->setChecked(watermarkPicture);
|
||||||
|
}
|
||||||
|
watermarkBlock = false;
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportDialog::on_cmdBackgroundChange_clicked()
|
||||||
|
{
|
||||||
|
QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||||
|
settings.beginGroup("FileDialogs");
|
||||||
|
bool dontUseNativeDialog = settings.value("DontUseNativeDialog", false).toBool();
|
||||||
|
settings.beginGroup("ImportBackground");
|
||||||
|
|
||||||
|
fileDialogPreOpen:
|
||||||
|
QFileDialog fileDialog(this);
|
||||||
|
fileDialog.setFileMode(QFileDialog::ExistingFiles);
|
||||||
|
fileDialog.setViewMode(QFileDialog::Detail);
|
||||||
|
fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
|
||||||
|
fileDialog.setOption(QFileDialog::DontUseNativeDialog, dontUseNativeDialog);
|
||||||
|
fileDialog.setWindowFlags(fileDialog.windowFlags()^Qt::WindowContextHelpButtonHint);
|
||||||
|
fileDialog.setWindowTitle(QApplication::translate("ProfileInterface", "Import..."));
|
||||||
|
fileDialog.setLabelText(QFileDialog::Accept, QApplication::translate("ProfileInterface", "Import"));
|
||||||
|
|
||||||
|
// Getting readable Image formats
|
||||||
|
QString imageFormatsStr = " ";
|
||||||
|
for (QByteArray imageFormat : QImageReader::supportedImageFormats())
|
||||||
|
{
|
||||||
|
imageFormatsStr += QString("*.") % QString::fromUtf8(imageFormat).toLower() % " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList filters;
|
||||||
|
filters << QApplication::translate("ProfileInterface", "All image files (%1)").arg(imageFormatsStr.trimmed());
|
||||||
|
filters << QApplication::translate("ProfileInterface", "All files (**)");
|
||||||
|
fileDialog.setNameFilters(filters);
|
||||||
|
|
||||||
|
QList<QUrl> sidebarUrls = SidebarGenerator::generateSidebarUrls(fileDialog.sidebarUrls());
|
||||||
|
|
||||||
|
fileDialog.setSidebarUrls(sidebarUrls);
|
||||||
|
fileDialog.setDirectory(settings.value("Directory", StandardPaths::documentsLocation()).toString());
|
||||||
|
fileDialog.restoreGeometry(settings.value("Geometry", "").toByteArray());
|
||||||
|
|
||||||
|
if (fileDialog.exec())
|
||||||
|
{
|
||||||
|
QStringList selectedFiles = fileDialog.selectedFiles();
|
||||||
|
if (selectedFiles.length() == 1)
|
||||||
|
{
|
||||||
|
QString selectedFile = selectedFiles.at(0);
|
||||||
|
QString selectedFileName = QFileInfo(selectedFile).fileName();
|
||||||
|
|
||||||
|
QFile snapmaticFile(selectedFile);
|
||||||
|
if (!snapmaticFile.open(QFile::ReadOnly))
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, QApplication::translate("ProfileInterface", "Import"), QApplication::translate("ProfileInterface", "Can't import %1 because file can't be open").arg("\""+selectedFileName+"\""));
|
||||||
|
goto fileDialogPreOpen;
|
||||||
|
}
|
||||||
|
QImage importImage;
|
||||||
|
QImageReader snapmaticImageReader;
|
||||||
|
snapmaticImageReader.setDecideFormatFromContent(true);
|
||||||
|
snapmaticImageReader.setDevice(&snapmaticFile);
|
||||||
|
if (!snapmaticImageReader.read(&importImage))
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, QApplication::translate("ProfileInterface", "Import"), QApplication::translate("ProfileInterface", "Can't import %1 because file can't be parsed properly").arg("\""+selectedFileName+"\""));
|
||||||
|
goto fileDialogPreOpen;
|
||||||
|
}
|
||||||
|
backImage = importImage.scaled(snapmaticResolutionW, snapmaticResolutionH, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||||
|
backgroundPath = selectedFile;
|
||||||
|
ui->labBackgroundImage->setText(tr("Background Image: %1").arg(tr("File", "Background Image: File")));
|
||||||
|
ui->cmdBackgroundWipe->setVisible(true);
|
||||||
|
processImage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.setValue("Geometry", fileDialog.saveGeometry());
|
||||||
|
settings.setValue("Directory", fileDialog.directory().absolutePath());
|
||||||
|
settings.endGroup();
|
||||||
|
settings.endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportDialog::on_cmdBackgroundWipe_clicked()
|
||||||
|
{
|
||||||
|
backImage = QImage();
|
||||||
|
ui->labBackgroundImage->setText(tr("Background Image:"));
|
||||||
|
ui->cmdBackgroundWipe->setVisible(false);
|
||||||
|
processImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportDialog::on_cbStretch_toggled(bool checked)
|
||||||
|
{
|
||||||
|
Q_UNUSED(checked)
|
||||||
|
processImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportDialog::on_cbForceAvatarColour_toggled(bool checked)
|
||||||
|
{
|
||||||
|
Q_UNUSED(checked)
|
||||||
|
processImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportDialog::on_cbWatermark_toggled(bool checked)
|
||||||
|
{
|
||||||
|
if (!watermarkBlock)
|
||||||
|
{
|
||||||
|
if (insideAvatarZone)
|
||||||
|
{
|
||||||
|
watermarkAvatar = checked;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
watermarkPicture = checked;
|
||||||
|
}
|
||||||
|
processImage();
|
||||||
|
}
|
||||||
|
}
|
86
ImportDialog.h
Normal file
86
ImportDialog.h
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 Profile Viewer
|
||||||
|
* 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>
|
||||||
|
#include <QMenu>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class ImportDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ImportDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ImportDialog(QString profileName, QWidget *parent = 0);
|
||||||
|
~ImportDialog();
|
||||||
|
QImage image();
|
||||||
|
QString getImageTitle();
|
||||||
|
void setImage(QImage *image);
|
||||||
|
void lockSettings(bool lock);
|
||||||
|
void enableOverwriteMode();
|
||||||
|
bool isImportAgreed();
|
||||||
|
bool areSettingsLocked();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void processImage();
|
||||||
|
void cropPicture();
|
||||||
|
void importNewPicture();
|
||||||
|
void loadImportSettings();
|
||||||
|
void saveImportSettings();
|
||||||
|
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();
|
||||||
|
void on_cmdBackgroundChange_clicked();
|
||||||
|
void on_cmdBackgroundWipe_clicked();
|
||||||
|
void on_cbStretch_toggled(bool checked);
|
||||||
|
void on_cbForceAvatarColour_toggled(bool checked);
|
||||||
|
void on_cbWatermark_toggled(bool checked);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString profileName;
|
||||||
|
Ui::ImportDialog *ui;
|
||||||
|
QImage avatarAreaImage;
|
||||||
|
QString backgroundPath;
|
||||||
|
QString imageTitle;
|
||||||
|
QImage backImage;
|
||||||
|
QImage workImage;
|
||||||
|
QImage newImage;
|
||||||
|
QColor selectedColour;
|
||||||
|
QMenu *optionsMenu;
|
||||||
|
bool insideAvatarZone;
|
||||||
|
bool watermarkPicture;
|
||||||
|
bool watermarkAvatar;
|
||||||
|
bool watermarkBlock;
|
||||||
|
bool settingsLocked;
|
||||||
|
bool importAgreed;
|
||||||
|
int snapmaticResolutionLW;
|
||||||
|
int snapmaticResolutionLH;
|
||||||
|
void processWatermark(QPainter *snapmaticPainter);
|
||||||
|
void processSettings(QString settingsProfile, bool setDefault = false);
|
||||||
|
void saveSettings(QString settingsProfile);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // IMPORTDIALOG_H
|
382
ImportDialog.ui
Normal file
382
ImportDialog.ui
Normal file
|
@ -0,0 +1,382 @@
|
||||||
|
<?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>516</width>
|
||||||
|
<height>512</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>516</width>
|
||||||
|
<height>512</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>516</width>
|
||||||
|
<height>288</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>Picture</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="vlSettings">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="hlCheckboxesTop">
|
||||||
|
<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>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="hlCheckboxesButtom">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="cbWatermark">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Watermark</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="gbBackground">
|
||||||
|
<property name="title">
|
||||||
|
<string>Background</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="vlBackground">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="hlColour">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="hlColourManage">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="labColour">
|
||||||
|
<property name="text">
|
||||||
|
<string>Background Colour: <span style="color: %1">%1</span></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="hlColourButton">
|
||||||
|
<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="QToolButton" name="cmdColourChange">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Select background colour</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="hsColour">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="hlBackgroundManage">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="labBackgroundImage">
|
||||||
|
<property name="text">
|
||||||
|
<string>Background Image:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="hlBackgroundButton">
|
||||||
|
<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="QToolButton" name="cmdBackgroundChange">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Select background image</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="cmdBackgroundWipe">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Remove background image</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>X</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="hsBackgroundImage">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="hlBackground">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="cbForceAvatarColour">
|
||||||
|
<property name="text">
|
||||||
|
<string>Force Colour in Avatar Zone</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="cbStretch">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Ignore Aspect Ratio</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</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>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="hlButtons">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="cmdOptions">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Import options</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Options</string>
|
||||||
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</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="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>
|
233
JsonEditorDialog.cpp
Normal file
233
JsonEditorDialog.cpp
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 Profile Viewer
|
||||||
|
* Copyright (C) 2017-2018 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 "JsonEditorDialog.h"
|
||||||
|
#include "ui_JsonEditorDialog.h"
|
||||||
|
#include "SnapmaticEditor.h"
|
||||||
|
#include "AppEnv.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include <QStringBuilder>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
#if QT_VERSION >= 0x050200
|
||||||
|
#include <QFontDatabase>
|
||||||
|
#include <QDebug>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GTA5SYNC_TELEMETRY
|
||||||
|
#include "TelemetryClass.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
JsonEditorDialog::JsonEditorDialog(SnapmaticPicture *picture, QWidget *parent) :
|
||||||
|
QDialog(parent), smpic(picture),
|
||||||
|
ui(new Ui::JsonEditorDialog)
|
||||||
|
{
|
||||||
|
// Set Window Flags
|
||||||
|
setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint^Qt::WindowMinMaxButtonsHint);
|
||||||
|
|
||||||
|
ui->setupUi(this);
|
||||||
|
ui->cmdClose->setDefault(true);
|
||||||
|
ui->cmdClose->setFocus();
|
||||||
|
|
||||||
|
// Set Icon for Close Button
|
||||||
|
if (QIcon::hasThemeIcon("dialog-close"))
|
||||||
|
{
|
||||||
|
ui->cmdClose->setIcon(QIcon::fromTheme("dialog-close"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("gtk-close"))
|
||||||
|
{
|
||||||
|
ui->cmdClose->setIcon(QIcon::fromTheme("gtk-close"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Icon for Save Button
|
||||||
|
if (QIcon::hasThemeIcon("document-save"))
|
||||||
|
{
|
||||||
|
ui->cmdSave->setIcon(QIcon::fromTheme("document-save"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("gtk-save"))
|
||||||
|
{
|
||||||
|
ui->cmdSave->setIcon(QIcon::fromTheme("gtk-save"));
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonCode = picture->getJsonStr();
|
||||||
|
|
||||||
|
#if QT_VERSION >= 0x050200
|
||||||
|
ui->txtJSON->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
|
||||||
|
#endif
|
||||||
|
QFontMetrics fontMetrics(ui->txtJSON->font());
|
||||||
|
ui->txtJSON->setTabStopWidth(fontMetrics.width(" "));
|
||||||
|
|
||||||
|
QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonCode.toUtf8());
|
||||||
|
ui->txtJSON->setStyleSheet("QPlainTextEdit{background-color: rgb(46, 47, 48); color: rgb(238, 231, 172);}");
|
||||||
|
ui->txtJSON->setPlainText(QString::fromUtf8(jsonDocument.toJson(QJsonDocument::Indented)).trimmed());
|
||||||
|
jsonHl = new JSHighlighter(ui->txtJSON->document());
|
||||||
|
|
||||||
|
// DPI calculation
|
||||||
|
qreal screenRatio = AppEnv::screenRatio();
|
||||||
|
#ifndef Q_OS_MAC
|
||||||
|
ui->hlButtons->setSpacing(6 * screenRatio);
|
||||||
|
ui->hlButtons->setContentsMargins(9 * screenRatio, 0, 9 * screenRatio, 0);
|
||||||
|
ui->vlInterface->setContentsMargins(0, 0, 0, 9 * screenRatio);
|
||||||
|
#else
|
||||||
|
ui->hlButtons->setSpacing(6 * screenRatio);
|
||||||
|
ui->hlButtons->setContentsMargins(9 * screenRatio, 0, 9 * screenRatio, 0);
|
||||||
|
ui->vlInterface->setContentsMargins(0, 0, 0, 9 * screenRatio);
|
||||||
|
#endif
|
||||||
|
if (screenRatio > 1)
|
||||||
|
{
|
||||||
|
ui->lineJSON->setMinimumHeight(qRound(1 * screenRatio));
|
||||||
|
ui->lineJSON->setMaximumHeight(qRound(1 * screenRatio));
|
||||||
|
ui->lineJSON->setLineWidth(qRound(1 * screenRatio));
|
||||||
|
}
|
||||||
|
resize(450 * screenRatio, 550 * screenRatio);
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonEditorDialog::~JsonEditorDialog()
|
||||||
|
{
|
||||||
|
delete jsonHl;
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JsonEditorDialog::closeEvent(QCloseEvent *ev)
|
||||||
|
{
|
||||||
|
QString jsonPatched = QString(ui->txtJSON->toPlainText()).replace("\t", " ");
|
||||||
|
QJsonDocument jsonNew = QJsonDocument::fromJson(jsonPatched.toUtf8());
|
||||||
|
QJsonDocument jsonOriginal = QJsonDocument::fromJson(jsonCode.toUtf8());
|
||||||
|
QString originalCode = QString::fromUtf8(jsonOriginal.toJson(QJsonDocument::Compact));
|
||||||
|
QString newCode = QString::fromUtf8(jsonNew.toJson(QJsonDocument::Compact));
|
||||||
|
if (newCode != originalCode)
|
||||||
|
{
|
||||||
|
QMessageBox::StandardButton button = QMessageBox::warning(this, SnapmaticEditor::tr("Snapmatic Properties"), SnapmaticEditor::tr("<h4>Unsaved changes detected</h4>You want to save the JSON content before you quit?"), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Cancel);
|
||||||
|
if (button == QMessageBox::Yes)
|
||||||
|
{
|
||||||
|
if (saveJsonContent())
|
||||||
|
{
|
||||||
|
ev->accept();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ev->ignore();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (button == QMessageBox::No)
|
||||||
|
{
|
||||||
|
ev->accept();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ev->ignore();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JsonEditorDialog::saveJsonContent()
|
||||||
|
{
|
||||||
|
QString jsonPatched = QString(ui->txtJSON->toPlainText()).replace("\t", " ");
|
||||||
|
QJsonDocument jsonNew = QJsonDocument::fromJson(jsonPatched.toUtf8());
|
||||||
|
if (!jsonNew.isEmpty())
|
||||||
|
{
|
||||||
|
QJsonDocument jsonOriginal = QJsonDocument::fromJson(jsonCode.toUtf8());
|
||||||
|
QString originalCode = QString::fromUtf8(jsonOriginal.toJson(QJsonDocument::Compact));
|
||||||
|
QString newCode = QString::fromUtf8(jsonNew.toJson(QJsonDocument::Compact));
|
||||||
|
if (newCode != originalCode)
|
||||||
|
{
|
||||||
|
QString currentFilePath = smpic->getPictureFilePath();
|
||||||
|
QString originalFilePath = smpic->getOriginalPictureFilePath();
|
||||||
|
QString backupFileName = originalFilePath % ".bak";
|
||||||
|
if (!QFile::exists(backupFileName))
|
||||||
|
{
|
||||||
|
QFile::copy(currentFilePath, backupFileName);
|
||||||
|
}
|
||||||
|
smpic->setJsonStr(newCode, true);
|
||||||
|
if (!smpic->isJsonOk())
|
||||||
|
{
|
||||||
|
QString lastStep = smpic->getLastStep(false);
|
||||||
|
QString readableError;
|
||||||
|
if (lastStep.contains("JSONINCOMPLETE") && lastStep.contains("JSONERROR"))
|
||||||
|
{
|
||||||
|
readableError = SnapmaticPicture::tr("JSON is incomplete and malformed");
|
||||||
|
}
|
||||||
|
else if (lastStep.contains("JSONINCOMPLETE"))
|
||||||
|
{
|
||||||
|
readableError = SnapmaticPicture::tr("JSON is incomplete");
|
||||||
|
}
|
||||||
|
else if (lastStep.contains("JSONERROR"))
|
||||||
|
{
|
||||||
|
readableError = SnapmaticPicture::tr("JSON is malformed");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
readableError = tr("JSON Error");
|
||||||
|
}
|
||||||
|
QMessageBox::warning(this, SnapmaticEditor::tr("Snapmatic Properties"), SnapmaticEditor::tr("Patching of Snapmatic Properties failed because of %1").arg(readableError));
|
||||||
|
smpic->setJsonStr(originalCode, true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!smpic->exportPicture(currentFilePath))
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, SnapmaticEditor::tr("Snapmatic Properties"), SnapmaticEditor::tr("Patching of Snapmatic Properties failed because of I/O Error"));
|
||||||
|
smpic->setJsonStr(originalCode, true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
jsonCode = newCode;
|
||||||
|
smpic->updateStrings();
|
||||||
|
smpic->emitUpdate();
|
||||||
|
#ifdef GTA5SYNC_TELEMETRY
|
||||||
|
QSettings telemetrySettings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||||
|
telemetrySettings.beginGroup("Telemetry");
|
||||||
|
bool pushUsageData = telemetrySettings.value("PushUsageData", false).toBool();
|
||||||
|
telemetrySettings.endGroup();
|
||||||
|
if (pushUsageData && Telemetry->canPush())
|
||||||
|
{
|
||||||
|
QJsonDocument jsonDocument;
|
||||||
|
QJsonObject jsonObject;
|
||||||
|
jsonObject["Type"] = "JSONEdited";
|
||||||
|
jsonObject["EditedSize"] = QString::number(smpic->getContentMaxLength());
|
||||||
|
jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toTime_t());
|
||||||
|
jsonDocument.setObject(jsonObject);
|
||||||
|
Telemetry->push(TelemetryCategory::PersonalData, jsonDocument);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, SnapmaticEditor::tr("Snapmatic Properties"), SnapmaticEditor::tr("Patching of Snapmatic Properties failed because of JSON Error"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JsonEditorDialog::on_cmdClose_clicked()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JsonEditorDialog::on_cmdSave_clicked()
|
||||||
|
{
|
||||||
|
if (saveJsonContent())
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
56
JsonEditorDialog.h
Normal file
56
JsonEditorDialog.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 Profile Viewer
|
||||||
|
* 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 JSONEDITORDIALOG_H
|
||||||
|
#define JSONEDITORDIALOG_H
|
||||||
|
|
||||||
|
#include "SnapmaticPicture.h"
|
||||||
|
#include "JSHighlighter.h"
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class JsonEditorDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
class JsonEditorDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit JsonEditorDialog(SnapmaticPicture *picture, QWidget *parent = 0);
|
||||||
|
bool saveJsonContent();
|
||||||
|
~JsonEditorDialog();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void closeEvent(QCloseEvent *ev);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_cmdClose_clicked();
|
||||||
|
void on_cmdSave_clicked();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void codeUpdated(QString jsonCode);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString jsonCode;
|
||||||
|
JSHighlighter *jsonHl;
|
||||||
|
SnapmaticPicture *smpic;
|
||||||
|
Ui::JsonEditorDialog *ui;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // JSONEDITORDIALOG_H
|
145
JsonEditorDialog.ui
Normal file
145
JsonEditorDialog.ui
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>JsonEditorDialog</class>
|
||||||
|
<widget class="QDialog" name="JsonEditorDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>550</width>
|
||||||
|
<height>450</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Snapmatic JSON Editor</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="vlInterface">
|
||||||
|
<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>9</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="vlJSON">
|
||||||
|
<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="QPlainTextEdit" name="txtJSON">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Plain</enum>
|
||||||
|
</property>
|
||||||
|
<property name="lineWidth">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="lineJSON">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>1</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16777215</width>
|
||||||
|
<height>1</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">QFrame[frameShape="4"]
|
||||||
|
{
|
||||||
|
color: black;
|
||||||
|
}</string>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Plain</enum>
|
||||||
|
</property>
|
||||||
|
<property name="lineWidth">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</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="cmdSave">
|
||||||
|
<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>&Save</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="toolTip">
|
||||||
|
<string>Discard changes</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Close</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
674
LICENSE
Normal file
674
LICENSE
Normal file
|
@ -0,0 +1,674 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The GNU General Public License is a free, copyleft license for
|
||||||
|
software and other kinds of works.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed
|
||||||
|
to take away your freedom to share and change the works. By contrast,
|
||||||
|
the GNU General Public License is intended to guarantee your freedom to
|
||||||
|
share and change all versions of a program--to make sure it remains free
|
||||||
|
software for all its users. We, the Free Software Foundation, use the
|
||||||
|
GNU General Public License for most of our software; it applies also to
|
||||||
|
any other work released this way by its authors. You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to prevent others from denying you
|
||||||
|
these rights or asking you to surrender the rights. Therefore, you have
|
||||||
|
certain responsibilities if you distribute copies of the software, or if
|
||||||
|
you modify it: responsibilities to respect the freedom of others.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must pass on to the recipients the same
|
||||||
|
freedoms that you received. You must make sure that they, too, receive
|
||||||
|
or can get the source code. And you must show them these terms so they
|
||||||
|
know their rights.
|
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps:
|
||||||
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains
|
||||||
|
that there is no warranty for this free software. For both users' and
|
||||||
|
authors' sake, the GPL requires that modified versions be marked as
|
||||||
|
changed, so that their problems will not be attributed erroneously to
|
||||||
|
authors of previous versions.
|
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run
|
||||||
|
modified versions of the software inside them, although the manufacturer
|
||||||
|
can do so. This is fundamentally incompatible with the aim of
|
||||||
|
protecting users' freedom to change the software. The systematic
|
||||||
|
pattern of such abuse occurs in the area of products for individuals to
|
||||||
|
use, which is precisely where it is most unacceptable. Therefore, we
|
||||||
|
have designed this version of the GPL to prohibit the practice for those
|
||||||
|
products. If such problems arise substantially in other domains, we
|
||||||
|
stand ready to extend this provision to those domains in future versions
|
||||||
|
of the GPL, as needed to protect the freedom of users.
|
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents.
|
||||||
|
States should not allow patents to restrict development and use of
|
||||||
|
software on general-purpose computers, but in those that do, we wish to
|
||||||
|
avoid the special danger that patents applied to a free program could
|
||||||
|
make it effectively proprietary. To prevent this, the GPL assures that
|
||||||
|
patents cannot be used to render the program non-free.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Use with the GNU Affero General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU Affero General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the special requirements of the GNU Affero General Public License,
|
||||||
|
section 13, concerning interaction through a network will apply to the
|
||||||
|
combination as such.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Program specifies that a certain numbered version of the GNU General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
state the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
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 <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program does terminal interaction, make it output a short
|
||||||
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
|
<program> Copyright (C) <year> <name of author>
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, your program's commands
|
||||||
|
might be different; for a GUI interface, you would use an "about box".
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
|
For more information on this, and how to apply and follow the GNU GPL, see
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
The GNU General Public License does not permit incorporating your program
|
||||||
|
into proprietary programs. If your program is a subroutine library, you
|
||||||
|
may consider it more useful to permit linking proprietary applications with
|
||||||
|
the library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License. But first, please read
|
||||||
|
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
674
LICENSE.GPL
Normal file
674
LICENSE.GPL
Normal file
|
@ -0,0 +1,674 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The GNU General Public License is a free, copyleft license for
|
||||||
|
software and other kinds of works.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed
|
||||||
|
to take away your freedom to share and change the works. By contrast,
|
||||||
|
the GNU General Public License is intended to guarantee your freedom to
|
||||||
|
share and change all versions of a program--to make sure it remains free
|
||||||
|
software for all its users. We, the Free Software Foundation, use the
|
||||||
|
GNU General Public License for most of our software; it applies also to
|
||||||
|
any other work released this way by its authors. You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to prevent others from denying you
|
||||||
|
these rights or asking you to surrender the rights. Therefore, you have
|
||||||
|
certain responsibilities if you distribute copies of the software, or if
|
||||||
|
you modify it: responsibilities to respect the freedom of others.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must pass on to the recipients the same
|
||||||
|
freedoms that you received. You must make sure that they, too, receive
|
||||||
|
or can get the source code. And you must show them these terms so they
|
||||||
|
know their rights.
|
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps:
|
||||||
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains
|
||||||
|
that there is no warranty for this free software. For both users' and
|
||||||
|
authors' sake, the GPL requires that modified versions be marked as
|
||||||
|
changed, so that their problems will not be attributed erroneously to
|
||||||
|
authors of previous versions.
|
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run
|
||||||
|
modified versions of the software inside them, although the manufacturer
|
||||||
|
can do so. This is fundamentally incompatible with the aim of
|
||||||
|
protecting users' freedom to change the software. The systematic
|
||||||
|
pattern of such abuse occurs in the area of products for individuals to
|
||||||
|
use, which is precisely where it is most unacceptable. Therefore, we
|
||||||
|
have designed this version of the GPL to prohibit the practice for those
|
||||||
|
products. If such problems arise substantially in other domains, we
|
||||||
|
stand ready to extend this provision to those domains in future versions
|
||||||
|
of the GPL, as needed to protect the freedom of users.
|
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents.
|
||||||
|
States should not allow patents to restrict development and use of
|
||||||
|
software on general-purpose computers, but in those that do, we wish to
|
||||||
|
avoid the special danger that patents applied to a free program could
|
||||||
|
make it effectively proprietary. To prevent this, the GPL assures that
|
||||||
|
patents cannot be used to render the program non-free.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Use with the GNU Affero General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU Affero General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the special requirements of the GNU Affero General Public License,
|
||||||
|
section 13, concerning interaction through a network will apply to the
|
||||||
|
combination as such.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Program specifies that a certain numbered version of the GNU General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
state the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
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 <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program does terminal interaction, make it output a short
|
||||||
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
|
<program> Copyright (C) <year> <name of author>
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, your program's commands
|
||||||
|
might be different; for a GUI interface, you would use an "about box".
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
|
For more information on this, and how to apply and follow the GNU GPL, see
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
The GNU General Public License does not permit incorporating your program
|
||||||
|
into proprietary programs. If your program is a subroutine library, you
|
||||||
|
may consider it more useful to permit linking proprietary applications with
|
||||||
|
the library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License. But first, please read
|
||||||
|
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
165
LICENSE.LGPL
Normal file
165
LICENSE.LGPL
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
|
||||||
|
This version of the GNU Lesser General Public License incorporates
|
||||||
|
the terms and conditions of version 3 of the GNU General Public
|
||||||
|
License, supplemented by the additional permissions listed below.
|
||||||
|
|
||||||
|
0. Additional Definitions.
|
||||||
|
|
||||||
|
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||||
|
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||||
|
General Public License.
|
||||||
|
|
||||||
|
"The Library" refers to a covered work governed by this License,
|
||||||
|
other than an Application or a Combined Work as defined below.
|
||||||
|
|
||||||
|
An "Application" is any work that makes use of an interface provided
|
||||||
|
by the Library, but which is not otherwise based on the Library.
|
||||||
|
Defining a subclass of a class defined by the Library is deemed a mode
|
||||||
|
of using an interface provided by the Library.
|
||||||
|
|
||||||
|
A "Combined Work" is a work produced by combining or linking an
|
||||||
|
Application with the Library. The particular version of the Library
|
||||||
|
with which the Combined Work was made is also called the "Linked
|
||||||
|
Version".
|
||||||
|
|
||||||
|
The "Minimal Corresponding Source" for a Combined Work means the
|
||||||
|
Corresponding Source for the Combined Work, excluding any source code
|
||||||
|
for portions of the Combined Work that, considered in isolation, are
|
||||||
|
based on the Application, and not on the Linked Version.
|
||||||
|
|
||||||
|
The "Corresponding Application Code" for a Combined Work means the
|
||||||
|
object code and/or source code for the Application, including any data
|
||||||
|
and utility programs needed for reproducing the Combined Work from the
|
||||||
|
Application, but excluding the System Libraries of the Combined Work.
|
||||||
|
|
||||||
|
1. Exception to Section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
You may convey a covered work under sections 3 and 4 of this License
|
||||||
|
without being bound by section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
2. Conveying Modified Versions.
|
||||||
|
|
||||||
|
If you modify a copy of the Library, and, in your modifications, a
|
||||||
|
facility refers to a function or data to be supplied by an Application
|
||||||
|
that uses the facility (other than as an argument passed when the
|
||||||
|
facility is invoked), then you may convey a copy of the modified
|
||||||
|
version:
|
||||||
|
|
||||||
|
a) under this License, provided that you make a good faith effort to
|
||||||
|
ensure that, in the event an Application does not supply the
|
||||||
|
function or data, the facility still operates, and performs
|
||||||
|
whatever part of its purpose remains meaningful, or
|
||||||
|
|
||||||
|
b) under the GNU GPL, with none of the additional permissions of
|
||||||
|
this License applicable to that copy.
|
||||||
|
|
||||||
|
3. Object Code Incorporating Material from Library Header Files.
|
||||||
|
|
||||||
|
The object code form of an Application may incorporate material from
|
||||||
|
a header file that is part of the Library. You may convey such object
|
||||||
|
code under terms of your choice, provided that, if the incorporated
|
||||||
|
material is not limited to numerical parameters, data structure
|
||||||
|
layouts and accessors, or small macros, inline functions and templates
|
||||||
|
(ten or fewer lines in length), you do both of the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the object code that the
|
||||||
|
Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
4. Combined Works.
|
||||||
|
|
||||||
|
You may convey a Combined Work under terms of your choice that,
|
||||||
|
taken together, effectively do not restrict modification of the
|
||||||
|
portions of the Library contained in the Combined Work and reverse
|
||||||
|
engineering for debugging such modifications, if you also do each of
|
||||||
|
the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the Combined Work that
|
||||||
|
the Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
c) For a Combined Work that displays copyright notices during
|
||||||
|
execution, include the copyright notice for the Library among
|
||||||
|
these notices, as well as a reference directing the user to the
|
||||||
|
copies of the GNU GPL and this license document.
|
||||||
|
|
||||||
|
d) Do one of the following:
|
||||||
|
|
||||||
|
0) Convey the Minimal Corresponding Source under the terms of this
|
||||||
|
License, and the Corresponding Application Code in a form
|
||||||
|
suitable for, and under terms that permit, the user to
|
||||||
|
recombine or relink the Application with a modified version of
|
||||||
|
the Linked Version to produce a modified Combined Work, in the
|
||||||
|
manner specified by section 6 of the GNU GPL for conveying
|
||||||
|
Corresponding Source.
|
||||||
|
|
||||||
|
1) Use a suitable shared library mechanism for linking with the
|
||||||
|
Library. A suitable mechanism is one that (a) uses at run time
|
||||||
|
a copy of the Library already present on the user's computer
|
||||||
|
system, and (b) will operate properly with a modified version
|
||||||
|
of the Library that is interface-compatible with the Linked
|
||||||
|
Version.
|
||||||
|
|
||||||
|
e) Provide Installation Information, but only if you would otherwise
|
||||||
|
be required to provide such information under section 6 of the
|
||||||
|
GNU GPL, and only to the extent that such information is
|
||||||
|
necessary to install and execute a modified version of the
|
||||||
|
Combined Work produced by recombining or relinking the
|
||||||
|
Application with a modified version of the Linked Version. (If
|
||||||
|
you use option 4d0, the Installation Information must accompany
|
||||||
|
the Minimal Corresponding Source and Corresponding Application
|
||||||
|
Code. If you use option 4d1, you must provide the Installation
|
||||||
|
Information in the manner specified by section 6 of the GNU GPL
|
||||||
|
for conveying Corresponding Source.)
|
||||||
|
|
||||||
|
5. Combined Libraries.
|
||||||
|
|
||||||
|
You may place library facilities that are a work based on the
|
||||||
|
Library side by side in a single library together with other library
|
||||||
|
facilities that are not Applications and are not covered by this
|
||||||
|
License, and convey such a combined library under terms of your
|
||||||
|
choice, if you do both of the following:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work based
|
||||||
|
on the Library, uncombined with any other library facilities,
|
||||||
|
conveyed under the terms of this License.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library that part of it
|
||||||
|
is a work based on the Library, and explaining where to find the
|
||||||
|
accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
6. Revised Versions of the GNU Lesser General Public License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the GNU Lesser General Public License from time to time. Such new
|
||||||
|
versions will be similar in spirit to the present version, but may
|
||||||
|
differ in detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Library as you received it specifies that a certain numbered version
|
||||||
|
of the GNU Lesser General Public License "or any later version"
|
||||||
|
applies to it, you have the option of following the terms and
|
||||||
|
conditions either of that published version or of any later version
|
||||||
|
published by the Free Software Foundation. If the Library as you
|
||||||
|
received it does not specify a version number of the GNU Lesser
|
||||||
|
General Public License, you may choose any version of the GNU Lesser
|
||||||
|
General Public License ever published by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Library as you received it specifies that a proxy can decide
|
||||||
|
whether future versions of the GNU Lesser General Public License shall
|
||||||
|
apply, that proxy's public statement of acceptance of any version is
|
||||||
|
permanent authorization for you to choose that version for the
|
||||||
|
Library.
|
204
MapLocationDialog.cpp
Normal file
204
MapLocationDialog.cpp
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 Profile Viewer
|
||||||
|
* Copyright (C) 2017-2019 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 "MapLocationDialog.h"
|
||||||
|
#include "ui_MapLocationDialog.h"
|
||||||
|
#include "IconLoader.h"
|
||||||
|
#include "AppEnv.h"
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QStyle>
|
||||||
|
|
||||||
|
MapLocationDialog::MapLocationDialog(double x, double y, QWidget *parent) :
|
||||||
|
QDialog(parent), xpos_old(x), ypos_old(y),
|
||||||
|
ui(new Ui::MapLocationDialog)
|
||||||
|
{
|
||||||
|
// Set Window Flags
|
||||||
|
setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint);
|
||||||
|
|
||||||
|
ui->setupUi(this);
|
||||||
|
ui->cmdDone->setVisible(false);
|
||||||
|
ui->cmdApply->setVisible(false);
|
||||||
|
ui->cmdRevert->setVisible(false);
|
||||||
|
ui->cmdDone->setCursor(Qt::ArrowCursor);
|
||||||
|
ui->cmdClose->setCursor(Qt::ArrowCursor);
|
||||||
|
|
||||||
|
// DPI calculation
|
||||||
|
qreal screenRatio = AppEnv::screenRatio();
|
||||||
|
int widgetMargin = qRound(3 * screenRatio);
|
||||||
|
ui->hlMapDialog->setContentsMargins(widgetMargin, widgetMargin, widgetMargin, widgetMargin);
|
||||||
|
ui->vlMapDialog->setSpacing(widgetMargin);
|
||||||
|
setMinimumSize(500 * screenRatio, 600 * screenRatio);
|
||||||
|
setMaximumSize(500 * screenRatio, 600 * screenRatio);
|
||||||
|
setFixedSize(500 * screenRatio, 600 * screenRatio);
|
||||||
|
setMouseTracking(true);
|
||||||
|
|
||||||
|
changeMode = false;
|
||||||
|
propUpdate = false;
|
||||||
|
drawPointOnMap(xpos_old, ypos_old);
|
||||||
|
}
|
||||||
|
|
||||||
|
MapLocationDialog::~MapLocationDialog()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapLocationDialog::drawPointOnMap(double xpos_d, double ypos_d)
|
||||||
|
{
|
||||||
|
qreal screenRatio = AppEnv::screenRatio();
|
||||||
|
qreal screenRatioPR = AppEnv::screenRatioPR();
|
||||||
|
int pointMakerSize = 8 * screenRatio * screenRatioPR;
|
||||||
|
QPixmap pointMakerPixmap = IconLoader::loadingPointmakerIcon().pixmap(QSize(pointMakerSize, pointMakerSize));
|
||||||
|
QSize mapPixelSize = QSize(width() * screenRatioPR, height() * screenRatioPR);
|
||||||
|
|
||||||
|
int pointMakerHalfSize = pointMakerSize / 2;
|
||||||
|
long xpos_ms = qRound(xpos_d);
|
||||||
|
long ypos_ms = qRound(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 = qRound(xpos_ma * xrat);
|
||||||
|
long ypos_mp = qRound(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();
|
||||||
|
#if QT_VERSION >= 0x050600
|
||||||
|
mapPixmap.setDevicePixelRatio(screenRatioPR);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QPalette backgroundPalette;
|
||||||
|
backgroundPalette.setBrush(backgroundRole(), QBrush(mapPixmap));
|
||||||
|
setPalette(backgroundPalette);
|
||||||
|
|
||||||
|
xpos_new = xpos_d;
|
||||||
|
ypos_new = ypos_d;
|
||||||
|
ui->labPos->setText(tr("X: %1\nY: %2", "X and Y position").arg(QString::number(xpos_d), QString::number(ypos_d)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapLocationDialog::on_cmdChange_clicked()
|
||||||
|
{
|
||||||
|
qreal screenRatio = AppEnv::screenRatio();
|
||||||
|
int pointMakerSize = 8 * screenRatio;
|
||||||
|
QPixmap pointMakerPixmap = IconLoader::loadingPointmakerIcon().pixmap(QSize(pointMakerSize, pointMakerSize));
|
||||||
|
QCursor pointMakerCursor(pointMakerPixmap);
|
||||||
|
ui->cmdDone->setVisible(true);
|
||||||
|
ui->cmdApply->setVisible(false);
|
||||||
|
ui->cmdChange->setVisible(false);
|
||||||
|
ui->cmdRevert->setVisible(false);
|
||||||
|
|
||||||
|
setCursor(pointMakerCursor);
|
||||||
|
changeMode = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapLocationDialog::on_cmdDone_clicked()
|
||||||
|
{
|
||||||
|
ui->cmdDone->setVisible(false);
|
||||||
|
ui->cmdChange->setVisible(true);
|
||||||
|
if (xpos_new != xpos_old || ypos_new != ypos_old)
|
||||||
|
{
|
||||||
|
ui->cmdApply->setVisible(true);
|
||||||
|
ui->cmdRevert->setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
setCursor(Qt::ArrowCursor);
|
||||||
|
changeMode = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapLocationDialog::updatePosFromEvent(int x, int y)
|
||||||
|
{
|
||||||
|
QSize mapPixelSize = size();
|
||||||
|
int xpos_ad = x;
|
||||||
|
int ypos_ad = mapPixelSize.height() - y;
|
||||||
|
double xrat = 10000 / (double)mapPixelSize.width();
|
||||||
|
double yrat = 12000 / (double)mapPixelSize.height();
|
||||||
|
double xpos_rv = xrat * xpos_ad;
|
||||||
|
double ypos_rv = yrat * ypos_ad;
|
||||||
|
double xpos_fp = xpos_rv - 4000;
|
||||||
|
double ypos_fp = ypos_rv - 4000;
|
||||||
|
drawPointOnMap(xpos_fp, ypos_fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapLocationDialog::mouseMoveEvent(QMouseEvent *ev)
|
||||||
|
{
|
||||||
|
if (!changeMode) { ev->ignore(); }
|
||||||
|
else if (ev->buttons() & Qt::LeftButton)
|
||||||
|
{
|
||||||
|
updatePosFromEvent(ev->x(), ev->y());
|
||||||
|
ev->accept();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ev->ignore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapLocationDialog::mouseReleaseEvent(QMouseEvent *ev)
|
||||||
|
{
|
||||||
|
if (!changeMode) { ev->ignore(); }
|
||||||
|
else if (ev->button() == Qt::LeftButton)
|
||||||
|
{
|
||||||
|
updatePosFromEvent(ev->x(), ev->y());
|
||||||
|
ev->accept();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ev->ignore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapLocationDialog::on_cmdApply_clicked()
|
||||||
|
{
|
||||||
|
propUpdate = true;
|
||||||
|
xpos_old = xpos_new;
|
||||||
|
ypos_old = ypos_new;
|
||||||
|
ui->cmdApply->setVisible(false);
|
||||||
|
ui->cmdRevert->setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapLocationDialog::on_cmdRevert_clicked()
|
||||||
|
{
|
||||||
|
drawPointOnMap(xpos_old, ypos_old);
|
||||||
|
ui->cmdApply->setVisible(false);
|
||||||
|
ui->cmdRevert->setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MapLocationDialog::propUpdated()
|
||||||
|
{
|
||||||
|
return propUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
double MapLocationDialog::getXpos()
|
||||||
|
{
|
||||||
|
return xpos_old;
|
||||||
|
}
|
||||||
|
|
||||||
|
double MapLocationDialog::getYpos()
|
||||||
|
{
|
||||||
|
return ypos_old;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapLocationDialog::on_cmdClose_clicked()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
63
MapLocationDialog.h
Normal file
63
MapLocationDialog.h
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 Profile Viewer
|
||||||
|
* 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 MAPLOCATIONDIALOG_H
|
||||||
|
#define MAPLOCATIONDIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class MapLocationDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MapLocationDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit MapLocationDialog(double x, double y, QWidget *parent = 0);
|
||||||
|
void drawPointOnMap(double x, double y);
|
||||||
|
bool propUpdated();
|
||||||
|
double getXpos();
|
||||||
|
double getYpos();
|
||||||
|
~MapLocationDialog();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void mouseMoveEvent(QMouseEvent *ev);
|
||||||
|
void mouseReleaseEvent(QMouseEvent *ev);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_cmdDone_clicked();
|
||||||
|
void on_cmdApply_clicked();
|
||||||
|
void on_cmdChange_clicked();
|
||||||
|
void on_cmdRevert_clicked();
|
||||||
|
void updatePosFromEvent(int x, int y);
|
||||||
|
void on_cmdClose_clicked();
|
||||||
|
|
||||||
|
private:
|
||||||
|
double xpos_old;
|
||||||
|
double ypos_old;
|
||||||
|
double xpos_new;
|
||||||
|
double ypos_new;
|
||||||
|
bool propUpdate;
|
||||||
|
bool changeMode;
|
||||||
|
Ui::MapLocationDialog *ui;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MAPLOCATIONDIALOG_H
|
233
MapLocationDialog.ui
Normal file
233
MapLocationDialog.ui
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MapLocationDialog</class>
|
||||||
|
<widget class="QDialog" name="MapLocationDialog">
|
||||||
|
<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>
|
||||||
|
<layout class="QHBoxLayout" name="hlMapDialog">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="vlPosLayout">
|
||||||
|
<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="QLabel" name="labPos">
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">QLabel{
|
||||||
|
color: rgb(255, 255, 255);
|
||||||
|
}</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="vsPosSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="hsMapDialog">
|
||||||
|
<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>
|
||||||
|
<layout class="QVBoxLayout" name="vlMapDialog">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>3</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="QPushButton" name="cmdClose">
|
||||||
|
<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>
|
||||||
|
<item>
|
||||||
|
<spacer name="vsMapDialog">
|
||||||
|
<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="QPushButton" name="cmdApply">
|
||||||
|
<property name="focusPolicy">
|
||||||
|
<enum>Qt::NoFocus</enum>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Apply new position</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Apply</string>
|
||||||
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="cmdRevert">
|
||||||
|
<property name="focusPolicy">
|
||||||
|
<enum>Qt::NoFocus</enum>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Revert old position</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Revert</string>
|
||||||
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="cmdChange">
|
||||||
|
<property name="focusPolicy">
|
||||||
|
<enum>Qt::NoFocus</enum>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Select new position</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Select</string>
|
||||||
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="cmdDone">
|
||||||
|
<property name="focusPolicy">
|
||||||
|
<enum>Qt::NoFocus</enum>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Quit select position</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Done</string>
|
||||||
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
737
OptionsDialog.cpp
Normal file
737
OptionsDialog.cpp
Normal file
|
@ -0,0 +1,737 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 Profile Viewer
|
||||||
|
* Copyright (C) 2016-2018 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 <QJsonDocument>
|
||||||
|
#include <QStyleFactory>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QClipboard>
|
||||||
|
#include <QLocale>
|
||||||
|
#include <QString>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QList>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
|
#ifdef GTA5SYNC_TELEMETRY
|
||||||
|
#include "TelemetryClass.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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);
|
||||||
|
ui->cmdCancel->setDefault(true);
|
||||||
|
ui->cmdCancel->setFocus();
|
||||||
|
|
||||||
|
QRect desktopResolution = QApplication::desktop()->screenGeometry(this);
|
||||||
|
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())));
|
||||||
|
|
||||||
|
// Set Icon for OK Button
|
||||||
|
if (QIcon::hasThemeIcon("dialog-ok"))
|
||||||
|
{
|
||||||
|
ui->cmdOK->setIcon(QIcon::fromTheme("dialog-ok"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("gtk-ok"))
|
||||||
|
{
|
||||||
|
ui->cmdOK->setIcon(QIcon::fromTheme("gtk-ok"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Icon for Cancel Button
|
||||||
|
if (QIcon::hasThemeIcon("dialog-cancel"))
|
||||||
|
{
|
||||||
|
ui->cmdCancel->setIcon(QIcon::fromTheme("dialog-cancel"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("gtk-cancel"))
|
||||||
|
{
|
||||||
|
ui->cmdCancel->setIcon(QIcon::fromTheme("gtk-cancel"));
|
||||||
|
}
|
||||||
|
|
||||||
|
setupTreeWidget();
|
||||||
|
setupLanguageBox();
|
||||||
|
setupRadioButtons();
|
||||||
|
setupDefaultProfile();
|
||||||
|
setupPictureSettings();
|
||||||
|
setupCustomGTAFolder();
|
||||||
|
setupInterfaceSettings();
|
||||||
|
setupStatisticsSettings();
|
||||||
|
setupSnapmaticPictureViewer();
|
||||||
|
setupWindowsGameSettings();
|
||||||
|
|
||||||
|
#ifndef Q_QS_ANDROID
|
||||||
|
// DPI calculation
|
||||||
|
qreal screenRatio = AppEnv::screenRatio();
|
||||||
|
resize(435 * screenRatio, 405 * screenRatio);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
setWindowTitle(windowTitle().arg(GTA5SYNC_APPSTR));
|
||||||
|
}
|
||||||
|
|
||||||
|
OptionsDialog::~OptionsDialog()
|
||||||
|
{
|
||||||
|
delete settings;
|
||||||
|
qDeleteAll(playerItems.begin(), playerItems.end());
|
||||||
|
playerItems.clear();
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionsDialog::setupTreeWidget()
|
||||||
|
{
|
||||||
|
for (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();
|
||||||
|
currentAreaLanguage = settings->value("AreaLanguage", "Auto").toString();
|
||||||
|
settings->endGroup();
|
||||||
|
|
||||||
|
QString cbSysStr = tr("%1 (Language priority)", "First language a person can talk with a different person/application. \"Native\" or \"Not Native\".").arg(tr("System",
|
||||||
|
"System in context of System default"));
|
||||||
|
#ifdef GTA5SYNC_WIN
|
||||||
|
QString cbAutoStr;
|
||||||
|
if (AppEnv::getGameLanguage(AppEnv::getGameVersion()) != GameLanguage::Undefined)
|
||||||
|
{
|
||||||
|
cbAutoStr = tr("%1 (Game language)", "Next closest language compared to the Game settings").arg(tr("Auto", "Automatic language choice."));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cbAutoStr = tr("%1 (Closest to Interface)", "Next closest language compared to the Interface").arg(tr("Auto", "Automatic language choice."));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
QString cbAutoStr = tr("%1 (Closest to Interface)", "Next closest language compared to the Interface").arg(tr("Auto", "Automatic language choice."));
|
||||||
|
#endif
|
||||||
|
ui->cbLanguage->addItem(cbSysStr, "System");
|
||||||
|
ui->cbAreaLanguage->addItem(cbAutoStr, "Auto");
|
||||||
|
|
||||||
|
QStringList availableLanguages;
|
||||||
|
availableLanguages << QString("en_GB");
|
||||||
|
#ifndef GTA5SYNC_QCONF
|
||||||
|
availableLanguages << TranslationClass::listTranslations(AppEnv::getExLangFolder());
|
||||||
|
#endif
|
||||||
|
availableLanguages << TranslationClass::listTranslations(AppEnv::getInLangFolder());
|
||||||
|
availableLanguages.removeDuplicates();
|
||||||
|
availableLanguages.sort();
|
||||||
|
|
||||||
|
for (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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString aCurrentLanguage = QString("en_GB");
|
||||||
|
if (Translator->isLanguageLoaded()) { aCurrentLanguage = Translator->getCurrentLanguage(); }
|
||||||
|
QLocale currentLocale = QLocale(aCurrentLanguage);
|
||||||
|
ui->labCurrentLanguage->setText(tr("Current: %1").arg(currentLocale.nativeLanguageName() % " (" % currentLocale.nativeCountryName() % ") [" % aCurrentLanguage % "]"));
|
||||||
|
|
||||||
|
availableLanguages.clear();
|
||||||
|
availableLanguages << TranslationClass::listAreaTranslations();
|
||||||
|
availableLanguages.removeDuplicates();
|
||||||
|
availableLanguages.sort();
|
||||||
|
|
||||||
|
for (QString lang : availableLanguages)
|
||||||
|
{
|
||||||
|
// correcting Language Location if possible
|
||||||
|
QString aLang = lang;
|
||||||
|
if (QFile::exists(":/global/global." % lang % ".loc"))
|
||||||
|
{
|
||||||
|
QFile locFile(":/global/global." % lang % ".loc");
|
||||||
|
if (locFile.open(QFile::ReadOnly))
|
||||||
|
{
|
||||||
|
aLang = QString::fromUtf8(locFile.readLine()).trimmed();
|
||||||
|
locFile.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QLocale langLocale(aLang);
|
||||||
|
QString cbLangStr = langLocale.nativeLanguageName() % " (" % langLocale.nativeCountryName() % ") [" % aLang % "]";
|
||||||
|
QString langIconStr = "flag-" % TranslationClass::getCountryCode(langLocale);
|
||||||
|
|
||||||
|
ui->cbAreaLanguage->addItem(QIcon::fromTheme(langIconStr), cbLangStr, lang);
|
||||||
|
if (currentAreaLanguage == lang)
|
||||||
|
{
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
ui->cbAreaLanguage->setCurrentText(cbLangStr);
|
||||||
|
#else
|
||||||
|
int indexOfLang = ui->cbAreaLanguage->findText(cbLangStr);
|
||||||
|
ui->cbAreaLanguage->setCurrentIndex(indexOfLang);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString aCurrentAreaLanguage = Translator->getCurrentAreaLanguage();
|
||||||
|
if (QFile::exists(":/global/global." % aCurrentAreaLanguage % ".loc"))
|
||||||
|
{
|
||||||
|
qDebug() << "locFile found";
|
||||||
|
QFile locFile(":/global/global." % aCurrentAreaLanguage % ".loc");
|
||||||
|
if (locFile.open(QFile::ReadOnly))
|
||||||
|
{
|
||||||
|
aCurrentAreaLanguage = QString::fromUtf8(locFile.readLine()).trimmed();
|
||||||
|
locFile.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentLocale = QLocale(aCurrentAreaLanguage);
|
||||||
|
ui->labCurrentAreaLanguage->setText(tr("Current: %1").arg(currentLocale.nativeLanguageName() % " (" % currentLocale.nativeCountryName() % ") [" % aCurrentAreaLanguage % "]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionsDialog::setupRadioButtons()
|
||||||
|
{
|
||||||
|
bool contentModeOk;
|
||||||
|
settings->beginGroup("Profile");
|
||||||
|
contentMode = settings->value("ContentMode", 0).toInt(&contentModeOk);
|
||||||
|
settings->endGroup();
|
||||||
|
|
||||||
|
if (contentModeOk)
|
||||||
|
{
|
||||||
|
switch (contentMode)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
ui->rbOpenWithSC->setChecked(true);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
ui->rbOpenWithDC->setChecked(true);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
ui->rbSelectWithSC->setChecked(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionsDialog::setupInterfaceSettings()
|
||||||
|
{
|
||||||
|
settings->beginGroup("Startup");
|
||||||
|
bool alwaysUseMessageFont = settings->value("AlwaysUseMessageFont", false).toBool();
|
||||||
|
ui->cbAlwaysUseMessageFont->setChecked(alwaysUseMessageFont);
|
||||||
|
#ifdef GTA5SYNC_WIN
|
||||||
|
if (QSysInfo::windowsVersion() >= 0x0080)
|
||||||
|
{
|
||||||
|
ui->gbFont->setVisible(false);
|
||||||
|
ui->cbAlwaysUseMessageFont->setVisible(false);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ui->gbFont->setVisible(false);
|
||||||
|
ui->cbAlwaysUseMessageFont->setVisible(false);
|
||||||
|
#endif
|
||||||
|
QString currentStyle = QApplication::style()->objectName();
|
||||||
|
QString appStyle = settings->value("AppStyle", currentStyle).toString();
|
||||||
|
bool customStyle = settings->value("CustomStyle", false).toBool();
|
||||||
|
const QStringList availableStyles = QStyleFactory::keys();
|
||||||
|
ui->cbStyleList->addItems(availableStyles);
|
||||||
|
if (availableStyles.contains(appStyle, Qt::CaseInsensitive))
|
||||||
|
{
|
||||||
|
// use 'for' for select to be sure it's case insensitive
|
||||||
|
int currentIndex = 0;
|
||||||
|
for (QString currentStyleFF : availableStyles)
|
||||||
|
{
|
||||||
|
if (currentStyleFF.toLower() == appStyle.toLower())
|
||||||
|
{
|
||||||
|
ui->cbStyleList->setCurrentIndex(currentIndex);
|
||||||
|
}
|
||||||
|
currentIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (availableStyles.contains(currentStyle, Qt::CaseInsensitive))
|
||||||
|
{
|
||||||
|
int currentIndex = 0;
|
||||||
|
for (QString currentStyleFF : availableStyles)
|
||||||
|
{
|
||||||
|
if (currentStyleFF.toLower() == currentStyle.toLower())
|
||||||
|
{
|
||||||
|
ui->cbStyleList->setCurrentIndex(currentIndex);
|
||||||
|
}
|
||||||
|
currentIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (customStyle)
|
||||||
|
{
|
||||||
|
ui->cbDefaultStyle->setChecked(false);
|
||||||
|
}
|
||||||
|
settings->endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionsDialog::on_cmdOK_clicked()
|
||||||
|
{
|
||||||
|
applySettings();
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionsDialog::applySettings()
|
||||||
|
{
|
||||||
|
settings->beginGroup("Interface");
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
settings->setValue("Language", ui->cbLanguage->currentData());
|
||||||
|
settings->setValue("AreaLanguage", ui->cbAreaLanguage->currentData());
|
||||||
|
#else
|
||||||
|
settings->setValue("Language", ui->cbLanguage->itemData(ui->cbLanguage->currentIndex()));
|
||||||
|
settings->setValue("AreaLanguage", ui->cbAreaLanguage->itemData(ui->cbAreaLanguage->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();
|
||||||
|
|
||||||
|
bool defaultStyle = ui->cbDefaultStyle->isChecked();
|
||||||
|
settings->beginGroup("Startup");
|
||||||
|
if (!defaultStyle)
|
||||||
|
{
|
||||||
|
QString newStyle = ui->cbStyleList->currentText();
|
||||||
|
settings->setValue("CustomStyle", true);
|
||||||
|
settings->setValue("AppStyle", newStyle);
|
||||||
|
QApplication::setStyle(QStyleFactory::create(newStyle));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
settings->setValue("CustomStyle", false);
|
||||||
|
}
|
||||||
|
settings->setValue("AlwaysUseMessageFont", ui->cbAlwaysUseMessageFont->isChecked());
|
||||||
|
settings->endGroup();
|
||||||
|
|
||||||
|
#ifdef GTA5SYNC_TELEMETRY
|
||||||
|
settings->beginGroup("Telemetry");
|
||||||
|
settings->setValue("PushAppConf", ui->cbAppConfigStats->isChecked());
|
||||||
|
settings->setValue("PushUsageData", ui->cbUsageData->isChecked());
|
||||||
|
if (!Telemetry->isStateForced()) { settings->setValue("IsEnabled", ui->cbParticipateStats->isChecked()); }
|
||||||
|
settings->endGroup();
|
||||||
|
Telemetry->refresh();
|
||||||
|
Telemetry->work();
|
||||||
|
if (ui->cbUsageData->isChecked() && Telemetry->canPush())
|
||||||
|
{
|
||||||
|
QJsonDocument jsonDocument;
|
||||||
|
QJsonObject jsonObject;
|
||||||
|
jsonObject["Type"] = "SettingsUpdated";
|
||||||
|
jsonObject["UpdateTime"] = QString::number(QDateTime::currentDateTimeUtc().toTime_t());
|
||||||
|
jsonDocument.setObject(jsonObject);
|
||||||
|
Telemetry->push(TelemetryCategory::PersonalData, jsonDocument);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
bool languageChanged = ui->cbLanguage->currentData().toString() != currentLanguage;
|
||||||
|
bool languageAreaChanged = ui->cbAreaLanguage->currentData().toString() != currentAreaLanguage;
|
||||||
|
#else
|
||||||
|
bool languageChanged = ui->cbLanguage->itemData(ui->cbLanguage->currentIndex()).toString() != currentLanguage;
|
||||||
|
bool languageAreaChanged = ui->cbAreaLanguage->itemData(ui->cbLanguage->currentIndex()).toString() != currentAreaLanguage;
|
||||||
|
#endif
|
||||||
|
if (languageChanged)
|
||||||
|
{
|
||||||
|
Translator->unloadTranslation(qApp);
|
||||||
|
Translator->initUserLanguage();
|
||||||
|
Translator->loadTranslation(qApp);
|
||||||
|
}
|
||||||
|
else if (languageAreaChanged)
|
||||||
|
{
|
||||||
|
Translator->initUserLanguage();
|
||||||
|
}
|
||||||
|
|
||||||
|
settings->sync();
|
||||||
|
emit settingsApplied(newContentMode, languageChanged);
|
||||||
|
|
||||||
|
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(const QStringList &profiles)
|
||||||
|
{
|
||||||
|
for (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::setupStatisticsSettings()
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_TELEMETRY
|
||||||
|
ui->cbParticipateStats->setText(tr("Participate in %1 User Statistics").arg(GTA5SYNC_APPSTR));
|
||||||
|
ui->labUserStats->setText(QString("<a href=\"%2\">%1</a>").arg(tr("View %1 User Statistics Online").arg(GTA5SYNC_APPSTR), TelemetryClass::getWebURL().toString()));
|
||||||
|
|
||||||
|
settings->beginGroup("Telemetry");
|
||||||
|
ui->cbParticipateStats->setChecked(Telemetry->isEnabled());
|
||||||
|
ui->cbAppConfigStats->setChecked(settings->value("PushAppConf", false).toBool());
|
||||||
|
ui->cbUsageData->setChecked(settings->value("PushUsageData", false).toBool());
|
||||||
|
settings->endGroup();
|
||||||
|
|
||||||
|
if (Telemetry->isStateForced())
|
||||||
|
{
|
||||||
|
ui->cbParticipateStats->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Telemetry->isRegistered())
|
||||||
|
{
|
||||||
|
ui->labParticipationID->setText(tr("Participation ID: %1").arg(Telemetry->getRegisteredID()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->labParticipationID->setText(tr("Participation ID: %1").arg(tr("Not registered")));
|
||||||
|
ui->cmdCopyStatsID->setVisible(false);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->tabStats));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionsDialog::setupWindowsGameSettings()
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_GAME
|
||||||
|
GameVersion gameVersion = AppEnv::getGameVersion();
|
||||||
|
#ifdef GTA5SYNC_WIN
|
||||||
|
if (gameVersion != GameVersion::NoVersion)
|
||||||
|
{
|
||||||
|
if (gameVersion == GameVersion::SocialClubVersion)
|
||||||
|
{
|
||||||
|
ui->gbSteam->setDisabled(true);
|
||||||
|
ui->labSocialClubFound->setText(tr("Found: %1").arg(QString("<span style=\"color: green\">%1</span>").arg(tr("Yes"))));
|
||||||
|
ui->labSteamFound->setText(tr("Found: %1").arg(QString("<span style=\"color: red\">%1</span>").arg(tr("No"))));
|
||||||
|
if (AppEnv::getGameLanguage(GameVersion::SocialClubVersion) != GameLanguage::Undefined)
|
||||||
|
{
|
||||||
|
ui->labSocialClubLanguage->setText(tr("Language: %1").arg(QLocale(AppEnv::gameLanguageToString(AppEnv::getGameLanguage(GameVersion::SocialClubVersion))).nativeLanguageName()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->labSocialClubLanguage->setText(tr("Language: %1").arg(tr("OS defined")));
|
||||||
|
}
|
||||||
|
ui->labSteamLanguage->setVisible(false);
|
||||||
|
}
|
||||||
|
else if (gameVersion == GameVersion::SteamVersion)
|
||||||
|
{
|
||||||
|
ui->gbSocialClub->setDisabled(true);
|
||||||
|
ui->labSocialClubFound->setText(tr("Found: %1").arg(QString("<span style=\"color: red\">%1</span>").arg(tr("No"))));
|
||||||
|
ui->labSteamFound->setText(tr("Found: %1").arg(QString("<span style=\"color: green\">%1</span>").arg(tr("Yes"))));
|
||||||
|
ui->labSocialClubLanguage->setVisible(false);
|
||||||
|
if (AppEnv::getGameLanguage(GameVersion::SteamVersion) != GameLanguage::Undefined)
|
||||||
|
{
|
||||||
|
ui->labSteamLanguage->setText(tr("Language: %1").arg(QLocale(AppEnv::gameLanguageToString(AppEnv::getGameLanguage(GameVersion::SteamVersion))).nativeLanguageName()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->labSteamLanguage->setText(tr("Language: %1").arg(tr("Steam defined")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->labSocialClubFound->setText(tr("Found: %1").arg(QString("<span style=\"color: green\">%1</span>").arg(tr("Yes"))));
|
||||||
|
ui->labSteamFound->setText(tr("Found: %1").arg(QString("<span style=\"color: green\">%1</span>").arg(tr("Yes"))));
|
||||||
|
if (AppEnv::getGameLanguage(GameVersion::SocialClubVersion) != GameLanguage::Undefined)
|
||||||
|
{
|
||||||
|
ui->labSocialClubLanguage->setText(tr("Language: %1").arg(QLocale(AppEnv::gameLanguageToString(AppEnv::getGameLanguage(GameVersion::SocialClubVersion))).nativeLanguageName()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->labSocialClubLanguage->setText(tr("Language: %1").arg(tr("OS defined")));
|
||||||
|
}
|
||||||
|
if (AppEnv::getGameLanguage(GameVersion::SteamVersion) != GameLanguage::Undefined)
|
||||||
|
{
|
||||||
|
ui->labSteamLanguage->setText(tr("Language: %1").arg(QLocale(AppEnv::gameLanguageToString(AppEnv::getGameLanguage(GameVersion::SteamVersion))).nativeLanguageName()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->labSteamLanguage->setText(tr("Language: %1").arg(tr("Steam defined")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->tabGame));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->tabGame));
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->tabGame));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
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", true).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 RDR 2 Folder..."), StandardPaths::documentsLocation(), QFileDialog::ShowDirsOnly);
|
||||||
|
if (QFileInfo(GTAV_Folder).exists())
|
||||||
|
{
|
||||||
|
ui->txtFolder->setText(GTAV_Folder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionsDialog::on_cbDefaultStyle_toggled(bool checked)
|
||||||
|
{
|
||||||
|
ui->cbStyleList->setDisabled(checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionsDialog::on_cmdCopyStatsID_clicked()
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_TELEMETRY
|
||||||
|
QApplication::clipboard()->setText(Telemetry->getRegisteredID());
|
||||||
|
#endif
|
||||||
|
}
|
86
OptionsDialog.h
Normal file
86
OptionsDialog.h
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 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(const 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();
|
||||||
|
void on_cbDefaultStyle_toggled(bool checked);
|
||||||
|
void on_cmdCopyStatsID_clicked();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void settingsApplied(int contentMode, bool languageChanged);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ProfileDatabase *profileDB;
|
||||||
|
Ui::OptionsDialog *ui;
|
||||||
|
QList<QTreeWidgetItem*> playerItems;
|
||||||
|
Qt::AspectRatioMode aspectRatio;
|
||||||
|
QString currentAreaLanguage;
|
||||||
|
QString currentLanguage;
|
||||||
|
QString currentCFolder;
|
||||||
|
QString defaultProfile;
|
||||||
|
QString percentString;
|
||||||
|
QSettings *settings;
|
||||||
|
bool withoutPlayers;
|
||||||
|
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 setupInterfaceSettings();
|
||||||
|
void setupStatisticsSettings();
|
||||||
|
void setupSnapmaticPictureViewer();
|
||||||
|
void setupWindowsGameSettings();
|
||||||
|
void applySettings();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // OPTIONSDIALOG_H
|
789
OptionsDialog.ui
Normal file
789
OptionsDialog.ui
Normal file
|
@ -0,0 +1,789 @@
|
||||||
|
<?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>474</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 RDR 2 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="vsPictures">
|
||||||
|
<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="tabGame">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Game</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="vlGame">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="gbSocialClub">
|
||||||
|
<property name="title">
|
||||||
|
<string>Social Club Version</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="vlGameSocialClub">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="labSocialClubFound">
|
||||||
|
<property name="text">
|
||||||
|
<string>Found: %1</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="labSocialClubLanguage">
|
||||||
|
<property name="text">
|
||||||
|
<string>Language: %1</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="gbSteam">
|
||||||
|
<property name="title">
|
||||||
|
<string>Steam Version</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="vlGameSteam">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="labSteamFound">
|
||||||
|
<property name="text">
|
||||||
|
<string>Found: %1</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="labSteamLanguage">
|
||||||
|
<property name="text">
|
||||||
|
<string>Language: %1</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="vsGame">
|
||||||
|
<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="tabStats">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Feedback</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="vlStats">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="gbUserStats">
|
||||||
|
<property name="title">
|
||||||
|
<string>Participation</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="vlUserStats">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="cbParticipateStats">
|
||||||
|
<property name="text">
|
||||||
|
<string>Participate in %1 User Statistics</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="labUserStats">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true"><a href="%2">%1</a></string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="openExternalLinks">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="textInteractionFlags">
|
||||||
|
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="gbCategories">
|
||||||
|
<property name="title">
|
||||||
|
<string>Categories</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="vlCategories">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="cbGeneralStats">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Hardware, Application and OS Specification</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="cbOSLangStats">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>System Language Configuration</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="cbAppConfigStats">
|
||||||
|
<property name="text">
|
||||||
|
<string>Application Configuration</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="cbUsageData">
|
||||||
|
<property name="text">
|
||||||
|
<string>Personal Usage Data</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="gbOther">
|
||||||
|
<property name="title">
|
||||||
|
<string>Other</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="vlFeedbackOther">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="hlParticipation">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="labParticipationID">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Participation ID: %1</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="textInteractionFlags">
|
||||||
|
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="cmdCopyStatsID">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Copy</string>
|
||||||
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="vsUserStats">
|
||||||
|
<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="tabInterface">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Interface</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="vlInterface">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="gbLanguage">
|
||||||
|
<property name="title">
|
||||||
|
<string>Language for Interface</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="vlLanguage">
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="cbLanguage"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="labCurrentLanguage">
|
||||||
|
<property name="text">
|
||||||
|
<string>Current: %1</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="gbAreas">
|
||||||
|
<property name="title">
|
||||||
|
<string>Language for Areas</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="vlAreas">
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="cbAreaLanguage"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="labCurrentAreaLanguage">
|
||||||
|
<property name="text">
|
||||||
|
<string>Current: %1</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="gbStyle">
|
||||||
|
<property name="title">
|
||||||
|
<string>Style</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="vlStyle">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="cbDefaultStyle">
|
||||||
|
<property name="text">
|
||||||
|
<string>Use Default Style (Restart)</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="hlStyle">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="labStyle">
|
||||||
|
<property name="text">
|
||||||
|
<string>Style:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="cbStyleList">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="gbFont">
|
||||||
|
<property name="title">
|
||||||
|
<string>Font</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="vlFont">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="cbAlwaysUseMessageFont">
|
||||||
|
<property name="text">
|
||||||
|
<string>Always use Message Font (Windows 2003 and earlier)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</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>
|
||||||
|
</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>
|
1069
PictureDialog.cpp
Normal file
1069
PictureDialog.cpp
Normal file
File diff suppressed because it is too large
Load diff
147
PictureDialog.h
Normal file
147
PictureDialog.h
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 PICTUREDIALOG_H
|
||||||
|
#define PICTUREDIALOG_H
|
||||||
|
|
||||||
|
#include "SnapmaticPicture.h"
|
||||||
|
#include "ProfileDatabase.h"
|
||||||
|
#include "CrewDatabase.h"
|
||||||
|
#include <QResizeEvent>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QToolBar>
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QMenu>
|
||||||
|
|
||||||
|
#ifdef GTA5SYNC_WIN
|
||||||
|
#if QT_VERSION >= 0x050200
|
||||||
|
#ifdef GTA5SYNC_APV
|
||||||
|
#include <dwmapi.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class PictureDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PictureDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit PictureDialog(ProfileDatabase *profileDB, CrewDatabase *crewDB, QWidget *parent = 0);
|
||||||
|
explicit PictureDialog(ProfileDatabase *profileDB, CrewDatabase *crewDB, QString profileName, QWidget *parent = 0);
|
||||||
|
explicit PictureDialog(bool primaryWindow, ProfileDatabase *profileDB, CrewDatabase *crewDB, QWidget *parent = 0);
|
||||||
|
explicit PictureDialog(bool primaryWindow, ProfileDatabase *profileDB, CrewDatabase *crewDB, QString profileName, QWidget *parent = 0);
|
||||||
|
void setupPictureDialog();
|
||||||
|
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 styliseDialog();
|
||||||
|
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 editSnapmaticRawJson();
|
||||||
|
void editSnapmaticImage();
|
||||||
|
void renderOverlayPicture();
|
||||||
|
void renderPicture();
|
||||||
|
void openPreviewMap();
|
||||||
|
void updated();
|
||||||
|
void customSignal(QString signal);
|
||||||
|
|
||||||
|
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);
|
||||||
|
#ifdef GTA5SYNC_WIN
|
||||||
|
#if QT_VERSION >= 0x050200
|
||||||
|
#ifdef GTA5SYNC_APV
|
||||||
|
bool nativeEvent(const QByteArray &eventType, void *message, long *result);
|
||||||
|
LRESULT HitTestNCA(HWND hWnd, LPARAM lParam);
|
||||||
|
void resizeEvent(QResizeEvent *event);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString generateCrewString();
|
||||||
|
QString generatePlayersString();
|
||||||
|
bool primaryWindow;
|
||||||
|
ProfileDatabase *profileDB;
|
||||||
|
CrewDatabase *crewDB;
|
||||||
|
QString profileName;
|
||||||
|
Ui::PictureDialog *ui;
|
||||||
|
QMap<QString, QString> globalMap;
|
||||||
|
SnapmaticPicture *smpic;
|
||||||
|
QWidget *fullscreenWidget;
|
||||||
|
QImage avatarAreaPicture;
|
||||||
|
QImage snapmaticPicture;
|
||||||
|
QImage overlayTempImage;
|
||||||
|
QString jsonDrawString;
|
||||||
|
QString windowTitleStr;
|
||||||
|
QString picAreaStr;
|
||||||
|
QString crewStr;
|
||||||
|
bool overlayEnabled;
|
||||||
|
bool rqFullscreen;
|
||||||
|
bool naviEnabled;
|
||||||
|
bool previewMode;
|
||||||
|
bool indexed;
|
||||||
|
int index;
|
||||||
|
int avatarLocX;
|
||||||
|
int avatarLocY;
|
||||||
|
int avatarSize;
|
||||||
|
QMenu *manageMenu;
|
||||||
|
#ifdef GTA5SYNC_WIN
|
||||||
|
#if QT_VERSION >= 0x050200
|
||||||
|
QPoint dragPosition;
|
||||||
|
bool dragStart;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PICTUREDIALOG_H
|
249
PictureDialog.ui
Normal file
249
PictureDialog.ui
Normal file
|
@ -0,0 +1,249 @@
|
||||||
|
<?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>Snapmatic Picture Viewer - %1</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="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/>
|
||||||
|
<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>
|
329
PictureExport.cpp
Normal file
329
PictureExport.cpp
Normal file
|
@ -0,0 +1,329 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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/>.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#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>
|
||||||
|
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
#include <QSaveFile>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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");
|
||||||
|
bool dontUseNativeDialog = settings.value("DontUseNativeDialog", false).toBool();
|
||||||
|
settings.beginGroup("ExportAsPicture");
|
||||||
|
|
||||||
|
fileDialogPreSave: //Work?
|
||||||
|
QFileDialog fileDialog(parent);
|
||||||
|
fileDialog.setFileMode(QFileDialog::AnyFile);
|
||||||
|
fileDialog.setViewMode(QFileDialog::Detail);
|
||||||
|
fileDialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||||
|
fileDialog.setOption(QFileDialog::DontUseNativeDialog, dontUseNativeDialog);
|
||||||
|
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() % "+Geometry", "").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::No == QMessageBox::warning(parent, PictureDialog::tr("Export as Picture"), PictureDialog::tr("Overwrite %1 with current Snapmatic picture?").arg("\""+selectedFile+"\""), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes))
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
int errorId = 0;
|
||||||
|
bool isSaved = false;
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
QSaveFile *picFile = new QSaveFile(selectedFile);
|
||||||
|
#else
|
||||||
|
QFile *picFile = new QFile(selectedFile);
|
||||||
|
#endif
|
||||||
|
if (picFile->open(QIODevice::WriteOnly))
|
||||||
|
{
|
||||||
|
isSaved = exportPicture.save(picFile, saveFileFormat.toStdString().c_str(), useCustomQuality ? customQuality : defaultQuality);
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
if (isSaved)
|
||||||
|
{
|
||||||
|
isSaved = picFile->commit();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errorId = 1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
picFile->close();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errorId = 2;
|
||||||
|
}
|
||||||
|
delete picFile;
|
||||||
|
|
||||||
|
if (!isSaved)
|
||||||
|
{
|
||||||
|
switch (errorId)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
QMessageBox::warning(parent, PictureDialog::tr("Export as Picture"), PictureDialog::tr("Failed to export the picture because the system occurred a write failure"));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
QMessageBox::warning(parent, PictureDialog::tr("Export as Picture"), PictureDialog::tr("Failed to export the picture because the format detection failures"));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
QMessageBox::warning(parent, PictureDialog::tr("Export as Picture"), PictureDialog::tr("Failed to export the picture because the file can't be written"));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
QMessageBox::warning(parent, PictureDialog::tr("Export as Picture"), PictureDialog::tr("Failed to export the picture because of an unknown reason"));
|
||||||
|
}
|
||||||
|
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");
|
||||||
|
bool dontUseNativeDialog = settings.value("DontUseNativeDialog", false).toBool();
|
||||||
|
settings.beginGroup("ExportAsSnapmatic");
|
||||||
|
|
||||||
|
QString adjustedPicPath = picture->getOriginalPictureFileName();
|
||||||
|
|
||||||
|
fileDialogPreSave: //Work?
|
||||||
|
QFileInfo sgdFileInfo(adjustedPicPath);
|
||||||
|
QFileDialog fileDialog(parent);
|
||||||
|
fileDialog.setFileMode(QFileDialog::AnyFile);
|
||||||
|
fileDialog.setViewMode(QFileDialog::Detail);
|
||||||
|
fileDialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||||
|
fileDialog.setOption(QFileDialog::DontUseNativeDialog, dontUseNativeDialog);
|
||||||
|
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("RDR 2 Export (*.r5e)");
|
||||||
|
filters << PictureDialog::tr("RDR 2 Raw Export (*.auto)");
|
||||||
|
filters << PictureDialog::tr("Snapmatic pictures (PRDR*)");
|
||||||
|
fileDialog.setNameFilters(filters);
|
||||||
|
|
||||||
|
QList<QUrl> sidebarUrls = SidebarGenerator::generateSidebarUrls(fileDialog.sidebarUrls());
|
||||||
|
|
||||||
|
fileDialog.setSidebarUrls(sidebarUrls);
|
||||||
|
fileDialog.setDirectory(settings.value("Directory", StandardPaths::documentsLocation()).toString());
|
||||||
|
fileDialog.restoreGeometry(settings.value(parent->objectName() % "+Geometry", "").toByteArray());
|
||||||
|
fileDialog.selectFile(QString(picture->getExportPictureFileName() % ".r5e"));
|
||||||
|
|
||||||
|
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::No == QMessageBox::warning(parent, PictureDialog::tr("Export as Snapmatic"), PictureDialog::tr("Overwrite %1 with current Snapmatic picture?").arg("\""+selectedFile+"\""), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes))
|
||||||
|
{
|
||||||
|
goto fileDialogPreSave; //Work?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedFile.right(4) == ".r5e")
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
}
|
35
PictureExport.h
Normal file
35
PictureExport.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 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
|
109
PictureWidget.cpp
Normal file
109
PictureWidget.cpp
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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/>.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "PictureDialog.h"
|
||||||
|
#include "PictureWidget.h"
|
||||||
|
#include "UiModLabel.h"
|
||||||
|
#include <QDesktopWidget>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
PictureWidget::PictureWidget(QWidget *parent) : QDialog(parent)
|
||||||
|
{
|
||||||
|
installEventFilter(this);
|
||||||
|
|
||||||
|
widgetLayout = new QHBoxLayout(this);
|
||||||
|
widgetLayout->setSpacing(0);
|
||||||
|
widgetLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
pictureLabel = new UiModLabel(this);
|
||||||
|
pictureLabel->setObjectName("pictureLabel");
|
||||||
|
pictureLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
pictureLabel->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
pictureLabel->setAlignment(Qt::AlignCenter);
|
||||||
|
widgetLayout->addWidget(pictureLabel);
|
||||||
|
|
||||||
|
QObject::connect(pictureLabel, SIGNAL(mouseDoubleClicked(Qt::MouseButton)), this, SLOT(pictureDoubleClicked(Qt::MouseButton)));
|
||||||
|
QObject::connect(pictureLabel, SIGNAL(customContextMenuRequested(QPoint)), parent, SLOT(exportCustomContextMenuRequested(QPoint)));
|
||||||
|
QObject::connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(updateWindowSize(int)));
|
||||||
|
|
||||||
|
setLayout(widgetLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
PictureWidget::~PictureWidget()
|
||||||
|
{
|
||||||
|
widgetLayout->removeWidget(pictureLabel);
|
||||||
|
delete pictureLabel;
|
||||||
|
delete widgetLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PictureWidget::eventFilter(QObject *obj, QEvent *ev)
|
||||||
|
{
|
||||||
|
if (obj == this)
|
||||||
|
{
|
||||||
|
if (ev->type() == QEvent::KeyPress)
|
||||||
|
{
|
||||||
|
QKeyEvent *keyEvent = (QKeyEvent*)ev;
|
||||||
|
switch (keyEvent->key()){
|
||||||
|
case Qt::Key_Left:
|
||||||
|
emit previousPictureRequested();
|
||||||
|
break;
|
||||||
|
case Qt::Key_Right:
|
||||||
|
emit nextPictureRequested();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PictureWidget::pictureDoubleClicked(Qt::MouseButton button)
|
||||||
|
{
|
||||||
|
if (button == Qt::LeftButton)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PictureWidget::setImage(QImage image_, QRect rec)
|
||||||
|
{
|
||||||
|
image = image_;
|
||||||
|
pictureLabel->setPixmap(QPixmap::fromImage(image.scaled(rec.width(), rec.height(), Qt::KeepAspectRatio, Qt::SmoothTransformation)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PictureWidget::setImage(QImage image_)
|
||||||
|
{
|
||||||
|
image = image_;
|
||||||
|
pictureLabel->setPixmap(QPixmap::fromImage(image.scaled(geometry().width(), geometry().height(), Qt::KeepAspectRatio, Qt::SmoothTransformation)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PictureWidget::updateWindowSize(int screenID)
|
||||||
|
{
|
||||||
|
if (screenID == QApplication::desktop()->screenNumber(this))
|
||||||
|
{
|
||||||
|
QRect desktopRect = QApplication::desktop()->screenGeometry(this);
|
||||||
|
this->move(desktopRect.x(), desktopRect.y());
|
||||||
|
this->resize(desktopRect.width(), desktopRect.height());
|
||||||
|
this->showFullScreen();
|
||||||
|
pictureLabel->setPixmap(QPixmap::fromImage(image.scaled(desktopRect.width(), desktopRect.height(), Qt::KeepAspectRatio, Qt::SmoothTransformation)));
|
||||||
|
}
|
||||||
|
}
|
56
PictureWidget.h
Normal file
56
PictureWidget.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 PICTUREWIDGET_H
|
||||||
|
#define PICTUREWIDGET_H
|
||||||
|
|
||||||
|
#include "UiModLabel.h"
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QEvent>
|
||||||
|
|
||||||
|
class PictureWidget : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit PictureWidget(QWidget *parent = 0);
|
||||||
|
void setImage(QImage image, QRect rec);
|
||||||
|
~PictureWidget();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void setImage(QImage image);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool eventFilter(QObject *obj, QEvent *ev);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHBoxLayout *widgetLayout;
|
||||||
|
UiModLabel *pictureLabel;
|
||||||
|
QImage image;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void pictureDoubleClicked(Qt::MouseButton button);
|
||||||
|
void updateWindowSize(int screenID);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void nextPictureRequested();
|
||||||
|
void previousPictureRequested();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PICTUREWIDGET_H
|
221
PlayerListDialog.cpp
Normal file
221
PlayerListDialog.cpp
Normal file
|
@ -0,0 +1,221 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 Profile Viewer
|
||||||
|
* Copyright (C) 2016-2018 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 "PlayerListDialog.h"
|
||||||
|
#include "ui_PlayerListDialog.h"
|
||||||
|
#include "AppEnv.h"
|
||||||
|
#include <QFontMetrics>
|
||||||
|
#include <QInputDialog>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
PlayerListDialog::PlayerListDialog(QStringList players, ProfileDatabase *profileDB, QWidget *parent) :
|
||||||
|
QDialog(parent), players(players), profileDB(profileDB),
|
||||||
|
ui(new Ui::PlayerListDialog)
|
||||||
|
{
|
||||||
|
// Set Window Flags
|
||||||
|
setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint);
|
||||||
|
|
||||||
|
listUpdated = false;
|
||||||
|
ui->setupUi(this);
|
||||||
|
ui->cmdCancel->setDefault(true);
|
||||||
|
ui->cmdCancel->setFocus();
|
||||||
|
|
||||||
|
// Set Icon for Apply Button
|
||||||
|
if (QIcon::hasThemeIcon("dialog-ok-apply"))
|
||||||
|
{
|
||||||
|
ui->cmdApply->setIcon(QIcon::fromTheme("dialog-ok-apply"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("dialog-apply"))
|
||||||
|
{
|
||||||
|
ui->cmdApply->setIcon(QIcon::fromTheme("dialog-apply"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("gtk-apply"))
|
||||||
|
{
|
||||||
|
ui->cmdApply->setIcon(QIcon::fromTheme("gtk-apply"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("dialog-ok"))
|
||||||
|
{
|
||||||
|
ui->cmdApply->setIcon(QIcon::fromTheme("dialog-ok"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("gtk-ok"))
|
||||||
|
{
|
||||||
|
ui->cmdApply->setIcon(QIcon::fromTheme("dialog-ok"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Icon for Cancel Button
|
||||||
|
if (QIcon::hasThemeIcon("dialog-cancel"))
|
||||||
|
{
|
||||||
|
ui->cmdCancel->setIcon(QIcon::fromTheme("dialog-cancel"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("gtk-cancel"))
|
||||||
|
{
|
||||||
|
ui->cmdCancel->setIcon(QIcon::fromTheme("gtk-cancel"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Icon for Manage Buttons
|
||||||
|
if (QIcon::hasThemeIcon("go-previous") && QIcon::hasThemeIcon("go-next") && QIcon::hasThemeIcon("list-add"))
|
||||||
|
{
|
||||||
|
ui->cmdMakeAv->setIcon(QIcon::fromTheme("go-previous"));
|
||||||
|
ui->cmdMakeSe->setIcon(QIcon::fromTheme("go-next"));
|
||||||
|
ui->cmdMakeAd->setIcon(QIcon::fromTheme("list-add"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->cmdMakeAv->setIcon(QIcon(":/img/back.svgz"));
|
||||||
|
ui->cmdMakeSe->setIcon(QIcon(":/img/next.svgz"));
|
||||||
|
ui->cmdMakeAd->setIcon(QIcon(":/img/add.svgz"));
|
||||||
|
}
|
||||||
|
buildInterface();
|
||||||
|
|
||||||
|
// DPI calculation
|
||||||
|
qreal screenRatio = AppEnv::screenRatio();
|
||||||
|
resize(500 * screenRatio, 350 * screenRatio);
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerListDialog::~PlayerListDialog()
|
||||||
|
{
|
||||||
|
for (QObject *object : ui->listAvPlayers->children())
|
||||||
|
{
|
||||||
|
delete object;
|
||||||
|
}
|
||||||
|
for (QObject *object : ui->listSePlayers->children())
|
||||||
|
{
|
||||||
|
delete object;
|
||||||
|
}
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerListDialog::on_cmdCancel_clicked()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerListDialog::buildInterface()
|
||||||
|
{
|
||||||
|
const QStringList dbPlayers = profileDB->getPlayers();
|
||||||
|
for (QString sePlayer : players)
|
||||||
|
{
|
||||||
|
QListWidgetItem *playerItem = new QListWidgetItem(profileDB->getPlayerName(sePlayer));
|
||||||
|
playerItem->setData(Qt::UserRole, sePlayer);
|
||||||
|
ui->listSePlayers->addItem(playerItem);
|
||||||
|
}
|
||||||
|
for (QString dbPlayer : dbPlayers)
|
||||||
|
{
|
||||||
|
if (!players.contains(dbPlayer))
|
||||||
|
{
|
||||||
|
QListWidgetItem *playerItem = new QListWidgetItem(profileDB->getPlayerName(dbPlayer));
|
||||||
|
playerItem->setData(Qt::UserRole, dbPlayer);
|
||||||
|
ui->listAvPlayers->addItem(playerItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ui->listAvPlayers->sortItems(Qt::AscendingOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerListDialog::on_cmdMakeAv_clicked()
|
||||||
|
{
|
||||||
|
for (QListWidgetItem *item : ui->listSePlayers->selectedItems())
|
||||||
|
{
|
||||||
|
QString playerName = item->text();
|
||||||
|
int playerID = item->data(Qt::UserRole).toInt();
|
||||||
|
delete item;
|
||||||
|
QListWidgetItem *playerItem = new QListWidgetItem(playerName);
|
||||||
|
playerItem->setData(Qt::UserRole, playerID);
|
||||||
|
ui->listAvPlayers->addItem(playerItem);
|
||||||
|
ui->listAvPlayers->sortItems(Qt::AscendingOrder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerListDialog::on_cmdMakeSe_clicked()
|
||||||
|
{
|
||||||
|
int maxPlayers = 30;
|
||||||
|
if (maxPlayers < ui->listSePlayers->count() + ui->listAvPlayers->selectedItems().count())
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Add Players..."), tr("Failed to add more Players because the limit of Players are %1!").arg(QString::number(maxPlayers)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (QListWidgetItem *item : ui->listAvPlayers->selectedItems())
|
||||||
|
{
|
||||||
|
QString playerName = item->text();
|
||||||
|
int playerID = item->data(Qt::UserRole).toInt();
|
||||||
|
delete item;
|
||||||
|
QListWidgetItem *playerItem = new QListWidgetItem(playerName);
|
||||||
|
playerItem->setData(Qt::UserRole, playerID);
|
||||||
|
ui->listSePlayers->addItem(playerItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerListDialog::on_cmdMakeAd_clicked()
|
||||||
|
{
|
||||||
|
bool playerOk;
|
||||||
|
int playerID = QInputDialog::getInt(this, tr("Add Player..."), tr("Enter Social Club Player ID"), 1, 1, 214783647, 1, &playerOk, windowFlags());
|
||||||
|
if (playerOk)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ui->listAvPlayers->count(); ++i)
|
||||||
|
{
|
||||||
|
QListWidgetItem *item = ui->listAvPlayers->item(i);
|
||||||
|
QString itemPlayerName = item->text();
|
||||||
|
int itemPlayerID = item->data(Qt::UserRole).toInt();
|
||||||
|
if (itemPlayerID == playerID)
|
||||||
|
{
|
||||||
|
delete item;
|
||||||
|
QListWidgetItem *playerItem = new QListWidgetItem(itemPlayerName);
|
||||||
|
playerItem->setData(Qt::UserRole, playerID);
|
||||||
|
ui->listSePlayers->addItem(playerItem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < ui->listSePlayers->count(); ++i)
|
||||||
|
{
|
||||||
|
QListWidgetItem *item = ui->listSePlayers->item(i);
|
||||||
|
int itemPlayerID = item->data(Qt::UserRole).toInt();
|
||||||
|
if (itemPlayerID == playerID)
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Add Player..."), tr("Failed to add Player %1 because Player %1 is already added!").arg(QString::number(playerID)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QListWidgetItem *playerItem = new QListWidgetItem(QString::number(playerID));
|
||||||
|
playerItem->setData(Qt::UserRole, playerID);
|
||||||
|
ui->listSePlayers->addItem(playerItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerListDialog::on_cmdApply_clicked()
|
||||||
|
{
|
||||||
|
players.clear();
|
||||||
|
for (int i = 0; i < ui->listSePlayers->count(); ++i)
|
||||||
|
{
|
||||||
|
players += ui->listSePlayers->item(i)->data(Qt::UserRole).toString();
|
||||||
|
}
|
||||||
|
emit playerListUpdated(players);
|
||||||
|
listUpdated = true;
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList PlayerListDialog::getPlayerList() const
|
||||||
|
{
|
||||||
|
return players;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PlayerListDialog::isListUpdated()
|
||||||
|
{
|
||||||
|
return listUpdated;
|
||||||
|
}
|
57
PlayerListDialog.h
Normal file
57
PlayerListDialog.h
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 PLAYERLISTDIALOG_H
|
||||||
|
#define PLAYERLISTDIALOG_H
|
||||||
|
|
||||||
|
#include "ProfileDatabase.h"
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class PlayerListDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PlayerListDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit PlayerListDialog(QStringList players, ProfileDatabase *profileDB, QWidget *parent = 0);
|
||||||
|
QStringList getPlayerList() const;
|
||||||
|
bool isListUpdated();
|
||||||
|
~PlayerListDialog();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_cmdCancel_clicked();
|
||||||
|
void on_cmdMakeAv_clicked();
|
||||||
|
void on_cmdMakeSe_clicked();
|
||||||
|
void on_cmdMakeAd_clicked();
|
||||||
|
void on_cmdApply_clicked();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QStringList players;
|
||||||
|
ProfileDatabase *profileDB;
|
||||||
|
Ui::PlayerListDialog *ui;
|
||||||
|
bool listUpdated;
|
||||||
|
void buildInterface();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void playerListUpdated(QStringList playerList);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PLAYERLISTDIALOG_H
|
173
PlayerListDialog.ui
Normal file
173
PlayerListDialog.ui
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>PlayerListDialog</class>
|
||||||
|
<widget class="QDialog" name="PlayerListDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>500</width>
|
||||||
|
<height>350</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Edit Players...</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="vlInterface">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="hlPlayers">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="vlAvPlayers">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="labAvPlayers">
|
||||||
|
<property name="text">
|
||||||
|
<string>Available Players:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="listAvPlayers">
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="vlButtons">
|
||||||
|
<item>
|
||||||
|
<spacer name="vsButtons1">
|
||||||
|
<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="QPushButton" name="cmdMakeSe">
|
||||||
|
<property name="focusPolicy">
|
||||||
|
<enum>Qt::NoFocus</enum>
|
||||||
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="cmdMakeAv">
|
||||||
|
<property name="focusPolicy">
|
||||||
|
<enum>Qt::NoFocus</enum>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="cmdMakeAd">
|
||||||
|
<property name="focusPolicy">
|
||||||
|
<enum>Qt::NoFocus</enum>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="vsButtons2">
|
||||||
|
<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>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="vlSePlayers">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="labSePlayers">
|
||||||
|
<property name="text">
|
||||||
|
<string>Selected Players:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="listSePlayers">
|
||||||
|
<property name="dragDropMode">
|
||||||
|
<enum>QAbstractItemView::InternalMove</enum>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</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>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
85
ProfileDatabase.cpp
Normal file
85
ProfileDatabase.cpp
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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/>.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#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 % "/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(QString playerID)
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&mutex);
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "getPlayerName" << playerID;
|
||||||
|
#endif
|
||||||
|
return profileDB->value(playerID, playerID).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
46
ProfileDatabase.h
Normal file
46
ProfileDatabase.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 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(QString playerID);
|
||||||
|
QString getPlayerName(int playerID);
|
||||||
|
QStringList getPlayers();
|
||||||
|
~ProfileDatabase();
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable QMutex mutex;
|
||||||
|
QSettings *profileDB;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void setPlayerName(int playerID, QString playerName);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PROFILEDATABASE_H
|
2371
ProfileInterface.cpp
Normal file
2371
ProfileInterface.cpp
Normal file
File diff suppressed because it is too large
Load diff
137
ProfileInterface.h
Normal file
137
ProfileInterface.h
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 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 "pcg_basic.h"
|
||||||
|
#include <QProgressDialog>
|
||||||
|
#include <QSpacerItem>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QList>
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class ProfileInterface;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class MassTool : int { Qualify = 0, Players = 1, Crew = 2, Title = 3 };
|
||||||
|
|
||||||
|
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, bool languageChanged);
|
||||||
|
void setupProfileInterface();
|
||||||
|
void massTool(MassTool tool);
|
||||||
|
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 pictureFixed_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;
|
||||||
|
QStringList fixedPictures;
|
||||||
|
QString enabledPicStr;
|
||||||
|
QString profileFolder;
|
||||||
|
QString profileName;
|
||||||
|
QString loadingStr;
|
||||||
|
QString language;
|
||||||
|
pcg32_random_t rng;
|
||||||
|
bool contextMenuOpened;
|
||||||
|
bool isProfileLoaded;
|
||||||
|
int selectedWidgts;
|
||||||
|
int contentMode;
|
||||||
|
|
||||||
|
bool isSupportedImageFile(QString selectedFileName);
|
||||||
|
bool importFile(QString selectedFile, QDateTime importDateTime, bool notMultiple);
|
||||||
|
bool importUrls(const QMimeData *mimeData);
|
||||||
|
bool importRemote(QUrl remoteUrl);
|
||||||
|
bool importImage(QImage *snapmaticImage, QDateTime importDateTime);
|
||||||
|
bool 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();
|
||||||
|
int getRandomUid();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void profileLoaded();
|
||||||
|
void profileClosed();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PROFILEINTERFACE_H
|
244
ProfileInterface.ui
Normal file
244
ProfileInterface.ui
Normal file
|
@ -0,0 +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 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>
|
116
ProfileLoader.cpp
Normal file
116
ProfileLoader.cpp
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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/>.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "ProfileLoader.h"
|
||||||
|
#include "SnapmaticPicture.h"
|
||||||
|
#include "SavegameData.h"
|
||||||
|
#include "CrewDatabase.h"
|
||||||
|
#include <QStringBuilder>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QString>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QList>
|
||||||
|
#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("SRDR*"));
|
||||||
|
QStringList SavegameFiles = profileDir.entryList(QDir::Files | QDir::NoDot, QDir::NoSort);
|
||||||
|
QStringList BackupFiles = SavegameFiles.filter(".bak", Qt::CaseInsensitive);
|
||||||
|
profileDir.setNameFilters(QStringList("PRDR*"));
|
||||||
|
QStringList SnapmaticPics = profileDir.entryList(QDir::Files | QDir::NoDot, QDir::NoSort);
|
||||||
|
BackupFiles += SnapmaticPics.filter(".bak", Qt::CaseInsensitive);
|
||||||
|
|
||||||
|
SavegameFiles.removeDuplicates();
|
||||||
|
SnapmaticPics.removeDuplicates();
|
||||||
|
for (QString BackupFile : BackupFiles)
|
||||||
|
{
|
||||||
|
SavegameFiles.removeAll(BackupFile);
|
||||||
|
SnapmaticPics.removeAll(BackupFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
int maximumV = SavegameFiles.length() + SnapmaticPics.length();
|
||||||
|
|
||||||
|
// Loading pictures and savegames
|
||||||
|
emit loadingProgress(curFile, maximumV);
|
||||||
|
for (QString SavegameFile : SavegameFiles)
|
||||||
|
{
|
||||||
|
emit loadingProgress(curFile, maximumV);
|
||||||
|
QString sgdPath = profileFolder % "/" % SavegameFile;
|
||||||
|
SavegameData *savegame = new SavegameData(sgdPath);
|
||||||
|
if (savegame->readingSavegame())
|
||||||
|
{
|
||||||
|
emit savegameLoaded(savegame, sgdPath);
|
||||||
|
}
|
||||||
|
curFile++;
|
||||||
|
}
|
||||||
|
for (QString SnapmaticPic : SnapmaticPics)
|
||||||
|
{
|
||||||
|
emit loadingProgress(curFile, maximumV);
|
||||||
|
QString picturePath = profileFolder % "/" % SnapmaticPic;
|
||||||
|
SnapmaticPicture *picture = new SnapmaticPicture(picturePath);
|
||||||
|
if (picture->readingPicture(true, true, true))
|
||||||
|
{
|
||||||
|
if (picture->isFormatSwitched())
|
||||||
|
{
|
||||||
|
picture->setSnapmaticFormat(SnapmaticFormat::PGTA_Format);
|
||||||
|
if (picture->exportPicture(picturePath, SnapmaticFormat::PGTA_Format))
|
||||||
|
{
|
||||||
|
emit pictureFixed(picture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emit pictureLoaded(picture);
|
||||||
|
int crewNumber = picture->getSnapmaticProperties().crewID;
|
||||||
|
if (!crewList.contains(crewNumber))
|
||||||
|
{
|
||||||
|
crewList += crewNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
curFile++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// adding found crews
|
||||||
|
crewDB->setAddingCrews(true);
|
||||||
|
for (int crewID : crewList)
|
||||||
|
{
|
||||||
|
crewDB->addCrew(crewID);
|
||||||
|
}
|
||||||
|
crewDB->setAddingCrews(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProfileLoader::preloaded()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProfileLoader::loaded()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
53
ProfileLoader.h
Normal file
53
ProfileLoader.h
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 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 pictureFixed(SnapmaticPicture *picture);
|
||||||
|
void savegameLoaded(SavegameData *savegame, QString savegamePath);
|
||||||
|
void loadingProgress(int value, int maximum);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PROFILELOADER_H
|
66
ProfileWidget.cpp
Normal file
66
ProfileWidget.cpp
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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/>.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
46
ProfileWidget.h
Normal file
46
ProfileWidget.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 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
|
2
README.md
Normal file
2
README.md
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
## rdr2view
|
||||||
|
Red Dead Redemption 2 Savegame and Snapmatic viewer/editor
|
108
SavegameCopy.cpp
Normal file
108
SavegameCopy.cpp
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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/>.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "SidebarGenerator.h"
|
||||||
|
#include "SavegameWidget.h"
|
||||||
|
#include "StandardPaths.h"
|
||||||
|
#include "SavegameCopy.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include <QStringBuilder>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QSettings>
|
||||||
|
|
||||||
|
SavegameCopy::SavegameCopy()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SavegameCopy::copySavegame(QWidget *parent, QString sgdPath)
|
||||||
|
{
|
||||||
|
QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||||
|
|
||||||
|
settings.beginGroup("FileDialogs");
|
||||||
|
bool dontUseNativeDialog = settings.value("DontUseNativeDialog", false).toBool();
|
||||||
|
settings.beginGroup("SavegameCopy");
|
||||||
|
|
||||||
|
fileDialogPreSave: //Work?
|
||||||
|
QFileInfo sgdFileInfo(sgdPath);
|
||||||
|
QFileDialog fileDialog(parent);
|
||||||
|
fileDialog.setFileMode(QFileDialog::AnyFile);
|
||||||
|
fileDialog.setViewMode(QFileDialog::Detail);
|
||||||
|
fileDialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||||
|
fileDialog.setOption(QFileDialog::DontUseNativeDialog, dontUseNativeDialog);
|
||||||
|
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 (SRDR*)");
|
||||||
|
filters << SavegameWidget::tr("All files (**)");
|
||||||
|
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() % "+Geometry", "").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(parent->objectName() % "+Geometry", fileDialog.saveGeometry());
|
||||||
|
settings.setValue("Directory", fileDialog.directory().absolutePath());
|
||||||
|
settings.endGroup();
|
||||||
|
settings.endGroup();
|
||||||
|
}
|
32
SavegameCopy.h
Normal file
32
SavegameCopy.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 SAVEGAMECOPY_H
|
||||||
|
#define SAVEGAMECOPY_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
class SavegameCopy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SavegameCopy();
|
||||||
|
static void copySavegame(QWidget *parent, QString sgdPath);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SAVEGAMECOPY_H
|
121
SavegameData.cpp
Normal file
121
SavegameData.cpp
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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/>.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "SnapmaticPicture.h"
|
||||||
|
#include "StringParser.h"
|
||||||
|
#include "SavegameData.h"
|
||||||
|
#include <QStringBuilder>
|
||||||
|
#include <QTextCodec>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
|
#define savegameHeaderLength 260
|
||||||
|
#define verificationValue QByteArray::fromHex("00000004")
|
||||||
|
|
||||||
|
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," % SnapmaticPicture::convertDrawStringForLog(savegameFileName);
|
||||||
|
saveFile->deleteLater();
|
||||||
|
delete saveFile;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reading Savegame Header
|
||||||
|
if (!saveFile->isReadable())
|
||||||
|
{
|
||||||
|
lastStep = "2;/3,ReadingFile," % SnapmaticPicture::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(0x04));
|
||||||
|
savegameBytes = savegameBytesList.at(1);
|
||||||
|
savegameBytesList.clear();
|
||||||
|
return SnapmaticPicture::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_;
|
||||||
|
}
|
45
SavegameData.h
Normal file
45
SavegameData.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 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
|
100
SavegameDialog.cpp
Normal file
100
SavegameDialog.cpp
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 Profile Viewer
|
||||||
|
* Copyright (C) 2016-2018 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 "SavegameDialog.h"
|
||||||
|
#include "ui_SavegameDialog.h"
|
||||||
|
#include "SavegameCopy.h"
|
||||||
|
#include "AppEnv.h"
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
SavegameDialog::SavegameDialog(QWidget *parent) :
|
||||||
|
QDialog(parent),
|
||||||
|
ui(new Ui::SavegameDialog)
|
||||||
|
{
|
||||||
|
// Set Window Flags
|
||||||
|
setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint);
|
||||||
|
|
||||||
|
// Setup User Interface
|
||||||
|
ui->setupUi(this);
|
||||||
|
ui->cmdClose->setFocus();
|
||||||
|
savegameLabStr = ui->labSavegameText->text();
|
||||||
|
|
||||||
|
// Set Icon for Close Button
|
||||||
|
if (QIcon::hasThemeIcon("dialog-close"))
|
||||||
|
{
|
||||||
|
ui->cmdClose->setIcon(QIcon::fromTheme("dialog-close"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("gtk-close"))
|
||||||
|
{
|
||||||
|
ui->cmdClose->setIcon(QIcon::fromTheme("gtk-close"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Icon for Export Button
|
||||||
|
if (QIcon::hasThemeIcon("document-export"))
|
||||||
|
{
|
||||||
|
ui->cmdCopy->setIcon(QIcon::fromTheme("document-export"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("document-save"))
|
||||||
|
{
|
||||||
|
ui->cmdCopy->setIcon(QIcon::fromTheme("document-save"));
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshWindowSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
SavegameDialog::~SavegameDialog()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SavegameDialog::refreshWindowSize()
|
||||||
|
{
|
||||||
|
// DPI calculation
|
||||||
|
qreal screenRatio = AppEnv::screenRatio();
|
||||||
|
int dpiWindowWidth = 400 * screenRatio;
|
||||||
|
int dpiWindowHeight = 105 * screenRatio;
|
||||||
|
if (dpiWindowHeight < heightForWidth(dpiWindowWidth))
|
||||||
|
{
|
||||||
|
dpiWindowHeight = heightForWidth(dpiWindowWidth);
|
||||||
|
}
|
||||||
|
resize(dpiWindowWidth, dpiWindowHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
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()));
|
||||||
|
refreshWindowSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SavegameDialog::on_cmdClose_clicked()
|
||||||
|
{
|
||||||
|
this->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SavegameDialog::on_cmdCopy_clicked()
|
||||||
|
{
|
||||||
|
SavegameCopy::copySavegame(this, sgdPath);
|
||||||
|
}
|
48
SavegameDialog.h
Normal file
48
SavegameDialog.h
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 Profile Viewer
|
||||||
|
* Copyright (C) 2016-2018 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 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();
|
||||||
|
void refreshWindowSize();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::SavegameDialog *ui;
|
||||||
|
QString savegameLabStr;
|
||||||
|
QString sgdPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SAVEGAMEDIALOG_H
|
93
SavegameDialog.ui
Normal file
93
SavegameDialog.ui
Normal file
|
@ -0,0 +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="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>
|
303
SavegameWidget.cpp
Normal file
303
SavegameWidget.cpp
Normal file
|
@ -0,0 +1,303 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 Profile Viewer
|
||||||
|
* Copyright (C) 2016-2018 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 "config.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>
|
||||||
|
|
||||||
|
#ifdef GTA5SYNC_TELEMETRY
|
||||||
|
#include "TelemetryClass.h"
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QDateTime>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
ui->labSavegamePic->setScaledContents(true);
|
||||||
|
ui->labSavegamePic->setPixmap(QPixmap(":/img/savegame.svgz"));
|
||||||
|
|
||||||
|
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();
|
||||||
|
#ifdef GTA5SYNC_TELEMETRY
|
||||||
|
QSettings telemetrySettings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||||
|
telemetrySettings.beginGroup("Telemetry");
|
||||||
|
bool pushUsageData = telemetrySettings.value("PushUsageData", false).toBool();
|
||||||
|
telemetrySettings.endGroup();
|
||||||
|
if (pushUsageData && Telemetry->canPush())
|
||||||
|
{
|
||||||
|
QJsonDocument jsonDocument;
|
||||||
|
QJsonObject jsonObject;
|
||||||
|
jsonObject["Type"] = "DeleteSuccess";
|
||||||
|
jsonObject["ExtraFlags"] = "Savegame";
|
||||||
|
jsonObject["DeletedTime"] = QString::number(QDateTime::currentDateTimeUtc().toTime_t());
|
||||||
|
jsonDocument.setObject(jsonObject);
|
||||||
|
Telemetry->push(TelemetryCategory::PersonalData, jsonDocument);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (QFile::remove(sgdPath))
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_TELEMETRY
|
||||||
|
QSettings telemetrySettings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||||
|
telemetrySettings.beginGroup("Telemetry");
|
||||||
|
bool pushUsageData = telemetrySettings.value("PushUsageData", false).toBool();
|
||||||
|
telemetrySettings.endGroup();
|
||||||
|
if (pushUsageData && Telemetry->canPush())
|
||||||
|
{
|
||||||
|
QJsonDocument jsonDocument;
|
||||||
|
QJsonObject jsonObject;
|
||||||
|
jsonObject["Type"] = "DeleteSuccess";
|
||||||
|
jsonObject["ExtraFlags"] = "Savegame";
|
||||||
|
jsonObject["DeletedTime"] = QString::number(QDateTime::currentDateTimeUtc().toTime_t());
|
||||||
|
jsonDocument.setObject(jsonObject);
|
||||||
|
Telemetry->push(TelemetryCategory::PersonalData, jsonDocument);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
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";
|
||||||
|
}
|
80
SavegameWidget.h
Normal file
80
SavegameWidget.h
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 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
|
135
SavegameWidget.ui
Normal file
135
SavegameWidget.ui
Normal file
|
@ -0,0 +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>
|
61
SidebarGenerator.cpp
Normal file
61
SidebarGenerator.cpp
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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/>.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
32
SidebarGenerator.h
Normal file
32
SidebarGenerator.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 SIDEBARGENERATOR_H
|
||||||
|
#define SIDEBARGENERATOR_H
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
class SidebarGenerator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SidebarGenerator();
|
||||||
|
static QList<QUrl> generateSidebarUrls(QList<QUrl> sidebarUrls);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SIDEBARGENERATOR_H
|
469
SnapmaticEditor.cpp
Normal file
469
SnapmaticEditor.cpp
Normal file
|
@ -0,0 +1,469 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 Profile Viewer
|
||||||
|
* Copyright (C) 2016-2018 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 "PlayerListDialog.h"
|
||||||
|
#include "StringParser.h"
|
||||||
|
#include "AppEnv.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include <QStringListIterator>
|
||||||
|
#include <QStringBuilder>
|
||||||
|
#include <QTextDocument>
|
||||||
|
#include <QInputDialog>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
|
#ifdef GTA5SYNC_TELEMETRY
|
||||||
|
#include "TelemetryClass.h"
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SnapmaticEditor::SnapmaticEditor(CrewDatabase *crewDB, ProfileDatabase *profileDB, QWidget *parent) :
|
||||||
|
QDialog(parent), crewDB(crewDB), profileDB(profileDB),
|
||||||
|
ui(new Ui::SnapmaticEditor)
|
||||||
|
{
|
||||||
|
// Set Window Flags
|
||||||
|
setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint);
|
||||||
|
|
||||||
|
ui->setupUi(this);
|
||||||
|
ui->cmdCancel->setDefault(true);
|
||||||
|
ui->cmdCancel->setFocus();
|
||||||
|
|
||||||
|
// Set Icon for Apply Button
|
||||||
|
if (QIcon::hasThemeIcon("dialog-ok-apply"))
|
||||||
|
{
|
||||||
|
ui->cmdApply->setIcon(QIcon::fromTheme("dialog-ok-apply"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("dialog-apply"))
|
||||||
|
{
|
||||||
|
ui->cmdApply->setIcon(QIcon::fromTheme("dialog-apply"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("gtk-apply"))
|
||||||
|
{
|
||||||
|
ui->cmdApply->setIcon(QIcon::fromTheme("gtk-apply"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("dialog-ok"))
|
||||||
|
{
|
||||||
|
ui->cmdApply->setIcon(QIcon::fromTheme("dialog-ok"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("gtk-ok"))
|
||||||
|
{
|
||||||
|
ui->cmdApply->setIcon(QIcon::fromTheme("dialog-ok"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Icon for Cancel Button
|
||||||
|
if (QIcon::hasThemeIcon("dialog-cancel"))
|
||||||
|
{
|
||||||
|
ui->cmdCancel->setIcon(QIcon::fromTheme("dialog-cancel"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("gtk-cancel"))
|
||||||
|
{
|
||||||
|
ui->cmdCancel->setIcon(QIcon::fromTheme("gtk-cancel"));
|
||||||
|
}
|
||||||
|
|
||||||
|
snapmaticTitle = QString();
|
||||||
|
smpic = 0;
|
||||||
|
|
||||||
|
#ifndef Q_OS_ANDROID
|
||||||
|
// DPI calculation
|
||||||
|
qreal screenRatio = AppEnv::screenRatio();
|
||||||
|
resize(400 * screenRatio, 360 * screenRatio);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
snapmaticProperties = smpic->getSnapmaticProperties();
|
||||||
|
ui->rbCustom->setChecked(true);
|
||||||
|
crewID = snapmaticProperties.crewID;
|
||||||
|
isSelfie = snapmaticProperties.isSelfie;
|
||||||
|
isMugshot = snapmaticProperties.isMug;
|
||||||
|
isEditor = snapmaticProperties.isFromRSEditor;
|
||||||
|
playersList = snapmaticProperties.playersList;
|
||||||
|
ui->cbDirector->setChecked(snapmaticProperties.isFromDirector);
|
||||||
|
ui->cbMeme->setChecked(snapmaticProperties.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());
|
||||||
|
setSnapmaticPlayers(insertPlayerNames(playersList));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SnapmaticEditor::insertPlayerNames(QStringList *players)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < players->size(); ++i)
|
||||||
|
{
|
||||||
|
players->replace(i, profileDB->getPlayerName(players->at(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList SnapmaticEditor::insertPlayerNames(const QStringList &players)
|
||||||
|
{
|
||||||
|
QStringList playersWI = players;
|
||||||
|
insertPlayerNames(&playersWI);
|
||||||
|
return playersWI;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SnapmaticEditor::setSnapmaticPlayers(const QStringList &players)
|
||||||
|
{
|
||||||
|
QString editStr = QString("<a href=\"g5e://editplayers\" style=\"text-decoration: none;\">%1</a>").arg(tr("Edit"));
|
||||||
|
QString playersStr;
|
||||||
|
if (players.length() != 1)
|
||||||
|
{
|
||||||
|
playersStr = tr("Players: %1 (%2)", "Multiple Player are inserted here");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
playersStr = tr("Player: %1 (%2)", "One Player is inserted here");
|
||||||
|
}
|
||||||
|
if (players.length() != 0)
|
||||||
|
{
|
||||||
|
ui->labPlayers->setText(playersStr.arg(players.join(", "), editStr));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->labPlayers->setText(playersStr.arg(QApplication::translate("PictureDialog", "No Players"), editStr));
|
||||||
|
}
|
||||||
|
#ifndef Q_OS_ANDROID
|
||||||
|
ui->gbValues->resize(ui->gbValues->width(), ui->gbValues->heightForWidth(ui->gbValues->width()));
|
||||||
|
ui->frameWidget->resize(ui->gbValues->width(), ui->frameWidget->heightForWidth(ui->frameWidget->width()));
|
||||||
|
if (heightForWidth(width()) > height()) { resize(width(), heightForWidth(width())); }
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
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</span>").arg(tr("Yes", "Yes, should work fine"))));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->labAppropriate->setText(tr("Appropriate: %1").arg(QString("<span style=\"color: red\">%1</span>").arg(tr("No", "No, could lead to issues"))));
|
||||||
|
}
|
||||||
|
#ifndef Q_OS_ANDROID
|
||||||
|
ui->gbValues->resize(ui->gbValues->width(), ui->gbValues->heightForWidth(ui->gbValues->width()));
|
||||||
|
ui->frameWidget->resize(ui->gbValues->width(), ui->frameWidget->heightForWidth(ui->frameWidget->width()));
|
||||||
|
if (heightForWidth(width()) > height()) { resize(width(), heightForWidth(width())); }
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
#ifndef Q_OS_ANDROID
|
||||||
|
ui->gbValues->resize(ui->gbValues->width(), ui->gbValues->heightForWidth(ui->gbValues->width()));
|
||||||
|
ui->frameWidget->resize(ui->gbValues->width(), ui->frameWidget->heightForWidth(ui->frameWidget->width()));
|
||||||
|
if (heightForWidth(width()) > height()) { resize(width(), heightForWidth(width())); }
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
snapmaticProperties.crewID = crewID;
|
||||||
|
snapmaticProperties.isSelfie = isSelfie;
|
||||||
|
snapmaticProperties.isMug = isMugshot;
|
||||||
|
snapmaticProperties.isFromRSEditor = isEditor;
|
||||||
|
snapmaticProperties.isFromDirector = ui->cbDirector->isChecked();
|
||||||
|
snapmaticProperties.isMeme = ui->cbMeme->isChecked();
|
||||||
|
snapmaticProperties.playersList = playersList;
|
||||||
|
if (smpic)
|
||||||
|
{
|
||||||
|
QString currentFilePath = smpic->getPictureFilePath();
|
||||||
|
QString originalFilePath = smpic->getOriginalPictureFilePath();
|
||||||
|
QString backupFileName = originalFilePath % ".bak";
|
||||||
|
if (!QFile::exists(backupFileName))
|
||||||
|
{
|
||||||
|
QFile::copy(currentFilePath, backupFileName);
|
||||||
|
}
|
||||||
|
SnapmaticProperties fallbackProperties = smpic->getSnapmaticProperties();
|
||||||
|
QString fallbackTitle = smpic->getPictureTitle();
|
||||||
|
smpic->setSnapmaticProperties(snapmaticProperties);
|
||||||
|
smpic->setPictureTitle(snapmaticTitle);
|
||||||
|
if (!smpic->exportPicture(currentFilePath))
|
||||||
|
{
|
||||||
|
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->updateStrings();
|
||||||
|
smpic->emitUpdate();
|
||||||
|
#ifdef GTA5SYNC_TELEMETRY
|
||||||
|
QSettings telemetrySettings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||||
|
telemetrySettings.beginGroup("Telemetry");
|
||||||
|
bool pushUsageData = telemetrySettings.value("PushUsageData", false).toBool();
|
||||||
|
telemetrySettings.endGroup();
|
||||||
|
if (pushUsageData && Telemetry->canPush())
|
||||||
|
{
|
||||||
|
QJsonDocument jsonDocument;
|
||||||
|
QJsonObject jsonObject;
|
||||||
|
jsonObject["Type"] = "PropertyEdited";
|
||||||
|
jsonObject["EditedSize"] = QString::number(smpic->getContentMaxLength());
|
||||||
|
jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toTime_t());
|
||||||
|
jsonDocument.setObject(jsonObject);
|
||||||
|
Telemetry->push(TelemetryCategory::PersonalData, jsonDocument);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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_labPlayers_linkActivated(const QString &link)
|
||||||
|
{
|
||||||
|
if (link == "g5e://editplayers")
|
||||||
|
{
|
||||||
|
PlayerListDialog *playerListDialog = new PlayerListDialog(playersList, profileDB, this);
|
||||||
|
connect(playerListDialog, SIGNAL(playerListUpdated(QStringList)), this, SLOT(playerListUpdated(QStringList)));
|
||||||
|
playerListDialog->setModal(true);
|
||||||
|
playerListDialog->show();
|
||||||
|
playerListDialog->exec();
|
||||||
|
delete playerListDialog;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
for (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;
|
||||||
|
for (QChar crewChar : newCrew)
|
||||||
|
{
|
||||||
|
if (!crewChar.isNumber())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!crewList.contains(newCrew))
|
||||||
|
{
|
||||||
|
crewDB->addCrew(crewID);
|
||||||
|
}
|
||||||
|
crewID = newCrew.toInt();
|
||||||
|
setSnapmaticCrew(returnCrewName(crewID));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SnapmaticEditor::playerListUpdated(QStringList playerList)
|
||||||
|
{
|
||||||
|
playersList = playerList;
|
||||||
|
setSnapmaticPlayers(insertPlayerNames(playerList));
|
||||||
|
}
|
77
SnapmaticEditor.h
Normal file
77
SnapmaticEditor.h
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 SNAPMATICEDITOR_H
|
||||||
|
#define SNAPMATICEDITOR_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include "CrewDatabase.h"
|
||||||
|
#include "ProfileDatabase.h"
|
||||||
|
#include "SnapmaticPicture.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class SnapmaticEditor;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SnapmaticEditor : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit SnapmaticEditor(CrewDatabase *crewDB, ProfileDatabase *profileDB, QWidget *parent = 0);
|
||||||
|
void setSnapmaticPicture(SnapmaticPicture *picture);
|
||||||
|
void setSnapmaticPlayers(const QStringList &players);
|
||||||
|
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_labPlayers_linkActivated(const QString &link);
|
||||||
|
void on_labTitle_linkActivated(const QString &link);
|
||||||
|
void on_labCrew_linkActivated(const QString &link);
|
||||||
|
void playerListUpdated(QStringList playerList);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CrewDatabase *crewDB;
|
||||||
|
ProfileDatabase *profileDB;
|
||||||
|
Ui::SnapmaticEditor *ui;
|
||||||
|
SnapmaticProperties snapmaticProperties;
|
||||||
|
SnapmaticPicture *smpic;
|
||||||
|
QStringList playersList;
|
||||||
|
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();
|
||||||
|
void insertPlayerNames(QStringList *players);
|
||||||
|
QStringList insertPlayerNames(const QStringList &players);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SNAPMATICEDITOR_H
|
276
SnapmaticEditor.ui
Normal file
276
SnapmaticEditor.ui
Normal file
|
@ -0,0 +1,276 @@
|
||||||
|
<?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>381</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="labPlayers">
|
||||||
|
<property name="contextMenuPolicy">
|
||||||
|
<enum>Qt::NoContextMenu</enum>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="textInteractionFlags">
|
||||||
|
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="UiModLabel" name="labCrew">
|
||||||
|
<property name="contextMenuPolicy">
|
||||||
|
<enum>Qt::NoContextMenu</enum>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="textInteractionFlags">
|
||||||
|
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="UiModLabel" name="labTitle">
|
||||||
|
<property name="contextMenuPolicy">
|
||||||
|
<enum>Qt::NoContextMenu</enum>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="textInteractionFlags">
|
||||||
|
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="UiModLabel" name="labAppropriate">
|
||||||
|
<property name="text">
|
||||||
|
<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="toolTip">
|
||||||
|
<string>Apply changes</string>
|
||||||
|
</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="toolTip">
|
||||||
|
<string>Discard changes</string>
|
||||||
|
</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>
|
1435
SnapmaticPicture.cpp
Normal file
1435
SnapmaticPicture.cpp
Normal file
File diff suppressed because it is too large
Load diff
189
SnapmaticPicture.h
Normal file
189
SnapmaticPicture.h
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* gta5spv Grand Theft Auto Snapmatic Picture Viewer
|
||||||
|
* Copyright (C) 2016-2018 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 {
|
||||||
|
double x;
|
||||||
|
double y;
|
||||||
|
double z;
|
||||||
|
};
|
||||||
|
int uid;
|
||||||
|
int size;
|
||||||
|
int crewID;
|
||||||
|
int streetID;
|
||||||
|
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(); // Please use isPictureOk instead
|
||||||
|
void clearCache();
|
||||||
|
QImage getImage(bool fastLoad = false);
|
||||||
|
QByteArray getPictureStream();
|
||||||
|
QString getLastStep(bool readable = true);
|
||||||
|
QString getPictureStr();
|
||||||
|
QString getPictureHead();
|
||||||
|
QString getPictureTitl();
|
||||||
|
QString getPictureDesc();
|
||||||
|
QString getPictureSortStr();
|
||||||
|
QString getPictureFileName();
|
||||||
|
QString getPictureFilePath();
|
||||||
|
QString getExportPictureFileName();
|
||||||
|
QString getOriginalPictureFileName();
|
||||||
|
QString getOriginalPictureFilePath();
|
||||||
|
int getContentMaxLength();
|
||||||
|
bool setImage(const QImage &picture);
|
||||||
|
bool setPictureTitl(const QString &newTitle); // Please use setPictureTitle instead
|
||||||
|
bool setPictureStream(const QByteArray &streamArray);
|
||||||
|
void updateStrings();
|
||||||
|
void emitUpdate();
|
||||||
|
void emitCustomSignal(const QString &signal);
|
||||||
|
|
||||||
|
// FILE MANAGEMENT
|
||||||
|
bool exportPicture(const QString &fileName, SnapmaticFormat format = SnapmaticFormat::Auto_Format);
|
||||||
|
void setPicFileName(const QString &picFileName); // Please use setPictureFileName instead
|
||||||
|
void setPicFilePath(const QString &picFilePath); // Please use setPictureFilePath instead
|
||||||
|
bool deletePicFile(); // Please use deletePictureFile instead
|
||||||
|
|
||||||
|
// JSON
|
||||||
|
bool isJsonOk();
|
||||||
|
QString getJsonStr(); // Please use getPictureJson instead
|
||||||
|
SnapmaticProperties getSnapmaticProperties();
|
||||||
|
bool setSnapmaticProperties(SnapmaticProperties properties);
|
||||||
|
bool setJsonStr(const QString &jsonStr, bool updateProperties = false); // Please use setPictureJson instead
|
||||||
|
|
||||||
|
// VISIBILITY
|
||||||
|
bool isHidden(); // Please use isPictureHidden instead
|
||||||
|
bool isVisible(); // Please use isPictureVisible instead
|
||||||
|
bool setPictureHidden();
|
||||||
|
bool setPictureVisible();
|
||||||
|
|
||||||
|
// ALTERNATIVES (MORE DEVELOPER FRIENDLY FUNCTION CALLS)
|
||||||
|
QString getJsonString() { return getJsonStr(); } // Please use getPictureJson instead
|
||||||
|
QString getPictureJson() { return getJsonStr(); }
|
||||||
|
QString getPictureTitle() { return getPictureTitl(); }
|
||||||
|
QString getPictureString() { return getPictureStr(); }
|
||||||
|
QString getPictureDescription() { return getPictureDesc(); }
|
||||||
|
bool setJsonString(const QString &jsonString, bool updateProperties = false) { return setJsonStr(jsonString, updateProperties); } // Please use setPictureJson instead
|
||||||
|
bool setPictureJson(const QString &json, bool updateProperties = false) { return setJsonStr(json, updateProperties); }
|
||||||
|
bool setPictureTitle(const QString &title) { return setPictureTitl(title); }
|
||||||
|
void setPictureFileName(const QString &fileName) { return setPicFileName(fileName); }
|
||||||
|
void setPictureFilePath(const QString &filePath) { return setPicFilePath(filePath); }
|
||||||
|
bool deletePictureFile() { return deletePicFile(); }
|
||||||
|
bool isPictureOk() { return isPicOk(); }
|
||||||
|
bool isPictureHidden() { return isHidden(); }
|
||||||
|
bool isPictureVisible() { return isVisible(); }
|
||||||
|
bool setHidden() { return setPictureHidden(); } // Please use setPictureHidden instead
|
||||||
|
bool setVisible() { return setPictureVisible(); } // Please use setPictureVisible instead
|
||||||
|
|
||||||
|
// PREDEFINED PROPERTIES
|
||||||
|
QSize getSnapmaticResolution();
|
||||||
|
|
||||||
|
// SNAPMATIC DEFAULTS
|
||||||
|
bool isSnapmaticDefaultsEnforced();
|
||||||
|
void setSnapmaticDefaultsEnforced(bool enforced);
|
||||||
|
|
||||||
|
// SNAPMATIC FORMAT
|
||||||
|
SnapmaticFormat getSnapmaticFormat();
|
||||||
|
void setSnapmaticFormat(SnapmaticFormat format);
|
||||||
|
bool isFormatSwitched();
|
||||||
|
|
||||||
|
// VERIFY CONTENT
|
||||||
|
static bool verifyTitle(const QString &title);
|
||||||
|
|
||||||
|
// STRING OPERATIONS
|
||||||
|
static QString parseTitleString(const QByteArray &commitBytes, int maxLength);
|
||||||
|
static QString convertDrawStringForLog(const QString &inputStr);
|
||||||
|
static QString convertLogStringForDraw(const QString &inputStr);
|
||||||
|
|
||||||
|
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 isFormatSwitch;
|
||||||
|
bool isModernFormat;
|
||||||
|
bool careSnapDefault;
|
||||||
|
int jpegRawContentSize;
|
||||||
|
int jpegRawContentSizeE;
|
||||||
|
|
||||||
|
// PICTURE STREAM
|
||||||
|
QByteArray rawPicContent;
|
||||||
|
|
||||||
|
// JSON
|
||||||
|
void parseJsonContent();
|
||||||
|
bool jsonOk;
|
||||||
|
QString jsonStr;
|
||||||
|
SnapmaticProperties localProperties;
|
||||||
|
|
||||||
|
// VERIFY CONTENT
|
||||||
|
static bool verifyTitleChar(const QChar &titleChar);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void customSignal(QString signal);
|
||||||
|
void preloaded();
|
||||||
|
void updated();
|
||||||
|
void loaded();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SNAPMATICPICTURE_H
|
499
SnapmaticWidget.cpp
Normal file
499
SnapmaticWidget.cpp
Normal file
|
@ -0,0 +1,499 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 Profile Viewer
|
||||||
|
* Copyright (C) 2016-2019 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 "ImageEditorDialog.h"
|
||||||
|
#include "MapLocationDialog.h"
|
||||||
|
#include "JsonEditorDialog.h"
|
||||||
|
#include "SnapmaticPicture.h"
|
||||||
|
#include "SnapmaticEditor.h"
|
||||||
|
#include "DatabaseThread.h"
|
||||||
|
#include "PictureDialog.h"
|
||||||
|
#include "PictureExport.h"
|
||||||
|
#include "StringParser.h"
|
||||||
|
#include "ImportDialog.h"
|
||||||
|
#include "AppEnv.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include <QStringBuilder>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
|
#ifdef GTA5SYNC_TELEMETRY
|
||||||
|
#include "TelemetryClass.h"
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SnapmaticWidget::SnapmaticWidget(ProfileDatabase *profileDB, CrewDatabase *crewDB, DatabaseThread *threadDB, QString profileName, QWidget *parent) :
|
||||||
|
ProfileWidget(parent), profileDB(profileDB), crewDB(crewDB), threadDB(threadDB), profileName(profileName),
|
||||||
|
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()));
|
||||||
|
QObject::connect(picture, SIGNAL(customSignal(QString)), this, SLOT(customSignal(QString)));
|
||||||
|
|
||||||
|
qreal screenRatio = AppEnv::screenRatio();
|
||||||
|
qreal screenRatioPR = AppEnv::screenRatioPR();
|
||||||
|
ui->labPicture->setFixedSize(48 * screenRatio, 27 * screenRatio);
|
||||||
|
|
||||||
|
ui->labPicture->setScaledContents(true);
|
||||||
|
|
||||||
|
QPixmap SnapmaticPixmap = QPixmap::fromImage(picture->getImage().scaled(ui->labPicture->width() * screenRatioPR, ui->labPicture->height() * screenRatioPR, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::AutoColor);
|
||||||
|
#if QT_VERSION >= 0x050600
|
||||||
|
SnapmaticPixmap.setDevicePixelRatio(screenRatioPR);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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::customSignal(QString signal)
|
||||||
|
{
|
||||||
|
if (signal == "PictureUpdated")
|
||||||
|
{
|
||||||
|
QPixmap SnapmaticPixmap = QPixmap::fromImage(smpic->getImage().scaled(ui->labPicture->width(), ui->labPicture->height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::AutoColor);
|
||||||
|
ui->labPicture->setPixmap(SnapmaticPixmap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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", true).toBool();
|
||||||
|
settings.endGroup();
|
||||||
|
|
||||||
|
PictureDialog *picDialog = new PictureDialog(profileDB, crewDB, profileName, 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->styliseDialog();
|
||||||
|
//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->getPictureTitle()+"\""), QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
||||||
|
if (uchoice == QMessageBox::Yes)
|
||||||
|
{
|
||||||
|
if (smpic->deletePictureFile())
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_TELEMETRY
|
||||||
|
QSettings telemetrySettings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||||
|
telemetrySettings.beginGroup("Telemetry");
|
||||||
|
bool pushUsageData = telemetrySettings.value("PushUsageData", false).toBool();
|
||||||
|
telemetrySettings.endGroup();
|
||||||
|
if (pushUsageData && Telemetry->canPush())
|
||||||
|
{
|
||||||
|
QJsonDocument jsonDocument;
|
||||||
|
QJsonObject jsonObject;
|
||||||
|
jsonObject["Type"] = "DeleteSuccess";
|
||||||
|
jsonObject["ExtraFlags"] = "Snapmatic";
|
||||||
|
jsonObject["DeletedSize"] = QString::number(smpic->getContentMaxLength());
|
||||||
|
jsonObject["DeletedTime"] = QString::number(QDateTime::currentDateTimeUtc().toTime_t());
|
||||||
|
jsonDocument.setObject(jsonObject);
|
||||||
|
Telemetry->push(TelemetryCategory::PersonalData, jsonDocument);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Delete picture"), tr("Failed at deleting %1 from your Snapmatic pictures").arg("\""+smpic->getPictureTitle()+"\""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
if (!makePictureHidden())
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, QApplication::translate("UserInterface", "Hide In-game"), QApplication::translate("SnapmaticWidget", "Failed to hide %1 In-game from your Snapmatic pictures").arg("\""+smpic->getPictureTitle()+"\""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SnapmaticWidget::makePictureVisibleSlot()
|
||||||
|
{
|
||||||
|
if (!makePictureVisible())
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, QApplication::translate("UserInterface", "Show In-game"), QApplication::translate("SnapmaticWidget", "Failed to show %1 In-game from your Snapmatic pictures").arg("\""+smpic->getPictureTitle()+"\""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SnapmaticWidget::editSnapmaticProperties()
|
||||||
|
{
|
||||||
|
SnapmaticEditor *snapmaticEditor = new SnapmaticEditor(crewDB, profileDB, this);
|
||||||
|
snapmaticEditor->setSnapmaticPicture(smpic);
|
||||||
|
snapmaticEditor->setModal(true);
|
||||||
|
snapmaticEditor->show();
|
||||||
|
snapmaticEditor->exec();
|
||||||
|
delete snapmaticEditor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SnapmaticWidget::editSnapmaticRawJson()
|
||||||
|
{
|
||||||
|
JsonEditorDialog *jsonEditor = new JsonEditorDialog(smpic, this);
|
||||||
|
jsonEditor->setModal(true);
|
||||||
|
jsonEditor->show();
|
||||||
|
jsonEditor->exec();
|
||||||
|
delete jsonEditor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SnapmaticWidget::editSnapmaticImage()
|
||||||
|
{
|
||||||
|
QImage *currentImage = new QImage(smpic->getImage());
|
||||||
|
ImportDialog *importDialog = new ImportDialog(profileName, this);
|
||||||
|
importDialog->setImage(currentImage);
|
||||||
|
importDialog->enableOverwriteMode();
|
||||||
|
importDialog->setModal(true);
|
||||||
|
importDialog->exec();
|
||||||
|
if (importDialog->isImportAgreed())
|
||||||
|
{
|
||||||
|
const QByteArray previousPicture = smpic->getPictureStream();
|
||||||
|
bool success = smpic->setImage(importDialog->image());
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
QString currentFilePath = smpic->getPictureFilePath();
|
||||||
|
QString originalFilePath = smpic->getOriginalPictureFilePath();
|
||||||
|
QString backupFileName = originalFilePath % ".bak";
|
||||||
|
if (!QFile::exists(backupFileName))
|
||||||
|
{
|
||||||
|
QFile::copy(currentFilePath, backupFileName);
|
||||||
|
}
|
||||||
|
if (!smpic->exportPicture(currentFilePath))
|
||||||
|
{
|
||||||
|
smpic->setPictureStream(previousPicture);
|
||||||
|
QMessageBox::warning(this, QApplication::translate("ImageEditorDialog", "Snapmatic Image Editor"), QApplication::translate("ImageEditorDialog", "Patching of Snapmatic Image failed because of I/O Error"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
smpic->emitCustomSignal("PictureUpdated");
|
||||||
|
#ifdef GTA5SYNC_TELEMETRY
|
||||||
|
QSettings telemetrySettings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||||
|
telemetrySettings.beginGroup("Telemetry");
|
||||||
|
bool pushUsageData = telemetrySettings.value("PushUsageData", false).toBool();
|
||||||
|
telemetrySettings.endGroup();
|
||||||
|
if (pushUsageData && Telemetry->canPush())
|
||||||
|
{
|
||||||
|
QJsonDocument jsonDocument;
|
||||||
|
QJsonObject jsonObject;
|
||||||
|
jsonObject["Type"] = "ImageEdited";
|
||||||
|
jsonObject["ExtraFlags"] = "Interface";
|
||||||
|
jsonObject["EditedSize"] = QString::number(smpic->getContentMaxLength());
|
||||||
|
jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toTime_t());
|
||||||
|
jsonDocument.setObject(jsonObject);
|
||||||
|
Telemetry->push(TelemetryCategory::PersonalData, jsonDocument);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, QApplication::translate("ImageEditorDialog", "Snapmatic Image Editor"), QApplication::translate("ImageEditorDialog", "Patching of Snapmatic Image failed because of Image Error"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete importDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SnapmaticWidget::openMapViewer()
|
||||||
|
{
|
||||||
|
SnapmaticPicture *picture = smpic;
|
||||||
|
MapLocationDialog *mapLocDialog = new MapLocationDialog(picture->getSnapmaticProperties().location.x, picture->getSnapmaticProperties().location.y, this);
|
||||||
|
mapLocDialog->setModal(true);
|
||||||
|
mapLocDialog->show();
|
||||||
|
mapLocDialog->exec();
|
||||||
|
if (mapLocDialog->propUpdated())
|
||||||
|
{
|
||||||
|
// Update Snapmatic Properties
|
||||||
|
SnapmaticProperties localSpJson = picture->getSnapmaticProperties();
|
||||||
|
localSpJson.location.x = mapLocDialog->getXpos();
|
||||||
|
localSpJson.location.y = mapLocDialog->getYpos();
|
||||||
|
localSpJson.location.z = 0;
|
||||||
|
|
||||||
|
// Update Snapmatic Picture
|
||||||
|
QString currentFilePath = picture->getPictureFilePath();
|
||||||
|
QString originalFilePath = picture->getOriginalPictureFilePath();
|
||||||
|
QString backupFileName = originalFilePath % ".bak";
|
||||||
|
if (!QFile::exists(backupFileName))
|
||||||
|
{
|
||||||
|
QFile::copy(currentFilePath, backupFileName);
|
||||||
|
}
|
||||||
|
SnapmaticProperties fallbackProperties = picture->getSnapmaticProperties();
|
||||||
|
picture->setSnapmaticProperties(localSpJson);
|
||||||
|
if (!picture->exportPicture(currentFilePath))
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, SnapmaticEditor::tr("Snapmatic Properties"), SnapmaticEditor::tr("Patching of Snapmatic Properties failed because of I/O Error"));
|
||||||
|
picture->setSnapmaticProperties(fallbackProperties);
|
||||||
|
}
|
||||||
|
#ifdef GTA5SYNC_TELEMETRY
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QSettings telemetrySettings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||||
|
telemetrySettings.beginGroup("Telemetry");
|
||||||
|
bool pushUsageData = telemetrySettings.value("PushUsageData", false).toBool();
|
||||||
|
telemetrySettings.endGroup();
|
||||||
|
if (pushUsageData && Telemetry->canPush())
|
||||||
|
{
|
||||||
|
QJsonDocument jsonDocument;
|
||||||
|
QJsonObject jsonObject;
|
||||||
|
jsonObject["Type"] = "LocationEdited";
|
||||||
|
jsonObject["ExtraFlags"] = "Interface";
|
||||||
|
jsonObject["EditedSize"] = QString::number(picture->getContentMaxLength());
|
||||||
|
jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toTime_t());
|
||||||
|
jsonDocument.setObject(jsonObject);
|
||||||
|
Telemetry->push(TelemetryCategory::PersonalData, jsonDocument);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
delete mapLocDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
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";
|
||||||
|
}
|
103
SnapmaticWidget.h
Normal file
103
SnapmaticWidget.h
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 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, QString profileName, 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 editSnapmaticRawJson();
|
||||||
|
void editSnapmaticImage();
|
||||||
|
void openMapViewer();
|
||||||
|
void snapmaticUpdated();
|
||||||
|
void customSignal(QString signal);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void mouseDoubleClickEvent(QMouseEvent *ev);
|
||||||
|
void mouseReleaseEvent(QMouseEvent *ev);
|
||||||
|
void mousePressEvent(QMouseEvent *ev);
|
||||||
|
void contextMenuEvent(QContextMenuEvent *ev);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ProfileDatabase *profileDB;
|
||||||
|
CrewDatabase *crewDB;
|
||||||
|
DatabaseThread *threadDB;
|
||||||
|
QString profileName;
|
||||||
|
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
|
169
SnapmaticWidget.ui
Normal file
169
SnapmaticWidget.ui
Normal file
|
@ -0,0 +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>
|
128
StandardPaths.cpp
Normal file
128
StandardPaths.cpp
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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/>.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#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
|
||||||
|
}
|
41
StandardPaths.h
Normal file
41
StandardPaths.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 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
|
61
StringParser.cpp
Normal file
61
StringParser.cpp
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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/>.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "StringParser.h"
|
||||||
|
#include <QTextDocument>
|
||||||
|
#include <QLibraryInfo>
|
||||||
|
#include <QTextCodec>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QString>
|
||||||
|
#include <QList>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
|
#ifdef GTA5SYNC_PROJECT
|
||||||
|
#include <QApplication>
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
StringParser::StringParser()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QString StringParser::escapeString(const QString &toEscape)
|
||||||
|
{
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
return toEscape.toHtmlEscaped();
|
||||||
|
#else
|
||||||
|
return Qt::escape(toEscape);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef GTA5SYNC_PROJECT
|
||||||
|
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
|
35
StringParser.h
Normal file
35
StringParser.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 STRINGPARSER_H
|
||||||
|
#define STRINGPARSER_H
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
class StringParser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StringParser();
|
||||||
|
static QString escapeString(const QString &toEscape);
|
||||||
|
#ifdef GTA5SYNC_PROJECT
|
||||||
|
static QString convertBuildedString(const QString &buildedStr);
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // STRINGPARSER_H
|
596
TelemetryClass.cpp
Normal file
596
TelemetryClass.cpp
Normal file
|
@ -0,0 +1,596 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 Profile Viewer
|
||||||
|
* Copyright (C) 2018 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 "TelemetryClassAuthenticator.h"
|
||||||
|
#include "TelemetryClass.h"
|
||||||
|
#include "StandardPaths.h"
|
||||||
|
#include "AppEnv.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
#include <QHttpMultiPart>
|
||||||
|
#include <QStringBuilder>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QSysInfo>
|
||||||
|
#include <QLocale>
|
||||||
|
#include <QBuffer>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
|
#ifndef GTA5SYNC_TELEMETRY_WEBURL
|
||||||
|
#define GTA5SYNC_TELEMETRY_WEBURL ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GTA5SYNC_WIN
|
||||||
|
#include "windows.h"
|
||||||
|
#include "intrin.h"
|
||||||
|
#include "d3d9.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TelemetryClass TelemetryClass::telemetryClassInstance;
|
||||||
|
|
||||||
|
void TelemetryClass::init()
|
||||||
|
{
|
||||||
|
QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||||
|
settings.beginGroup("Telemetry");
|
||||||
|
telemetryEnabled = true;
|
||||||
|
telemetryStateForced = true;
|
||||||
|
QString telemetryLegacyClientID = settings.value("ClientID", QString()).toString();
|
||||||
|
if (telemetryLegacyClientID.isEmpty() || telemetryLegacyClientID == "v2+")
|
||||||
|
{
|
||||||
|
telemetryClientID = QString::fromUtf8(QByteArray::fromBase64(settings.value("Identification", QByteArray()).toByteArray()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QDir dir;
|
||||||
|
dir.mkpath(StandardPaths::dataLocation());
|
||||||
|
dir.setPath(StandardPaths::dataLocation());
|
||||||
|
QString dirPath = dir.absolutePath();
|
||||||
|
QString portLoc = dirPath % "/.ported";
|
||||||
|
bool telemetryPortedKey = settings.value("IsPorted", false).toBool();
|
||||||
|
bool telemetryPortedFile = QFile::exists(portLoc);
|
||||||
|
if (!telemetryPortedKey && !telemetryPortedFile)
|
||||||
|
{
|
||||||
|
QFile portFile(portLoc);
|
||||||
|
if (portFile.open(QFile::WriteOnly))
|
||||||
|
{
|
||||||
|
portFile.write("\n");
|
||||||
|
portFile.flush();
|
||||||
|
}
|
||||||
|
portFile.close();
|
||||||
|
telemetryClientID = telemetryLegacyClientID;
|
||||||
|
settings.setValue("Identification", telemetryLegacyClientID.toUtf8().toBase64());
|
||||||
|
settings.setValue("IsPorted", true);
|
||||||
|
settings.setValue("ClientID", "v2+");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
telemetryClientID = QString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
telemetryPushAppConf = settings.value("PushAppConf", false).toBool();
|
||||||
|
settings.endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TelemetryClass::refresh()
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TelemetryClass::canPush()
|
||||||
|
{
|
||||||
|
if (!isEnabled() || !isRegistered() || !TelemetryClassAuthenticator::havePushURL()) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TelemetryClass::canRegister()
|
||||||
|
{
|
||||||
|
QDir dir;
|
||||||
|
dir.mkpath(StandardPaths::dataLocation());
|
||||||
|
dir.setPath(StandardPaths::dataLocation());
|
||||||
|
QString dirPath = dir.absolutePath();
|
||||||
|
QString regLoc = dirPath % "/.reg";
|
||||||
|
if (QFile::exists(regLoc)) return false;
|
||||||
|
if (!isEnabled() || isRegistered() || !TelemetryClassAuthenticator::haveRegURL()) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TelemetryClass::isEnabled()
|
||||||
|
{
|
||||||
|
return telemetryEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TelemetryClass::isStateForced()
|
||||||
|
{
|
||||||
|
return telemetryStateForced;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TelemetryClass::isRegistered()
|
||||||
|
{
|
||||||
|
return !telemetryClientID.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString TelemetryClass::getRegisteredID()
|
||||||
|
{
|
||||||
|
return telemetryClientID;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TelemetryClass::setEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
telemetryEnabled = enabled;
|
||||||
|
telemetryStateForced = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TelemetryClass::setDisabled(bool disabled)
|
||||||
|
{
|
||||||
|
telemetryEnabled = !disabled;
|
||||||
|
telemetryStateForced = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TelemetryClass::push(TelemetryCategory category)
|
||||||
|
{
|
||||||
|
if (!canPush()) return;
|
||||||
|
switch (category)
|
||||||
|
{
|
||||||
|
case TelemetryCategory::OperatingSystemSpec:
|
||||||
|
push(category, getOperatingSystem());
|
||||||
|
break;
|
||||||
|
case TelemetryCategory::HardwareSpec:
|
||||||
|
push(category, getSystemHardware());
|
||||||
|
break;
|
||||||
|
case TelemetryCategory::UserLocaleData:
|
||||||
|
push(category, getSystemLocaleList());
|
||||||
|
break;
|
||||||
|
case TelemetryCategory::ApplicationConf:
|
||||||
|
push(category, getApplicationConf());
|
||||||
|
break;
|
||||||
|
case TelemetryCategory::ApplicationSpec:
|
||||||
|
push(category, getApplicationSpec());
|
||||||
|
break;
|
||||||
|
case TelemetryCategory::UserFeedback:
|
||||||
|
break;
|
||||||
|
case TelemetryCategory::PersonalData:
|
||||||
|
break;
|
||||||
|
case TelemetryCategory::CustomEmitted:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TelemetryClass::push(TelemetryCategory category, QJsonDocument json)
|
||||||
|
{
|
||||||
|
if (!canPush()) return;
|
||||||
|
|
||||||
|
QJsonDocument jsonDocument(json);
|
||||||
|
QJsonObject jsonObject = jsonDocument.object();
|
||||||
|
jsonObject["ClientID"] = telemetryClientID;
|
||||||
|
jsonDocument.setObject(jsonObject);
|
||||||
|
|
||||||
|
QHttpMultiPart *httpMultiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
|
||||||
|
|
||||||
|
QHttpPart categoryPart;
|
||||||
|
categoryPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"json-category\""));
|
||||||
|
categoryPart.setBody(categoryToString(category).toUtf8());
|
||||||
|
|
||||||
|
QHttpPart jsonPart;
|
||||||
|
jsonPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
|
||||||
|
jsonPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"json-deflated\""));
|
||||||
|
jsonPart.setBody(qCompress(jsonDocument.toJson(QJsonDocument::Compact)));
|
||||||
|
|
||||||
|
httpMultiPart->append(categoryPart);
|
||||||
|
httpMultiPart->append(jsonPart);
|
||||||
|
|
||||||
|
QNetworkAccessManager *netManager = new QNetworkAccessManager();
|
||||||
|
QNetworkRequest netRequest(TelemetryClassAuthenticator::getTrackingPushURL());
|
||||||
|
netRequest.setRawHeader("User-Agent", AppEnv::getUserAgent());
|
||||||
|
QNetworkReply *netReply = netManager->post(netRequest, httpMultiPart);
|
||||||
|
httpMultiPart->setParent(netReply);
|
||||||
|
|
||||||
|
connect(netManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(pushFinished(QNetworkReply*)));
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonDocument TelemetryClass::getOperatingSystem()
|
||||||
|
{
|
||||||
|
QJsonDocument jsonDocument;
|
||||||
|
QJsonObject jsonObject;
|
||||||
|
#if QT_VERSION >= 0x050400
|
||||||
|
jsonObject["KernelType"] = QSysInfo::kernelType();
|
||||||
|
jsonObject["KernelVersion"] = QSysInfo::kernelVersion();
|
||||||
|
jsonObject["ProductType"] = QSysInfo::productType();
|
||||||
|
jsonObject["ProductVersion"] = QSysInfo::productVersion();
|
||||||
|
jsonObject["OSName"] = QSysInfo::prettyProductName();
|
||||||
|
jsonObject["OSArch"] = QSysInfo::currentCpuArchitecture();
|
||||||
|
#endif
|
||||||
|
jsonDocument.setObject(jsonObject);
|
||||||
|
return jsonDocument;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonDocument TelemetryClass::getSystemHardware()
|
||||||
|
{
|
||||||
|
QJsonDocument jsonDocument;
|
||||||
|
QJsonObject jsonObject;
|
||||||
|
#ifdef GTA5SYNC_WIN
|
||||||
|
{
|
||||||
|
int CPUInfo[4] = {-1};
|
||||||
|
unsigned nExIds, ic = 0;
|
||||||
|
char CPUBrandString[0x40];
|
||||||
|
__cpuid(CPUInfo, 0x80000000);
|
||||||
|
nExIds = CPUInfo[0];
|
||||||
|
for (ic = 0x80000000; ic <= nExIds; ic++)
|
||||||
|
{
|
||||||
|
__cpuid(CPUInfo, ic);
|
||||||
|
if (ic == 0x80000002) { memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo)); }
|
||||||
|
else if (ic == 0x80000003) { memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo)); }
|
||||||
|
else if (ic == 0x80000004) { memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo)); }
|
||||||
|
}
|
||||||
|
jsonObject["CPUName"] = QString::fromLatin1(CPUBrandString).simplified();
|
||||||
|
SYSTEM_INFO sysInfo;
|
||||||
|
GetSystemInfo(&sysInfo);
|
||||||
|
jsonObject["CPUThreads"] = QString::number(sysInfo.dwNumberOfProcessors);
|
||||||
|
MEMORYSTATUSEX statex;
|
||||||
|
statex.dwLength = sizeof(statex);
|
||||||
|
GlobalMemoryStatusEx(&statex);
|
||||||
|
jsonObject["SystemRAM"] = QString(QString::number((statex.ullTotalPhys / 1024) / 1024) % "MB");
|
||||||
|
QStringList gpusList;
|
||||||
|
IDirect3D9 *pD3D = Direct3DCreate9(D3D_SDK_VERSION);
|
||||||
|
int adapters = pD3D->GetAdapterCount();
|
||||||
|
for (int ia = 0; ia < adapters; ia++)
|
||||||
|
{
|
||||||
|
D3DADAPTER_IDENTIFIER9 d3dIdent;
|
||||||
|
HRESULT result = pD3D->GetAdapterIdentifier(ia, 0, &d3dIdent);
|
||||||
|
if (result == D3D_OK)
|
||||||
|
{
|
||||||
|
QString gpuAdapter = QString::fromLatin1(d3dIdent.Description);
|
||||||
|
if (!gpusList.contains(gpuAdapter)) { gpusList << gpuAdapter; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pD3D->Release();
|
||||||
|
jsonObject["GPUs"] = QJsonValue::fromVariant(gpusList);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
QDir procDir("/proc");
|
||||||
|
if (procDir.exists())
|
||||||
|
{
|
||||||
|
QFile cpuInfo("/proc/cpuinfo");
|
||||||
|
if (cpuInfo.open(QFile::ReadOnly))
|
||||||
|
{
|
||||||
|
QByteArray cpuInfoArray = cpuInfo.readAll();
|
||||||
|
QBuffer cpuInfoBuffer(&cpuInfoArray);
|
||||||
|
if (cpuInfoBuffer.open(QBuffer::ReadOnly))
|
||||||
|
{
|
||||||
|
QByteArray toFind = "model name";
|
||||||
|
while (cpuInfoBuffer.canReadLine())
|
||||||
|
{
|
||||||
|
QByteArray cpuData = cpuInfoBuffer.readLine();
|
||||||
|
if (cpuData.left(toFind.length()) == toFind)
|
||||||
|
{
|
||||||
|
jsonObject["CPUName"] = QString::fromUtf8(cpuData).split(':').at(1).simplified();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int cpuThreads = 0;
|
||||||
|
toFind = "processor";
|
||||||
|
cpuInfoBuffer.seek(0);
|
||||||
|
while (cpuInfoBuffer.canReadLine())
|
||||||
|
{
|
||||||
|
QByteArray cpuData = cpuInfoBuffer.readLine();
|
||||||
|
if (cpuData.left(toFind.length()) == toFind)
|
||||||
|
{
|
||||||
|
cpuThreads++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jsonObject["CPUThreads"] = QString::number(cpuThreads);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile memInfo("/proc/meminfo");
|
||||||
|
if (memInfo.open(QFile::ReadOnly))
|
||||||
|
{
|
||||||
|
QByteArray memInfoArray = memInfo.readAll();
|
||||||
|
QBuffer memInfoBuffer(&memInfoArray);
|
||||||
|
if (memInfoBuffer.open(QBuffer::ReadOnly))
|
||||||
|
{
|
||||||
|
QByteArray toFind = "MemTotal:";
|
||||||
|
while (memInfoBuffer.canReadLine())
|
||||||
|
{
|
||||||
|
QByteArray memData = memInfoBuffer.readLine();
|
||||||
|
if (memData.left(toFind.length()) == toFind)
|
||||||
|
{
|
||||||
|
QByteArray memDataVal = memData.mid(toFind.length()).trimmed();
|
||||||
|
int totalMemoryInKB = memDataVal.left(memDataVal.length() - 3).toInt();
|
||||||
|
jsonObject["SystemRAM"] = QString(QString::number(totalMemoryInKB / 1024) % "MB");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
jsonDocument.setObject(jsonObject);
|
||||||
|
return jsonDocument;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonDocument TelemetryClass::getApplicationSpec()
|
||||||
|
{
|
||||||
|
QJsonDocument jsonDocument;
|
||||||
|
QJsonObject jsonObject;
|
||||||
|
#if QT_VERSION >= 0x050400
|
||||||
|
jsonObject["Arch"] = QSysInfo::buildCpuArchitecture();
|
||||||
|
#endif
|
||||||
|
jsonObject["Name"] = GTA5SYNC_APPSTR;
|
||||||
|
#ifdef GTA5SYNC_COMMIT
|
||||||
|
jsonObject["Commit"] = GTA5SYNC_COMMIT;
|
||||||
|
#endif
|
||||||
|
jsonObject["Version"] = GTA5SYNC_APPVER;
|
||||||
|
jsonObject["BuildDateTime"] = AppEnv::getBuildDateTime();
|
||||||
|
jsonObject["BuildType"] = GTA5SYNC_BUILDTYPE;
|
||||||
|
jsonObject["BuildCode"] = AppEnv::getBuildCode();
|
||||||
|
jsonObject["QtVersion"] = qVersion();
|
||||||
|
jsonDocument.setObject(jsonObject);
|
||||||
|
return jsonDocument;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonDocument TelemetryClass::getApplicationConf()
|
||||||
|
{
|
||||||
|
QJsonDocument jsonDocument;
|
||||||
|
QJsonObject jsonObject;
|
||||||
|
QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||||
|
|
||||||
|
settings.beginGroup("Interface");
|
||||||
|
QJsonObject interfaceObject;
|
||||||
|
interfaceObject["AreaLanguage"] = settings.value("AreaLanguage", "Auto").toString();
|
||||||
|
interfaceObject["Language"] = settings.value("Language", "System").toString();
|
||||||
|
interfaceObject["NavigationBar"] = settings.value("NavigationBar", false).toBool();
|
||||||
|
jsonObject["Interface"] = interfaceObject;
|
||||||
|
settings.endGroup();
|
||||||
|
|
||||||
|
settings.beginGroup("Pictures");
|
||||||
|
QJsonObject picturesObject;
|
||||||
|
picturesObject["AspectRatio"] = ((Qt::AspectRatioMode)settings.value("AspectRatio").toInt() == Qt::IgnoreAspectRatio) ? "IgnoreAspectRatio" : "KeepAspectRatio";
|
||||||
|
picturesObject["CustomQuality"] = settings.value("CustomQuality", 100).toInt();
|
||||||
|
picturesObject["CustomQualityEnabled"] = settings.value("CustomQualityEnabled", false).toBool();
|
||||||
|
picturesObject["ExportSizeMode"] = settings.value("ExportSizeMode", "Default").toString();
|
||||||
|
jsonObject["Pictures"] = picturesObject;
|
||||||
|
settings.endGroup();
|
||||||
|
|
||||||
|
settings.beginGroup("Profile");
|
||||||
|
QJsonObject profileObject;
|
||||||
|
int contentMode = settings.value("ContentMode", 0).toInt();
|
||||||
|
switch (contentMode)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
profileObject["ContentMode"] = "OpenWithSingleClick";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
profileObject["ContentMode"] = "OpenWithDoubleClick";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
profileObject["ContentMode"] = "SelectWithSingleClick";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
jsonObject["Profile"] = profileObject;
|
||||||
|
settings.endGroup();
|
||||||
|
|
||||||
|
settings.beginGroup("Startup");
|
||||||
|
QJsonObject startupObject;
|
||||||
|
startupObject["AppStyle"] = settings.value("AppStyle", "System").toString();
|
||||||
|
startupObject["CustomStyle"] = settings.value("CustomStyle", false).toBool();
|
||||||
|
startupObject["StartCount"] = QString::number(settings.value("StartCount", 0).toUInt());
|
||||||
|
jsonObject["Startup"] = startupObject;
|
||||||
|
settings.endGroup();
|
||||||
|
|
||||||
|
jsonDocument.setObject(jsonObject);
|
||||||
|
return jsonDocument;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonDocument TelemetryClass::getSystemLocaleList()
|
||||||
|
{
|
||||||
|
QJsonDocument jsonDocument;
|
||||||
|
QJsonObject jsonObject;
|
||||||
|
QStringList languagesList = QLocale::system().uiLanguages();
|
||||||
|
if (languagesList.length() >= 1)
|
||||||
|
{
|
||||||
|
jsonObject["PrimaryLanguage"] = languagesList.at(0);
|
||||||
|
}
|
||||||
|
if (languagesList.length() >= 2)
|
||||||
|
{
|
||||||
|
languagesList.removeAt(0);
|
||||||
|
jsonObject["SecondaryLanguages"] = QJsonValue::fromVariant(languagesList);
|
||||||
|
}
|
||||||
|
jsonDocument.setObject(jsonObject);
|
||||||
|
return jsonDocument;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString TelemetryClass::categoryToString(TelemetryCategory category)
|
||||||
|
{
|
||||||
|
switch (category)
|
||||||
|
{
|
||||||
|
case TelemetryCategory::OperatingSystemSpec:
|
||||||
|
return QString("OperatingSystemSpec");
|
||||||
|
break;
|
||||||
|
case TelemetryCategory::HardwareSpec:
|
||||||
|
return QString("HardwareSpec");
|
||||||
|
break;
|
||||||
|
case TelemetryCategory::UserLocaleData:
|
||||||
|
return QString("UserLocaleData");
|
||||||
|
break;
|
||||||
|
case TelemetryCategory::ApplicationConf:
|
||||||
|
return QString("ApplicationConf");
|
||||||
|
break;
|
||||||
|
case TelemetryCategory::ApplicationSpec:
|
||||||
|
return QString("ApplicationSpec");
|
||||||
|
break;
|
||||||
|
case TelemetryCategory::UserFeedback:
|
||||||
|
return QString("UserFeedback");
|
||||||
|
break;
|
||||||
|
case TelemetryCategory::PersonalData:
|
||||||
|
return QString("PersonalData");
|
||||||
|
break;
|
||||||
|
case TelemetryCategory::CustomEmitted:
|
||||||
|
return QString("CustomEmitted");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return QString("UnknownCategory");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QUrl TelemetryClass::getWebURL()
|
||||||
|
{
|
||||||
|
return QUrl(GTA5SYNC_TELEMETRY_WEBURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TelemetryClass::registerClient()
|
||||||
|
{
|
||||||
|
QNetworkAccessManager *netManager = new QNetworkAccessManager();
|
||||||
|
QNetworkRequest netRequest(TelemetryClassAuthenticator::getTrackingRegURL());
|
||||||
|
netRequest.setRawHeader("User-Agent", AppEnv::getUserAgent());
|
||||||
|
netManager->get(netRequest);
|
||||||
|
|
||||||
|
connect(netManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(registerFinished(QNetworkReply*)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TelemetryClass::work()
|
||||||
|
{
|
||||||
|
if (!canPush() && canRegister())
|
||||||
|
{
|
||||||
|
connect(this, SIGNAL(registered(bool)), this, SLOT(work_pd(bool)));
|
||||||
|
registerClient();
|
||||||
|
}
|
||||||
|
else if (canPush())
|
||||||
|
{
|
||||||
|
work_p(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TelemetryClass::work_p(bool doWork)
|
||||||
|
{
|
||||||
|
if (doWork)
|
||||||
|
{
|
||||||
|
push(TelemetryCategory::ApplicationSpec);
|
||||||
|
push(TelemetryCategory::UserLocaleData);
|
||||||
|
push(TelemetryCategory::OperatingSystemSpec);
|
||||||
|
push(TelemetryCategory::HardwareSpec);
|
||||||
|
if (telemetryPushAppConf)
|
||||||
|
{
|
||||||
|
push(TelemetryCategory::ApplicationConf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
push(TelemetryCategory::ApplicationConf, QJsonDocument());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TelemetryClass::work_pd(bool doWork)
|
||||||
|
{
|
||||||
|
disconnect(this, SIGNAL(registered(bool)), this, SLOT(work_pd(bool)));
|
||||||
|
work_p(doWork);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TelemetryClass::pushFinished(QNetworkReply *reply)
|
||||||
|
{
|
||||||
|
bool isSuccessful = false;
|
||||||
|
if (reply->canReadLine())
|
||||||
|
{
|
||||||
|
QByteArray readedData = reply->readLine();
|
||||||
|
if (QString::fromUtf8(readedData).trimmed() == QString("Submit success!"))
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "Telemetry" << QString("Submit success!");
|
||||||
|
#endif
|
||||||
|
isSuccessful = true;
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
if (reply->isReadable())
|
||||||
|
{
|
||||||
|
readedData = reply->readAll().trimmed();
|
||||||
|
if (!readedData.isEmpty()) { qDebug() << "Telemetry Push" << readedData; }
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "Telemetry" << QString("Submit failed!");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "Telemetry" << QString("Submit failed!");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
reply->deleteLater();
|
||||||
|
sender()->deleteLater();
|
||||||
|
emit pushed(isSuccessful);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TelemetryClass::registerFinished(QNetworkReply *reply)
|
||||||
|
{
|
||||||
|
bool isSuccessful = false;
|
||||||
|
if (reply->canReadLine())
|
||||||
|
{
|
||||||
|
QByteArray readedData = reply->readLine();
|
||||||
|
if (QString::fromUtf8(readedData).trimmed() == QString("Registration success!") && reply->canReadLine())
|
||||||
|
{
|
||||||
|
QDir dir;
|
||||||
|
dir.mkpath(StandardPaths::dataLocation());
|
||||||
|
dir.setPath(StandardPaths::dataLocation());
|
||||||
|
QString dirPath = dir.absolutePath();
|
||||||
|
QString regLoc = dirPath % "/.reg";
|
||||||
|
readedData = reply->readLine();
|
||||||
|
telemetryClientID = QString::fromUtf8(readedData).trimmed();
|
||||||
|
QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||||
|
settings.beginGroup("Telemetry");
|
||||||
|
settings.setValue("Identification", telemetryClientID.toUtf8().toBase64());
|
||||||
|
settings.endGroup();
|
||||||
|
QFile regFile(regLoc);
|
||||||
|
if (regFile.open(QFile::WriteOnly))
|
||||||
|
{
|
||||||
|
regFile.write("\n");
|
||||||
|
regFile.flush();
|
||||||
|
}
|
||||||
|
regFile.close();
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "Telemetry" << QString("Registration success!");
|
||||||
|
#endif
|
||||||
|
isSuccessful = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "Telemetry" << QString("Registration failed!");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "Telemetry" << QString("Registration failed!");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
reply->deleteLater();
|
||||||
|
sender()->deleteLater();
|
||||||
|
emit registered(isSuccessful);
|
||||||
|
}
|
80
TelemetryClass.h
Normal file
80
TelemetryClass.h
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 Profile Viewer
|
||||||
|
* Copyright (C) 2018 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 TELEMETRYCLASS_H
|
||||||
|
#define TELEMETRYCLASS_H
|
||||||
|
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
enum class TelemetryCategory : int { OperatingSystemSpec = 0, HardwareSpec = 1, UserLocaleData = 2, ApplicationConf = 3, UserFeedback = 4, ApplicationSpec = 5, PersonalData = 6, CustomEmitted = 99 };
|
||||||
|
|
||||||
|
class TelemetryClass : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
static TelemetryClass* getInstance() { return &telemetryClassInstance; }
|
||||||
|
static QString categoryToString(TelemetryCategory category);
|
||||||
|
static QUrl getWebURL();
|
||||||
|
bool canPush();
|
||||||
|
bool canRegister();
|
||||||
|
bool isEnabled();
|
||||||
|
bool isStateForced();
|
||||||
|
bool isRegistered();
|
||||||
|
void init();
|
||||||
|
void work();
|
||||||
|
void refresh();
|
||||||
|
void setEnabled(bool enabled);
|
||||||
|
void setDisabled(bool disabled);
|
||||||
|
void push(TelemetryCategory category);
|
||||||
|
void push(TelemetryCategory category, const QJsonDocument json);
|
||||||
|
void registerClient();
|
||||||
|
QString getRegisteredID();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static TelemetryClass telemetryClassInstance;
|
||||||
|
QString telemetryClientID;
|
||||||
|
bool telemetryEnabled;
|
||||||
|
bool telemetryStateForced;
|
||||||
|
bool telemetryPushAppConf;
|
||||||
|
|
||||||
|
void work_p(bool doWork);
|
||||||
|
QJsonDocument getOperatingSystem();
|
||||||
|
QJsonDocument getSystemHardware();
|
||||||
|
QJsonDocument getApplicationSpec();
|
||||||
|
QJsonDocument getApplicationConf();
|
||||||
|
QJsonDocument getSystemLocaleList();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void pushFinished(QNetworkReply *reply);
|
||||||
|
void registerFinished(QNetworkReply *reply);
|
||||||
|
void work_pd(bool doWork);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void pushed(bool isSucessful);
|
||||||
|
void registered(bool isSucessful);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern TelemetryClass telemetryClass;
|
||||||
|
|
||||||
|
#define Telemetry TelemetryClass::getInstance()
|
||||||
|
|
||||||
|
#endif // TELEMETRYCLASS_H
|
653
TranslationClass.cpp
Normal file
653
TranslationClass.cpp
Normal file
|
@ -0,0 +1,653 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 Profile Viewer
|
||||||
|
* 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();
|
||||||
|
userAreaLanguage = settings.value("AreaLanguage", "Auto").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 externalEnglishMode = 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 || isEnglishMode) // Don't install the language until we know we not have a better language for the user
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "externalLanguageReady" << currentLanguage;
|
||||||
|
#endif
|
||||||
|
externalEnglishMode = isEnglishMode;
|
||||||
|
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;
|
||||||
|
qDebug() << "externalEnglishMode" << externalEnglishMode << "internalEnglishMode" << isEnglishMode;
|
||||||
|
#endif
|
||||||
|
if ((trLoadSuccess && externalLangIndex > currentLangIndex) || (trLoadSuccess && externalEnglishMode && !isEnglishMode))
|
||||||
|
{
|
||||||
|
#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
|
||||||
|
isEnglishMode = externalEnglishMode;
|
||||||
|
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;
|
||||||
|
for (QString lang : langDir.entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::NoSort))
|
||||||
|
{
|
||||||
|
availableLanguages << QString(lang).remove("gta5sync_").remove(".qm");
|
||||||
|
}
|
||||||
|
return availableLanguages;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList TranslationClass::listAreaTranslations()
|
||||||
|
{
|
||||||
|
QDir langDir;
|
||||||
|
langDir.setNameFilters(QStringList("global.*.ini"));
|
||||||
|
langDir.setPath(":/global");
|
||||||
|
QStringList availableLanguages;
|
||||||
|
for (QString lang : langDir.entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::NoSort))
|
||||||
|
{
|
||||||
|
availableLanguages << QString(lang).remove("global.").remove(".ini");
|
||||||
|
}
|
||||||
|
return availableLanguages;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TranslationClass::loadSystemTranslation_p(const QString &langPath, QTranslator *appTranslator)
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "loadSystemTranslation_p";
|
||||||
|
#endif
|
||||||
|
int currentLangCounter = 0;
|
||||||
|
for (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 % "/gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm");
|
||||||
|
#endif
|
||||||
|
if (QFile::exists(langPath % "/gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm"))
|
||||||
|
{
|
||||||
|
if (appTranslator->load(langPath % "/gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm"))
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "loadLanguageFileSuccess" << QString(langPath % "/gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm");
|
||||||
|
#endif
|
||||||
|
isEnglishMode = false;
|
||||||
|
currentLanguage = languageName;
|
||||||
|
currentLangIndex = currentLangCounter;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "loadLanguageFile" << QString(langPath % "/gta5sync_" % langList.at(0) % ".qm");
|
||||||
|
#endif
|
||||||
|
if (QFile::exists(langPath % "/gta5sync_" % langList.at(0) % ".qm"))
|
||||||
|
{
|
||||||
|
if (appTranslator->load(langPath % "/gta5sync_" % langList.at(0) % ".qm"))
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "loadLanguageFileSuccess" << QString(langPath % "/gta5sync_" % langList.at(0) % ".qm");
|
||||||
|
#endif
|
||||||
|
isEnglishMode = false;
|
||||||
|
currentLanguage = languageName;
|
||||||
|
currentLangIndex = currentLangCounter;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (langList.at(0) == "en")
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "languageEnglishMode index" << currentLangCounter;
|
||||||
|
#endif
|
||||||
|
isEnglishMode = true;
|
||||||
|
currentLanguage = languageName;
|
||||||
|
currentLangIndex = currentLangCounter;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (langList.at(0) == "en")
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "languageEnglishMode index" << currentLangCounter;
|
||||||
|
#endif
|
||||||
|
isEnglishMode = true;
|
||||||
|
currentLanguage = languageName;
|
||||||
|
currentLangIndex = currentLangCounter;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (langList.length() == 1)
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "loadLanguageFile" << QString(langPath % "/gta5sync_" % langList.at(0) % ".qm");
|
||||||
|
#endif
|
||||||
|
if (QFile::exists(langPath % "/gta5sync_" % langList.at(0) % ".qm"))
|
||||||
|
{
|
||||||
|
if (appTranslator->load(langPath % "/gta5sync_" % langList.at(0) % ".qm"))
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "loadLanguageFileSuccess" << QString(langPath % "/gta5sync_" % langList.at(0) % ".qm");
|
||||||
|
#endif
|
||||||
|
isEnglishMode = false;
|
||||||
|
currentLanguage = languageName;
|
||||||
|
currentLangIndex = currentLangCounter;
|
||||||
|
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 % "/gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm");
|
||||||
|
#endif
|
||||||
|
if (QFile::exists(langPath % "/gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm"))
|
||||||
|
{
|
||||||
|
if (appTranslator->load(langPath % "/gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm"))
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "loadLanguageFileSuccess" << QString(langPath % "/gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm");
|
||||||
|
#endif
|
||||||
|
currentLanguage = languageName;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "loadLanguageFile" << QString(langPath % "/gta5sync_" % langList.at(0) % ".qm");
|
||||||
|
#endif
|
||||||
|
if (QFile::exists(langPath % "/gta5sync_" % langList.at(0) % ".qm"))
|
||||||
|
{
|
||||||
|
if (appTranslator->load(langPath % "/gta5sync_" % langList.at(0) % ".qm"))
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "loadLanguageFileSuccess" << QString(langPath % "/gta5sync_" % langList.at(0) % ".qm");
|
||||||
|
#endif
|
||||||
|
currentLanguage = languageName;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (langList.length() == 1)
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "loadLanguageFile" << QString(langPath % "/gta5sync_" % langList.at(0) % ".qm");
|
||||||
|
#endif
|
||||||
|
if (QFile::exists(langPath % "/gta5sync_" % langList.at(0) % ".qm"))
|
||||||
|
{
|
||||||
|
if (appTranslator->load(langPath % "/gta5sync_" % langList.at(0) % ".qm"))
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "loadLanguageFileSuccess" << QString(langPath % "/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::getCurrentAreaLanguage()
|
||||||
|
{
|
||||||
|
const QStringList areaTranslations = listAreaTranslations();
|
||||||
|
if (userAreaLanguage == "Auto" || userAreaLanguage.trimmed().isEmpty())
|
||||||
|
{
|
||||||
|
GameLanguage gameLanguage = AppEnv::getGameLanguage(AppEnv::getGameVersion());
|
||||||
|
if (gameLanguage == GameLanguage::Undefined)
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "autoAreaLanguageModeInterface";
|
||||||
|
#endif
|
||||||
|
QString langCode = QString(currentLanguage).replace("-", "_");
|
||||||
|
if (areaTranslations.contains(langCode))
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "autoAreaLanguageSelected" << langCode;
|
||||||
|
#endif
|
||||||
|
return langCode;
|
||||||
|
}
|
||||||
|
else if (langCode.contains("_"))
|
||||||
|
{
|
||||||
|
langCode = langCode.split("_").at(0);
|
||||||
|
if (!areaTranslations.contains(langCode)) goto outputDefaultLanguage;
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "autoAreaLanguageSelected" << langCode;
|
||||||
|
#endif
|
||||||
|
return langCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "autoAreaLanguageModeGame";
|
||||||
|
#endif
|
||||||
|
QString langCode = AppEnv::gameLanguageToString(gameLanguage).replace("-", "_");
|
||||||
|
if (areaTranslations.contains(langCode))
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "autoAreaLanguageSelected" << langCode;
|
||||||
|
#endif
|
||||||
|
return langCode;
|
||||||
|
}
|
||||||
|
else if (langCode.contains("_"))
|
||||||
|
{
|
||||||
|
langCode = langCode.split("_").at(0);
|
||||||
|
if (!areaTranslations.contains(langCode)) goto outputDefaultLanguage;
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "autoAreaLanguageSelected" << langCode;
|
||||||
|
#endif
|
||||||
|
return langCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (areaTranslations.contains(userAreaLanguage))
|
||||||
|
{
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "userAreaLanguageSelected" << userAreaLanguage;
|
||||||
|
#endif
|
||||||
|
return userAreaLanguage;
|
||||||
|
}
|
||||||
|
else if (userAreaLanguage.contains("_"))
|
||||||
|
{
|
||||||
|
QString langCode = QString(userAreaLanguage).replace("-", "_").split("_").at(0);
|
||||||
|
if (!areaTranslations.contains(langCode)) goto outputDefaultLanguage;
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "userAreaLanguageSelected" << langCode;
|
||||||
|
#endif
|
||||||
|
return langCode;
|
||||||
|
}
|
||||||
|
outputDefaultLanguage:
|
||||||
|
#ifdef GTA5SYNC_DEBUG
|
||||||
|
qDebug() << "defaultAreaLanguageSelected";
|
||||||
|
#endif
|
||||||
|
return "en";
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
isEnglishMode = false;
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
67
TranslationClass.h
Normal file
67
TranslationClass.h
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 Profile Viewer
|
||||||
|
* 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);
|
||||||
|
static QStringList listTranslations(const QString &langPath);
|
||||||
|
static QStringList listAreaTranslations();
|
||||||
|
QString getCurrentAreaLanguage();
|
||||||
|
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 userAreaLanguage;
|
||||||
|
QString currentLanguage;
|
||||||
|
QString userLanguage;
|
||||||
|
int currentLangIndex;
|
||||||
|
bool isEnglishMode;
|
||||||
|
bool isLangLoaded;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern TranslationClass translationClass;
|
||||||
|
|
||||||
|
#define Translator TranslationClass::getInstance()
|
||||||
|
|
||||||
|
#endif // TRANSLATIONCLASS_H
|
677
UserInterface.cpp
Normal file
677
UserInterface.cpp
Normal file
|
@ -0,0 +1,677 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 Profile Viewer
|
||||||
|
* Copyright (C) 2016-2019 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 <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")));
|
||||||
|
QString appVersion = GTA5SYNC_APPVER;
|
||||||
|
#ifndef GTA5SYNC_BUILDTYPE_REL
|
||||||
|
#ifdef GTA5SYNC_COMMIT
|
||||||
|
if (!appVersion.contains("-")) { appVersion = appVersion % "-" % GTA5SYNC_COMMIT; }
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
ui->labVersion->setText(QString("%1 %2").arg(GTA5SYNC_APPSTR, appVersion));
|
||||||
|
|
||||||
|
// Set Icon for Close Button
|
||||||
|
if (QIcon::hasThemeIcon("dialog-close"))
|
||||||
|
{
|
||||||
|
ui->cmdClose->setIcon(QIcon::fromTheme("dialog-close"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("gtk-close"))
|
||||||
|
{
|
||||||
|
ui->cmdClose->setIcon(QIcon::fromTheme("gtk-close"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Icon for Reload Button
|
||||||
|
if (QIcon::hasThemeIcon("view-refresh"))
|
||||||
|
{
|
||||||
|
ui->cmdReload->setIcon(QIcon::fromTheme("view-refresh"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("reload"))
|
||||||
|
{
|
||||||
|
ui->cmdReload->setIcon(QIcon::fromTheme("reload"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Icon for Choose RDR 2 Folder Menu Item
|
||||||
|
if (QIcon::hasThemeIcon("document-open-folder"))
|
||||||
|
{
|
||||||
|
ui->actionSelect_GTA_Folder->setIcon(QIcon::fromTheme("document-open-folder"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("gtk-directory"))
|
||||||
|
{
|
||||||
|
ui->actionSelect_GTA_Folder->setIcon(QIcon::fromTheme("gtk-directory"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Icon for Open File Menu Item
|
||||||
|
if (QIcon::hasThemeIcon("document-open"))
|
||||||
|
{
|
||||||
|
ui->actionOpen_File->setIcon(QIcon::fromTheme("document-open"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Icon for Close Profile Menu Item
|
||||||
|
if (QIcon::hasThemeIcon("dialog-close"))
|
||||||
|
{
|
||||||
|
ui->actionSelect_profile->setIcon(QIcon::fromTheme("dialog-close"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("gtk-close"))
|
||||||
|
{
|
||||||
|
ui->actionSelect_profile->setIcon(QIcon::fromTheme("gtk-close"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Icon for Exit Menu Item
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Icon for Preferences Menu Item
|
||||||
|
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
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("configure"))
|
||||||
|
{
|
||||||
|
#ifndef Q_OS_MACOS // Setting icon for preferences/settings/options lead to a crash in Mac OS X
|
||||||
|
ui->actionOptions->setIcon(QIcon::fromTheme("configure"));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Icon for Profile Import Menu Item
|
||||||
|
if (QIcon::hasThemeIcon("document-import"))
|
||||||
|
{
|
||||||
|
ui->action_Import->setIcon(QIcon::fromTheme("document-import"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("document-open"))
|
||||||
|
{
|
||||||
|
ui->action_Import->setIcon(QIcon::fromTheme("document-open"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Icon for Profile Export Menu Item
|
||||||
|
if (QIcon::hasThemeIcon("document-export"))
|
||||||
|
{
|
||||||
|
ui->actionExport_selected->setIcon(QIcon::fromTheme("document-export"));
|
||||||
|
}
|
||||||
|
else if (QIcon::hasThemeIcon("document-save"))
|
||||||
|
{
|
||||||
|
ui->actionExport_selected->setIcon(QIcon::fromTheme("document-save"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Icon for Profile Remove Menu Item
|
||||||
|
if (QIcon::hasThemeIcon("remove"))
|
||||||
|
{
|
||||||
|
ui->actionDelete_selected->setIcon(QIcon::fromTheme("remove"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// DPI calculation
|
||||||
|
qreal screenRatio = AppEnv::screenRatio();
|
||||||
|
#ifndef Q_QS_ANDROID
|
||||||
|
resize(625 * screenRatio, 500 * screenRatio);
|
||||||
|
#endif
|
||||||
|
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 RDR 2 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 % "/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.isEmpty())
|
||||||
|
{
|
||||||
|
QPushButton *changeDirBtn = new QPushButton(tr("Select &RDR 2 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 for (QString GTAV_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()
|
||||||
|
{
|
||||||
|
for (QPushButton *profileBtn : profileBtns)
|
||||||
|
{
|
||||||
|
ui->vlButtons->removeWidget(profileBtn);
|
||||||
|
delete profileBtn;
|
||||||
|
}
|
||||||
|
profileBtns.clear();
|
||||||
|
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, false);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
closeProfile_p();
|
||||||
|
}
|
||||||
|
this->setWindowTitle(defaultWindowTitle.arg(tr("Select Profile")));
|
||||||
|
}
|
||||||
|
|
||||||
|
void UserInterface::closeProfile_p()
|
||||||
|
{
|
||||||
|
profileOpen = false;
|
||||||
|
profileName.clear();
|
||||||
|
profileName.squeeze();
|
||||||
|
ui->menuProfile->setEnabled(false);
|
||||||
|
ui->actionSelect_profile->setEnabled(false);
|
||||||
|
ui->swProfile->removeWidget(profileUI);
|
||||||
|
profileUI->disconnect();
|
||||||
|
delete profileUI;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UserInterface::closeEvent(QCloseEvent *ev)
|
||||||
|
{
|
||||||
|
Q_UNUSED(ev)
|
||||||
|
threadDB->terminateThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
UserInterface::~UserInterface()
|
||||||
|
{
|
||||||
|
if (profileOpen)
|
||||||
|
{
|
||||||
|
closeProfile_p();
|
||||||
|
}
|
||||||
|
for (QPushButton *profileBtn : profileBtns)
|
||||||
|
{
|
||||||
|
delete profileBtn;
|
||||||
|
}
|
||||||
|
profileBtns.clear();
|
||||||
|
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, bool)), this, SLOT(settingsApplied(int, bool)));
|
||||||
|
|
||||||
|
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 (*.r5e SRDR* PRDR*)");
|
||||||
|
filters << ProfileInterface::tr("RDR 2 Export (*.r5e)");
|
||||||
|
filters << ProfileInterface::tr("Savegames files (SRDR*)");
|
||||||
|
filters << ProfileInterface::tr("Snapmatic pictures (PRDR*)");
|
||||||
|
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) == "PRDR" || selectedFileName.right(4) == ".r5e")
|
||||||
|
{
|
||||||
|
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) == "SRDR")
|
||||||
|
{
|
||||||
|
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, bool languageChanged)
|
||||||
|
{
|
||||||
|
if (languageChanged)
|
||||||
|
{
|
||||||
|
retranslateUi();
|
||||||
|
}
|
||||||
|
contentMode = _contentMode;
|
||||||
|
if (profileOpen)
|
||||||
|
{
|
||||||
|
profileUI->settingsApplied(contentMode, languageChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UserInterface::on_actionSelect_GTA_Folder_triggered()
|
||||||
|
{
|
||||||
|
QString GTAV_Folder_Temp = QFileDialog::getExistingDirectory(this, tr("Select RDR 2 Folder..."), StandardPaths::documentsLocation(), QFileDialog::ShowDirsOnly);
|
||||||
|
if (QFileInfo(GTAV_Folder_Temp).exists())
|
||||||
|
{
|
||||||
|
if (profileOpen)
|
||||||
|
{
|
||||||
|
closeProfile_p();
|
||||||
|
}
|
||||||
|
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));
|
||||||
|
QString appVersion = GTA5SYNC_APPVER;
|
||||||
|
#ifndef GTA5SYNC_BUILDTYPE_REL
|
||||||
|
#ifdef GTA5SYNC_COMMIT
|
||||||
|
if (!appVersion.contains("-")) { appVersion = appVersion % "-" % GTA5SYNC_COMMIT; }
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
ui->labVersion->setText(QString("%1 %2").arg(GTA5SYNC_APPSTR, appVersion));
|
||||||
|
if (profileOpen)
|
||||||
|
{
|
||||||
|
this->setWindowTitle(defaultWindowTitle.arg(profileName));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->setWindowTitle(defaultWindowTitle.arg(tr("Select Profile")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UserInterface::on_actionQualify_as_Avatar_triggered()
|
||||||
|
{
|
||||||
|
profileUI->massTool(MassTool::Qualify);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UserInterface::on_actionChange_Players_triggered()
|
||||||
|
{
|
||||||
|
profileUI->massTool(MassTool::Players);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UserInterface::on_actionSet_Crew_triggered()
|
||||||
|
{
|
||||||
|
profileUI->massTool(MassTool::Crew);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UserInterface::on_actionSet_Title_triggered()
|
||||||
|
{
|
||||||
|
profileUI->massTool(MassTool::Title);
|
||||||
|
}
|
101
UserInterface.h
Normal file
101
UserInterface.h
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 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 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 on_actionQualify_as_Avatar_triggered();
|
||||||
|
void on_actionChange_Players_triggered();
|
||||||
|
void on_actionSet_Crew_triggered();
|
||||||
|
void on_actionSet_Title_triggered();
|
||||||
|
void settingsApplied(int contentMode, bool languageChanged);
|
||||||
|
|
||||||
|
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 closeProfile_p();
|
||||||
|
void openSelectProfile();
|
||||||
|
void retranslateUi();
|
||||||
|
|
||||||
|
// Open File
|
||||||
|
bool openFile(QString selectedFile, bool warn = true);
|
||||||
|
void openSavegameFile(SavegameData *savegame);
|
||||||
|
void openSnapmaticFile(SnapmaticPicture *picture);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // USERINTERFACE_H
|
396
UserInterface.ui
Normal file
396
UserInterface.ui
Normal file
|
@ -0,0 +1,396 @@
|
||||||
|
<?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>23</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>
|
||||||
|
<widget class="QMenu" name="menuManage_selection">
|
||||||
|
<property name="title">
|
||||||
|
<string>Selection &mass tools</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionQualify_as_Avatar"/>
|
||||||
|
<addaction name="actionChange_Players"/>
|
||||||
|
<addaction name="actionSet_Crew"/>
|
||||||
|
<addaction name="actionSet_Title"/>
|
||||||
|
</widget>
|
||||||
|
<addaction name="action_Import"/>
|
||||||
|
<addaction name="actionExport_selected"/>
|
||||||
|
<addaction name="actionDelete_selected"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="menuManage_selection"/>
|
||||||
|
<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 notr="true">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 notr="true">Ctrl+Q</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSelect_profile">
|
||||||
|
<property name="text">
|
||||||
|
<string>Close &Profile</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string notr="true">Ctrl+End</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionOptions">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Settings</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string notr="true">Ctrl+S</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSelect_all">
|
||||||
|
<property name="text">
|
||||||
|
<string>Select &All</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string notr="true">Ctrl+A</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionDeselect_all">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Deselect All</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string notr="true">Ctrl+D</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionExport_selected">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Export selected...</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string notr="true">Ctrl+E</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionDelete_selected">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Remove selected</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string notr="true">Ctrl+Del</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_Import">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Import files...</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string notr="true">Ctrl+I</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionOpen_File">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Open File...</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string notr="true">Ctrl+O</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSelect_GTA_Folder">
|
||||||
|
<property name="text">
|
||||||
|
<string>Select &RDR 2 Folder...</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Select RDR 2 Folder...</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string notr="true">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 notr="true">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 notr="true">Shift+D</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSet_Title">
|
||||||
|
<property name="text">
|
||||||
|
<string>Change &Title...</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string notr="true">Shift+T</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSet_Crew">
|
||||||
|
<property name="text">
|
||||||
|
<string>Change &Crew...</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string notr="true">Shift+C</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionQualify_as_Avatar">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Qualify as Avatar</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string notr="true">Shift+Q</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionChange_Players">
|
||||||
|
<property name="text">
|
||||||
|
<string>Change &Players...</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string notr="true">Shift+P</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>
|
519
anpro/imagecropper.cpp
Normal file
519
anpro/imagecropper.cpp
Normal file
|
@ -0,0 +1,519 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* ImageCropper Qt Widget for cropping images
|
||||||
|
* Copyright (C) 2013 Dimka Novikov, to@dimkanovikov.pro
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "imagecropper.h"
|
||||||
|
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
static const QSize WIDGET_MINIMUM_SIZE(470, 470);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageCropper::ImageCropper(QWidget* parent) :
|
||||||
|
QWidget(parent),
|
||||||
|
pimpl(new ImageCropperPrivate)
|
||||||
|
{
|
||||||
|
setMinimumSize(WIDGET_MINIMUM_SIZE);
|
||||||
|
setMouseTracking(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageCropper::~ImageCropper()
|
||||||
|
{
|
||||||
|
delete pimpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageCropper::setImage(const QPixmap& _image)
|
||||||
|
{
|
||||||
|
pimpl->imageForCropping = _image;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageCropper::setBackgroundColor(const QColor& _backgroundColor)
|
||||||
|
{
|
||||||
|
pimpl->backgroundColor = _backgroundColor;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageCropper::setCroppingRectBorderColor(const QColor& _borderColor)
|
||||||
|
{
|
||||||
|
pimpl->croppingRectBorderColor = _borderColor;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageCropper::setProportion(const QSizeF& _proportion)
|
||||||
|
{
|
||||||
|
// Пропорции хранятся в коэффициентах приращения сторон
|
||||||
|
// Таким образом, при изменении размера области выделения,
|
||||||
|
// размеры сторон изменяются на размер зависящий от
|
||||||
|
// коэффициентов приращения.
|
||||||
|
|
||||||
|
// Сохраним пропорциональную зависимость области выделения в коэффициентах приращения сторон
|
||||||
|
if (pimpl->proportion != _proportion) {
|
||||||
|
pimpl->proportion = _proportion;
|
||||||
|
// ... расчитаем коэффициенты
|
||||||
|
float heightDelta = (float)_proportion.height() / _proportion.width();
|
||||||
|
float widthDelta = (float)_proportion.width() / _proportion.height();
|
||||||
|
// ... сохраним коэффициенты
|
||||||
|
pimpl->deltas.setHeight(heightDelta);
|
||||||
|
pimpl->deltas.setWidth(widthDelta);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обновим пропорции области выделения
|
||||||
|
if ( pimpl->isProportionFixed ) {
|
||||||
|
float croppintRectSideRelation =
|
||||||
|
(float)pimpl->croppingRect.width() / pimpl->croppingRect.height();
|
||||||
|
float proportionSideRelation =
|
||||||
|
(float)pimpl->proportion.width() / pimpl->proportion.height();
|
||||||
|
// Если область выделения не соответствует необходимым пропорциям обновим её
|
||||||
|
if (croppintRectSideRelation != proportionSideRelation) {
|
||||||
|
bool widthShotrerThenHeight =
|
||||||
|
pimpl->croppingRect.width() < pimpl->croppingRect.height();
|
||||||
|
// ... установим размер той стороны, что длиннее
|
||||||
|
if (widthShotrerThenHeight) {
|
||||||
|
pimpl->croppingRect.setHeight(
|
||||||
|
pimpl->croppingRect.width() * pimpl->deltas.height());
|
||||||
|
} else {
|
||||||
|
pimpl->croppingRect.setWidth(
|
||||||
|
pimpl->croppingRect.height() * pimpl->deltas.width());
|
||||||
|
}
|
||||||
|
// ... перерисуем виджет
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageCropper::setProportionFixed(const bool _isFixed)
|
||||||
|
{
|
||||||
|
if (pimpl->isProportionFixed != _isFixed) {
|
||||||
|
pimpl->isProportionFixed = _isFixed;
|
||||||
|
setProportion(pimpl->proportion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const QPixmap ImageCropper::cropImage()
|
||||||
|
{
|
||||||
|
// Получим размер отображаемого изображения
|
||||||
|
QSize scaledImageSize =
|
||||||
|
pimpl->imageForCropping.scaled(
|
||||||
|
this->size(), Qt::KeepAspectRatio, Qt::FastTransformation
|
||||||
|
).size();
|
||||||
|
// Определим расстояние от левого и верхнего краёв
|
||||||
|
float leftDelta = 0;
|
||||||
|
float topDelta = 0;
|
||||||
|
const float HALF_COUNT = 2;
|
||||||
|
if (this->size().height() == scaledImageSize.height()) {
|
||||||
|
leftDelta = (this->width() - scaledImageSize.width()) / HALF_COUNT;
|
||||||
|
} else {
|
||||||
|
topDelta = (this->height() - scaledImageSize.height()) / HALF_COUNT;
|
||||||
|
}
|
||||||
|
// Определим пропорцию области обрезки по отношению к исходному изображению
|
||||||
|
float xScale = (float)pimpl->imageForCropping.width() / scaledImageSize.width();
|
||||||
|
float yScale = (float)pimpl->imageForCropping.height() / scaledImageSize.height();
|
||||||
|
// Расчитаем область обрезки с учётом коррекции размеров исходного изображения
|
||||||
|
QRectF realSizeRect(
|
||||||
|
QPointF(pimpl->croppingRect.left() - leftDelta, pimpl->croppingRect.top() - topDelta),
|
||||||
|
pimpl->croppingRect.size());
|
||||||
|
// ... корректируем левый и верхний края
|
||||||
|
realSizeRect.setLeft((pimpl->croppingRect.left() - leftDelta) * xScale);
|
||||||
|
realSizeRect.setTop ((pimpl->croppingRect.top() - topDelta) * yScale);
|
||||||
|
// ... корректируем размер
|
||||||
|
realSizeRect.setWidth(pimpl->croppingRect.width() * xScale);
|
||||||
|
realSizeRect.setHeight(pimpl->croppingRect.height() * yScale);
|
||||||
|
// Получаем обрезанное изображение
|
||||||
|
return pimpl->imageForCropping.copy(realSizeRect.toRect());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ********
|
||||||
|
// Protected section
|
||||||
|
|
||||||
|
void ImageCropper::paintEvent(QPaintEvent* _event)
|
||||||
|
{
|
||||||
|
QWidget::paintEvent( _event );
|
||||||
|
//
|
||||||
|
QPainter widgetPainter(this);
|
||||||
|
// Рисуем изображение по центру виджета
|
||||||
|
{
|
||||||
|
// ... подгоним изображение для отображения по размеру виджета
|
||||||
|
QPixmap scaledImage =
|
||||||
|
pimpl->imageForCropping.scaled(this->size(), Qt::KeepAspectRatio, Qt::FastTransformation);
|
||||||
|
// ... заливаем фон
|
||||||
|
widgetPainter.fillRect( this->rect(), pimpl->backgroundColor );
|
||||||
|
// ... рисуем изображение по центру виджета
|
||||||
|
if ( this->size().height() == scaledImage.height() ) {
|
||||||
|
widgetPainter.drawPixmap( ( this->width() - scaledImage.width() ) / 2, 0, scaledImage );
|
||||||
|
} else {
|
||||||
|
widgetPainter.drawPixmap( 0, ( this->height() - scaledImage.height() ) / 2, scaledImage );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Рисуем область обрезки
|
||||||
|
{
|
||||||
|
// ... если это первое отображение после инициилизации, то центруем областо обрезки
|
||||||
|
if (pimpl->croppingRect.isNull()) {
|
||||||
|
const int width = WIDGET_MINIMUM_SIZE.width()/2;
|
||||||
|
const int height = WIDGET_MINIMUM_SIZE.height()/2;
|
||||||
|
pimpl->croppingRect.setSize(QSize(width, height));
|
||||||
|
float x = (this->width() - pimpl->croppingRect.width())/2;
|
||||||
|
float y = (this->height() - pimpl->croppingRect.height())/2;
|
||||||
|
pimpl->croppingRect.moveTo(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... рисуем затемненную область
|
||||||
|
QPainterPath p;
|
||||||
|
p.addRect(pimpl->croppingRect);
|
||||||
|
p.addRect(this->rect());
|
||||||
|
widgetPainter.setBrush(QBrush(QColor(0,0,0,120)));
|
||||||
|
widgetPainter.setPen(Qt::transparent);
|
||||||
|
widgetPainter.drawPath(p);
|
||||||
|
// Рамка и контрольные точки
|
||||||
|
widgetPainter.setPen(pimpl->croppingRectBorderColor);
|
||||||
|
// ... рисуем прямоугольник области обрезки
|
||||||
|
{
|
||||||
|
widgetPainter.setBrush(QBrush(Qt::transparent));
|
||||||
|
widgetPainter.drawRect(pimpl->croppingRect);
|
||||||
|
}
|
||||||
|
// ... рисуем контрольные точки
|
||||||
|
{
|
||||||
|
widgetPainter.setBrush(QBrush(pimpl->croppingRectBorderColor));
|
||||||
|
// Вспомогательные X координаты
|
||||||
|
int leftXCoord = pimpl->croppingRect.left() - 2;
|
||||||
|
int centerXCoord = pimpl->croppingRect.center().x() - 3;
|
||||||
|
int rightXCoord = pimpl->croppingRect.right() - 2;
|
||||||
|
// Вспомогательные Y координаты
|
||||||
|
int topYCoord = pimpl->croppingRect.top() - 2;
|
||||||
|
int middleYCoord = pimpl->croppingRect.center().y() - 3;
|
||||||
|
int bottomYCoord = pimpl->croppingRect.bottom() - 2;
|
||||||
|
//
|
||||||
|
const QSize pointSize(6, 6);
|
||||||
|
//
|
||||||
|
QVector<QRect> points;
|
||||||
|
points
|
||||||
|
// левая сторона
|
||||||
|
<< QRect( QPoint(leftXCoord, topYCoord), pointSize )
|
||||||
|
<< QRect( QPoint(leftXCoord, middleYCoord), pointSize )
|
||||||
|
<< QRect( QPoint(leftXCoord, bottomYCoord), pointSize )
|
||||||
|
// центр
|
||||||
|
<< QRect( QPoint(centerXCoord, topYCoord), pointSize )
|
||||||
|
<< QRect( QPoint(centerXCoord, middleYCoord), pointSize )
|
||||||
|
<< QRect( QPoint(centerXCoord, bottomYCoord), pointSize )
|
||||||
|
// правая сторона
|
||||||
|
<< QRect( QPoint(rightXCoord, topYCoord), pointSize )
|
||||||
|
<< QRect( QPoint(rightXCoord, middleYCoord), pointSize )
|
||||||
|
<< QRect( QPoint(rightXCoord, bottomYCoord), pointSize );
|
||||||
|
//
|
||||||
|
widgetPainter.drawRects( points );
|
||||||
|
}
|
||||||
|
// ... рисуем пунктирные линии
|
||||||
|
{
|
||||||
|
QPen dashPen(pimpl->croppingRectBorderColor);
|
||||||
|
dashPen.setStyle(Qt::DashLine);
|
||||||
|
widgetPainter.setPen(dashPen);
|
||||||
|
// ... вертикальная
|
||||||
|
widgetPainter.drawLine(
|
||||||
|
QPoint(pimpl->croppingRect.center().x(), pimpl->croppingRect.top()),
|
||||||
|
QPoint(pimpl->croppingRect.center().x(), pimpl->croppingRect.bottom()) );
|
||||||
|
// ... горизонтальная
|
||||||
|
widgetPainter.drawLine(
|
||||||
|
QPoint(pimpl->croppingRect.left(), pimpl->croppingRect.center().y()),
|
||||||
|
QPoint(pimpl->croppingRect.right(), pimpl->croppingRect.center().y()) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
widgetPainter.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageCropper::mousePressEvent(QMouseEvent* _event)
|
||||||
|
{
|
||||||
|
if (_event->button() == Qt::LeftButton) {
|
||||||
|
pimpl->isMousePressed = true;
|
||||||
|
pimpl->startMousePos = _event->pos();
|
||||||
|
pimpl->lastStaticCroppingRect = pimpl->croppingRect;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
updateCursorIcon(_event->pos());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageCropper::mouseMoveEvent(QMouseEvent* _event)
|
||||||
|
{
|
||||||
|
QPointF mousePos = _event->pos(); // относительно себя (виджета)
|
||||||
|
//
|
||||||
|
if (!pimpl->isMousePressed) {
|
||||||
|
// Обработка обычного состояния, т.е. не изменяется размер
|
||||||
|
// области обрезки, и она не перемещается по виджету
|
||||||
|
pimpl->cursorPosition = cursorPosition(pimpl->croppingRect, mousePos);
|
||||||
|
updateCursorIcon(mousePos);
|
||||||
|
} else if (pimpl->cursorPosition != CursorPositionUndefined) {
|
||||||
|
// Обработка действий над областью обрезки
|
||||||
|
// ... определим смещение курсора мышки
|
||||||
|
QPointF mouseDelta;
|
||||||
|
mouseDelta.setX( mousePos.x() - pimpl->startMousePos.x() );
|
||||||
|
mouseDelta.setY( mousePos.y() - pimpl->startMousePos.y() );
|
||||||
|
//
|
||||||
|
if (pimpl->cursorPosition != CursorPositionMiddle) {
|
||||||
|
// ... изменяем размер области обрезки
|
||||||
|
QRectF newGeometry =
|
||||||
|
calculateGeometry(
|
||||||
|
pimpl->lastStaticCroppingRect,
|
||||||
|
pimpl->cursorPosition,
|
||||||
|
mouseDelta);
|
||||||
|
// ... пользователь пытается вывернуть область обрезки наизнанку
|
||||||
|
if (!newGeometry.isNull()) {
|
||||||
|
pimpl->croppingRect = newGeometry;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// ... перемещаем область обрезки
|
||||||
|
pimpl->croppingRect.moveTo( pimpl->lastStaticCroppingRect.topLeft() + mouseDelta );
|
||||||
|
}
|
||||||
|
// Перерисуем виджет
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageCropper::mouseReleaseEvent(QMouseEvent* _event)
|
||||||
|
{
|
||||||
|
pimpl->isMousePressed = false;
|
||||||
|
updateCursorIcon(_event->pos());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ********
|
||||||
|
// Private section
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// Находится ли точка рядом с координатой стороны
|
||||||
|
static bool isPointNearSide (const int _sideCoordinate, const int _pointCoordinate)
|
||||||
|
{
|
||||||
|
static const int indent = 10;
|
||||||
|
return (_sideCoordinate - indent) < _pointCoordinate && _pointCoordinate < (_sideCoordinate + indent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CursorPosition ImageCropper::cursorPosition(const QRectF& _cropRect, const QPointF& _mousePosition)
|
||||||
|
{
|
||||||
|
CursorPosition cursorPosition = CursorPositionUndefined;
|
||||||
|
//
|
||||||
|
if ( _cropRect.contains( _mousePosition ) ) {
|
||||||
|
// Двухстороннее направление
|
||||||
|
if (isPointNearSide(_cropRect.top(), _mousePosition.y()) &&
|
||||||
|
isPointNearSide(_cropRect.left(), _mousePosition.x())) {
|
||||||
|
cursorPosition = CursorPositionTopLeft;
|
||||||
|
} else if (isPointNearSide(_cropRect.bottom(), _mousePosition.y()) &&
|
||||||
|
isPointNearSide(_cropRect.left(), _mousePosition.x())) {
|
||||||
|
cursorPosition = CursorPositionBottomLeft;
|
||||||
|
} else if (isPointNearSide(_cropRect.top(), _mousePosition.y()) &&
|
||||||
|
isPointNearSide(_cropRect.right(), _mousePosition.x())) {
|
||||||
|
cursorPosition = CursorPositionTopRight;
|
||||||
|
} else if (isPointNearSide(_cropRect.bottom(), _mousePosition.y()) &&
|
||||||
|
isPointNearSide(_cropRect.right(), _mousePosition.x())) {
|
||||||
|
cursorPosition = CursorPositionBottomRight;
|
||||||
|
// Одностороннее направление
|
||||||
|
} else if (isPointNearSide(_cropRect.left(), _mousePosition.x())) {
|
||||||
|
cursorPosition = CursorPositionLeft;
|
||||||
|
} else if (isPointNearSide(_cropRect.right(), _mousePosition.x())) {
|
||||||
|
cursorPosition = CursorPositionRight;
|
||||||
|
} else if (isPointNearSide(_cropRect.top(), _mousePosition.y())) {
|
||||||
|
cursorPosition = CursorPositionTop;
|
||||||
|
} else if (isPointNearSide(_cropRect.bottom(), _mousePosition.y())) {
|
||||||
|
cursorPosition = CursorPositionBottom;
|
||||||
|
// Без направления
|
||||||
|
} else {
|
||||||
|
cursorPosition = CursorPositionMiddle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
return cursorPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageCropper::updateCursorIcon(const QPointF& _mousePosition)
|
||||||
|
{
|
||||||
|
QCursor cursorIcon;
|
||||||
|
//
|
||||||
|
switch (cursorPosition(pimpl->croppingRect, _mousePosition))
|
||||||
|
{
|
||||||
|
case CursorPositionTopRight:
|
||||||
|
case CursorPositionBottomLeft:
|
||||||
|
cursorIcon = QCursor(Qt::SizeBDiagCursor);
|
||||||
|
break;
|
||||||
|
case CursorPositionTopLeft:
|
||||||
|
case CursorPositionBottomRight:
|
||||||
|
cursorIcon = QCursor(Qt::SizeFDiagCursor);
|
||||||
|
break;
|
||||||
|
case CursorPositionTop:
|
||||||
|
case CursorPositionBottom:
|
||||||
|
cursorIcon = QCursor(Qt::SizeVerCursor);
|
||||||
|
break;
|
||||||
|
case CursorPositionLeft:
|
||||||
|
case CursorPositionRight:
|
||||||
|
cursorIcon = QCursor(Qt::SizeHorCursor);
|
||||||
|
break;
|
||||||
|
case CursorPositionMiddle:
|
||||||
|
cursorIcon = pimpl->isMousePressed ?
|
||||||
|
QCursor(Qt::ClosedHandCursor) :
|
||||||
|
QCursor(Qt::OpenHandCursor);
|
||||||
|
break;
|
||||||
|
case CursorPositionUndefined:
|
||||||
|
default:
|
||||||
|
cursorIcon = QCursor(Qt::ArrowCursor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
this->setCursor(cursorIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
const QRectF ImageCropper::calculateGeometry(
|
||||||
|
const QRectF& _sourceGeometry,
|
||||||
|
const CursorPosition _cursorPosition,
|
||||||
|
const QPointF& _mouseDelta
|
||||||
|
)
|
||||||
|
{
|
||||||
|
QRectF resultGeometry;
|
||||||
|
//
|
||||||
|
if ( pimpl->isProportionFixed ) {
|
||||||
|
resultGeometry =
|
||||||
|
calculateGeometryWithFixedProportions(
|
||||||
|
_sourceGeometry, _cursorPosition, _mouseDelta, pimpl->deltas);
|
||||||
|
} else {
|
||||||
|
resultGeometry =
|
||||||
|
calculateGeometryWithCustomProportions(
|
||||||
|
_sourceGeometry, _cursorPosition, _mouseDelta);
|
||||||
|
}
|
||||||
|
// Если пользователь пытается вывернуть область обрезки наизнанку,
|
||||||
|
// возвращаем null-прямоугольник
|
||||||
|
if ((resultGeometry.left() >= resultGeometry.right()) ||
|
||||||
|
(resultGeometry.top() >= resultGeometry.bottom())) {
|
||||||
|
resultGeometry = QRect();
|
||||||
|
}
|
||||||
|
//
|
||||||
|
return resultGeometry;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QRectF ImageCropper::calculateGeometryWithCustomProportions(
|
||||||
|
const QRectF& _sourceGeometry,
|
||||||
|
const CursorPosition _cursorPosition,
|
||||||
|
const QPointF& _mouseDelta
|
||||||
|
)
|
||||||
|
{
|
||||||
|
QRectF resultGeometry = _sourceGeometry;
|
||||||
|
//
|
||||||
|
switch ( _cursorPosition )
|
||||||
|
{
|
||||||
|
case CursorPositionTopLeft:
|
||||||
|
resultGeometry.setLeft( _sourceGeometry.left() + _mouseDelta.x() );
|
||||||
|
resultGeometry.setTop ( _sourceGeometry.top() + _mouseDelta.y() );
|
||||||
|
break;
|
||||||
|
case CursorPositionTopRight:
|
||||||
|
resultGeometry.setTop ( _sourceGeometry.top() + _mouseDelta.y() );
|
||||||
|
resultGeometry.setRight( _sourceGeometry.right() + _mouseDelta.x() );
|
||||||
|
break;
|
||||||
|
case CursorPositionBottomLeft:
|
||||||
|
resultGeometry.setBottom( _sourceGeometry.bottom() + _mouseDelta.y() );
|
||||||
|
resultGeometry.setLeft ( _sourceGeometry.left() + _mouseDelta.x() );
|
||||||
|
break;
|
||||||
|
case CursorPositionBottomRight:
|
||||||
|
resultGeometry.setBottom( _sourceGeometry.bottom() + _mouseDelta.y() );
|
||||||
|
resultGeometry.setRight ( _sourceGeometry.right() + _mouseDelta.x() );
|
||||||
|
break;
|
||||||
|
case CursorPositionTop:
|
||||||
|
resultGeometry.setTop( _sourceGeometry.top() + _mouseDelta.y() );
|
||||||
|
break;
|
||||||
|
case CursorPositionBottom:
|
||||||
|
resultGeometry.setBottom( _sourceGeometry.bottom() + _mouseDelta.y() );
|
||||||
|
break;
|
||||||
|
case CursorPositionLeft:
|
||||||
|
resultGeometry.setLeft( _sourceGeometry.left() + _mouseDelta.x() );
|
||||||
|
break;
|
||||||
|
case CursorPositionRight:
|
||||||
|
resultGeometry.setRight( _sourceGeometry.right() + _mouseDelta.x() );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
return resultGeometry;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QRectF ImageCropper::calculateGeometryWithFixedProportions(
|
||||||
|
const QRectF& _sourceGeometry,
|
||||||
|
const CursorPosition _cursorPosition,
|
||||||
|
const QPointF& _mouseDelta,
|
||||||
|
const QSizeF& _deltas
|
||||||
|
)
|
||||||
|
{
|
||||||
|
QRectF resultGeometry = _sourceGeometry;
|
||||||
|
//
|
||||||
|
switch (_cursorPosition)
|
||||||
|
{
|
||||||
|
case CursorPositionLeft:
|
||||||
|
resultGeometry.setTop(_sourceGeometry.top() + _mouseDelta.x() * _deltas.height());
|
||||||
|
resultGeometry.setLeft(_sourceGeometry.left() + _mouseDelta.x());
|
||||||
|
break;
|
||||||
|
case CursorPositionRight:
|
||||||
|
resultGeometry.setTop(_sourceGeometry.top() - _mouseDelta.x() * _deltas.height());
|
||||||
|
resultGeometry.setRight(_sourceGeometry.right() + _mouseDelta.x());
|
||||||
|
break;
|
||||||
|
case CursorPositionTop:
|
||||||
|
resultGeometry.setTop(_sourceGeometry.top() + _mouseDelta.y());
|
||||||
|
resultGeometry.setRight(_sourceGeometry.right() - _mouseDelta.y() * _deltas.width());
|
||||||
|
break;
|
||||||
|
case CursorPositionBottom:
|
||||||
|
resultGeometry.setBottom(_sourceGeometry.bottom() + _mouseDelta.y());
|
||||||
|
resultGeometry.setRight(_sourceGeometry.right() + _mouseDelta.y() * _deltas.width());
|
||||||
|
break;
|
||||||
|
case CursorPositionTopLeft:
|
||||||
|
if ((_mouseDelta.x() * _deltas.height()) < (_mouseDelta.y())) {
|
||||||
|
resultGeometry.setTop(_sourceGeometry.top() + _mouseDelta.x() * _deltas.height());
|
||||||
|
resultGeometry.setLeft(_sourceGeometry.left() + _mouseDelta.x());
|
||||||
|
} else {
|
||||||
|
resultGeometry.setTop(_sourceGeometry.top() + _mouseDelta.y());
|
||||||
|
resultGeometry.setLeft(_sourceGeometry.left() + _mouseDelta.y() * _deltas.width());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CursorPositionTopRight:
|
||||||
|
if ((_mouseDelta.x() * _deltas.height() * -1) < (_mouseDelta.y())) {
|
||||||
|
resultGeometry.setTop(_sourceGeometry.top() - _mouseDelta.x() * _deltas.height());
|
||||||
|
resultGeometry.setRight(_sourceGeometry.right() + _mouseDelta.x() );
|
||||||
|
} else {
|
||||||
|
resultGeometry.setTop(_sourceGeometry.top() + _mouseDelta.y());
|
||||||
|
resultGeometry.setRight(_sourceGeometry.right() - _mouseDelta.y() * _deltas.width());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CursorPositionBottomLeft:
|
||||||
|
if ((_mouseDelta.x() * _deltas.height()) < (_mouseDelta.y() * -1)) {
|
||||||
|
resultGeometry.setBottom(_sourceGeometry.bottom() - _mouseDelta.x() * _deltas.height());
|
||||||
|
resultGeometry.setLeft(_sourceGeometry.left() + _mouseDelta.x());
|
||||||
|
} else {
|
||||||
|
resultGeometry.setBottom(_sourceGeometry.bottom() + _mouseDelta.y());
|
||||||
|
resultGeometry.setLeft(_sourceGeometry.left() - _mouseDelta.y() * _deltas.width());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CursorPositionBottomRight:
|
||||||
|
if ((_mouseDelta.x() * _deltas.height()) > (_mouseDelta.y())) {
|
||||||
|
resultGeometry.setBottom(_sourceGeometry.bottom() + _mouseDelta.x() * _deltas.height());
|
||||||
|
resultGeometry.setRight(_sourceGeometry.right() + _mouseDelta.x());
|
||||||
|
} else {
|
||||||
|
resultGeometry.setBottom(_sourceGeometry.bottom() + _mouseDelta.y());
|
||||||
|
resultGeometry.setRight(_sourceGeometry.right() + _mouseDelta.y() * _deltas.width());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
return resultGeometry;
|
||||||
|
}
|
||||||
|
|
103
anpro/imagecropper.h
Normal file
103
anpro/imagecropper.h
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* ImageCropper Qt Widget for cropping images
|
||||||
|
* Copyright (C) 2013 Dimka Novikov, to@dimkanovikov.pro
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef IMAGECROPPER_H
|
||||||
|
#define IMAGECROPPER_H
|
||||||
|
|
||||||
|
#include "imagecropper_p.h"
|
||||||
|
#include "imagecropper_e.h"
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class ImageCropper : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ImageCropper(QWidget *parent = 0);
|
||||||
|
~ImageCropper();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
// Установить изображение для обрезки
|
||||||
|
void setImage(const QPixmap& _image);
|
||||||
|
// Установить цвет фона виджета обрезки
|
||||||
|
void setBackgroundColor(const QColor& _backgroundColor);
|
||||||
|
// Установить цвет рамки области обрезки
|
||||||
|
void setCroppingRectBorderColor(const QColor& _borderColor);
|
||||||
|
// Установить пропорции области выделения
|
||||||
|
void setProportion(const QSizeF& _proportion);
|
||||||
|
// Использовать фиксированные пропорции области виделения
|
||||||
|
void setProportionFixed(const bool _isFixed);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Обрезать изображение
|
||||||
|
const QPixmap cropImage();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void paintEvent(QPaintEvent* _event);
|
||||||
|
virtual void mousePressEvent(QMouseEvent* _event);
|
||||||
|
virtual void mouseMoveEvent(QMouseEvent* _event);
|
||||||
|
virtual void mouseReleaseEvent(QMouseEvent* _event);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Определение местоположения курсора над виджетом
|
||||||
|
CursorPosition cursorPosition(const QRectF& _cropRect, const QPointF& _mousePosition);
|
||||||
|
// Обновить иконку курсора соответствующую местоположению мыши
|
||||||
|
void updateCursorIcon(const QPointF& _mousePosition);
|
||||||
|
|
||||||
|
// Получить размер виджета после его изменения мышью
|
||||||
|
// --------
|
||||||
|
// Контракты:
|
||||||
|
// 1. Метод должен вызываться, только при зажатой кнопке мыши
|
||||||
|
// (т.е. при перемещении или изменении размера виджета)
|
||||||
|
// --------
|
||||||
|
// В случае неудачи возвращает null-прямоугольник
|
||||||
|
const QRectF calculateGeometry(
|
||||||
|
const QRectF& _sourceGeometry,
|
||||||
|
const CursorPosition _cursorPosition,
|
||||||
|
const QPointF& _mouseDelta
|
||||||
|
);
|
||||||
|
// Получить размер виджета после его изменения мышью
|
||||||
|
// Метод изменяет виджет не сохраняя начальных пропорций сторон
|
||||||
|
// ------
|
||||||
|
// Контракты:
|
||||||
|
// 1. Метод должен вызываться, только при зажатой кнопке мыши
|
||||||
|
// (т.е. при перемещении или изменении размера виджета)
|
||||||
|
const QRectF calculateGeometryWithCustomProportions(
|
||||||
|
const QRectF& _sourceGeometry,
|
||||||
|
const CursorPosition _cursorPosition,
|
||||||
|
const QPointF& _mouseDelta
|
||||||
|
);
|
||||||
|
// Получить размер виджета после его изменения мышью
|
||||||
|
// Метод изменяет виджет сохраняя начальные пропорции сторон
|
||||||
|
// ------
|
||||||
|
// Контракты:
|
||||||
|
// 1. Метод должен вызываться, только при зажатой кнопке мыши
|
||||||
|
// (т.е. при перемещении или изменении размера виджета)
|
||||||
|
const QRectF calculateGeometryWithFixedProportions(const QRectF &_sourceGeometry,
|
||||||
|
const CursorPosition _cursorPosition,
|
||||||
|
const QPointF &_mouseDelta,
|
||||||
|
const QSizeF &_deltas
|
||||||
|
);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Private data implementation
|
||||||
|
ImageCropperPrivate* pimpl;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // IMAGECROPPER_H
|
36
anpro/imagecropper_e.h
Normal file
36
anpro/imagecropper_e.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* ImageCropper Qt Widget for cropping images
|
||||||
|
* Copyright (C) 2013 Dimka Novikov, to@dimkanovikov.pro
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef IMAGECROPPER_E_H
|
||||||
|
#define IMAGECROPPER_E_H
|
||||||
|
|
||||||
|
enum CursorPosition
|
||||||
|
{
|
||||||
|
CursorPositionUndefined,
|
||||||
|
CursorPositionMiddle,
|
||||||
|
CursorPositionTop,
|
||||||
|
CursorPositionBottom,
|
||||||
|
CursorPositionLeft,
|
||||||
|
CursorPositionRight,
|
||||||
|
CursorPositionTopLeft,
|
||||||
|
CursorPositionTopRight,
|
||||||
|
CursorPositionBottomLeft,
|
||||||
|
CursorPositionBottomRight
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // IMAGECROPPER_E_H
|
76
anpro/imagecropper_p.h
Normal file
76
anpro/imagecropper_p.h
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* ImageCropper Qt Widget for cropping images
|
||||||
|
* Copyright (C) 2013 Dimka Novikov, to@dimkanovikov.pro
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef IMAGECROPPER_P_H
|
||||||
|
#define IMAGECROPPER_P_H
|
||||||
|
|
||||||
|
#include "imagecropper_e.h"
|
||||||
|
|
||||||
|
#include <QtCore/QRect>
|
||||||
|
#include <QtGui/QPixmap>
|
||||||
|
#include <QtGui/QColor>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const QRect INIT_CROPPING_RECT = QRect();
|
||||||
|
const QSizeF INIT_PROPORTION = QSizeF(1.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ImageCropperPrivate {
|
||||||
|
public:
|
||||||
|
ImageCropperPrivate() :
|
||||||
|
imageForCropping(QPixmap()),
|
||||||
|
croppingRect(INIT_CROPPING_RECT),
|
||||||
|
lastStaticCroppingRect(QRect()),
|
||||||
|
cursorPosition(CursorPositionUndefined),
|
||||||
|
isMousePressed(false),
|
||||||
|
isProportionFixed(false),
|
||||||
|
startMousePos(QPoint()),
|
||||||
|
proportion(INIT_PROPORTION),
|
||||||
|
deltas(INIT_PROPORTION),
|
||||||
|
backgroundColor(Qt::black),
|
||||||
|
croppingRectBorderColor(Qt::white)
|
||||||
|
{}
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Изображение для обрезки
|
||||||
|
QPixmap imageForCropping;
|
||||||
|
// Область обрезки
|
||||||
|
QRectF croppingRect;
|
||||||
|
// Последняя фиксированная область обрезки
|
||||||
|
QRectF lastStaticCroppingRect;
|
||||||
|
// Позиция курсора относительно области обрезки
|
||||||
|
CursorPosition cursorPosition;
|
||||||
|
// Зажата ли левая кнопка мыши
|
||||||
|
bool isMousePressed;
|
||||||
|
// Фиксировать пропорции области обрезки
|
||||||
|
bool isProportionFixed;
|
||||||
|
// Начальная позиция курсора при изменении размера области обрезки
|
||||||
|
QPointF startMousePos;
|
||||||
|
// Пропорции
|
||||||
|
QSizeF proportion;
|
||||||
|
// Приращения
|
||||||
|
// width - приращение по x
|
||||||
|
// height - приращение по y
|
||||||
|
QSizeF deltas;
|
||||||
|
// Цвет заливки фона под изображением
|
||||||
|
QColor backgroundColor;
|
||||||
|
// Цвет рамки области обрезки
|
||||||
|
QColor croppingRectBorderColor;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // IMAGECROPPER_P_H
|
155
config.h
Normal file
155
config.h
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 Profile Viewer
|
||||||
|
* Copyright (C) 2016-2018 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
|
||||||
|
|
||||||
|
#if __cplusplus
|
||||||
|
#include <QString>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GTA5SYNC_APPVENDOR
|
||||||
|
#define GTA5SYNC_APPVENDOR "Syping"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GTA5SYNC_APPVENDORLINK
|
||||||
|
#define GTA5SYNC_APPVENDORLINK "g5e://about?U3lwaW5n:R2l0TGFiOiA8YSBocmVmPSJodHRwczovL2dpdGxhYi5jb20vU3lwaW5nIj5TeXBpbmc8L2E+PGJyLz5HaXRIdWI6IDxhIGhyZWY9Imh0dHBzOi8vZ2l0aHViLmNvbS9TeXBpbmciPlN5cGluZzwvYT48YnIvPlNvY2lhbCBDbHViOiA8YSBocmVmPSJodHRwczovL3NvY2lhbGNsdWIucm9ja3N0YXJnYW1lcy5jb20vbWVtYmVyL1N5cGluZy80NjMwMzA1NiI+U3lwaW5nPC9hPg=="
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GTA5SYNC_APPSTR
|
||||||
|
#define GTA5SYNC_APPSTR "rdr2view"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GTA5SYNC_APPDES
|
||||||
|
#define GTA5SYNC_APPDES "INSERT YOUR APPLICATION DESCRIPTION HERE"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GTA5SYNC_COPYRIGHT
|
||||||
|
#define GTA5SYNC_COPYRIGHT "2016-2019"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GTA5SYNC_APPVER
|
||||||
|
#define GTA5SYNC_APPVER "0.1.0"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __cplusplus
|
||||||
|
#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
|
||||||
|
|
||||||
|
#ifndef GTA5SYNC_BUILDTYPE
|
||||||
|
#define GTA5SYNC_BUILDTYPE QT_TRANSLATE_NOOP("AboutDialog", "Custom")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GTA5SYNC_BUILDCODE
|
||||||
|
#define GTA5SYNC_BUILDCODE "Source"
|
||||||
|
#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__
|
||||||
|
#ifndef Q_OS_MAC
|
||||||
|
#define GTA5SYNC_COMPILER QString("Clang %1.%2.%3").arg(QString::number(__clang_major__), QString::number(__clang_minor__), QString::number(__clang_patchlevel__))
|
||||||
|
#else
|
||||||
|
#define GTA5SYNC_COMPILER QString("Apple LLVM %1.%2.%3").arg(QString::number(__clang_major__), QString::number(__clang_minor__), QString::number(__clang_patchlevel__))
|
||||||
|
#endif
|
||||||
|
#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
|
||||||
|
|
||||||
|
#endif // CONFIG_H
|
5
lang/README.txt
Normal file
5
lang/README.txt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
Community translation files
|
||||||
|
|
||||||
|
They get loaded in ApplicationPathExecFileFolder/lang
|
||||||
|
|
||||||
|
You can help translate with using Qt Linguist, after you've translated you'll need to send me a pull request on https://github.com/SyDevTeam/gta5view
|
320
main.cpp
Normal file
320
main.cpp
Normal file
|
@ -0,0 +1,320 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* rdr2view Red Dead Redemption 2 Profile Viewer
|
||||||
|
* Copyright (C) 2016-2019 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 "OptionsDialog.h"
|
||||||
|
#include "PictureDialog.h"
|
||||||
|
#include "UserInterface.h"
|
||||||
|
#include "CrewDatabase.h"
|
||||||
|
#include "SavegameData.h"
|
||||||
|
#include "UiModWidget.h"
|
||||||
|
#include "UiModLabel.h"
|
||||||
|
#include "IconLoader.h"
|
||||||
|
#include "AppEnv.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include <QDesktopWidget>
|
||||||
|
#include <QStringBuilder>
|
||||||
|
#include <QSignalMapper>
|
||||||
|
#include <QStyleFactory>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QSpacerItem>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QTranslator>
|
||||||
|
#include <QResource>
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QSysInfo>
|
||||||
|
#include <QLayout>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFont>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
|
#ifdef GTA5SYNC_WIN
|
||||||
|
#include "windows.h"
|
||||||
|
#include <iostream>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GTA5SYNC_TELEMETRY
|
||||||
|
#include "TelemetryClass.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
#if QT_VERSION >= 0x050600
|
||||||
|
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true);
|
||||||
|
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true);
|
||||||
|
#endif
|
||||||
|
QApplication a(argc, argv);
|
||||||
|
a.setApplicationName(GTA5SYNC_APPSTR);
|
||||||
|
a.setApplicationVersion(GTA5SYNC_APPVER);
|
||||||
|
a.setQuitOnLastWindowClosed(false);
|
||||||
|
|
||||||
|
QResource::registerResource(":/global/global.rcc");
|
||||||
|
|
||||||
|
QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||||
|
settings.beginGroup("Startup");
|
||||||
|
|
||||||
|
#ifdef GTA5SYNC_TELEMETRY
|
||||||
|
// Increase Start count at every startup
|
||||||
|
uint startCount = settings.value("StartCount", 0).toUInt();
|
||||||
|
startCount++;
|
||||||
|
settings.setValue("StartCount", startCount);
|
||||||
|
settings.sync();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool isFirstStart = settings.value("IsFirstStart", true).toBool();
|
||||||
|
bool customStyle = settings.value("CustomStyle", false).toBool();
|
||||||
|
QString appStyle = settings.value("AppStyle", "Default").toString();
|
||||||
|
|
||||||
|
if (customStyle)
|
||||||
|
{
|
||||||
|
if (QStyleFactory::keys().contains(appStyle, Qt::CaseInsensitive))
|
||||||
|
{
|
||||||
|
a.setStyle(QStyleFactory::create(appStyle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef GTA5SYNC_WIN
|
||||||
|
#if QT_VERSION >= 0x050400
|
||||||
|
bool alwaysUseMessageFont = settings.value("AlwaysUseMessageFont", false).toBool();
|
||||||
|
if (QSysInfo::windowsVersion() >= 0x0080 || alwaysUseMessageFont)
|
||||||
|
{
|
||||||
|
// 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
|
||||||
|
|
||||||
|
QStringList applicationArgs = a.arguments();
|
||||||
|
QString selectedAction;
|
||||||
|
QString arg1;
|
||||||
|
applicationArgs.removeAt(0);
|
||||||
|
|
||||||
|
Translator->initUserLanguage();
|
||||||
|
Translator->loadTranslation(&a);
|
||||||
|
|
||||||
|
#ifdef GTA5SYNC_TELEMETRY
|
||||||
|
Telemetry->init();
|
||||||
|
Telemetry->work();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!applicationArgs.contains("--skip-firststart"))
|
||||||
|
{
|
||||||
|
if (isFirstStart)
|
||||||
|
{
|
||||||
|
QMessageBox::StandardButton button = QMessageBox::information(a.desktop(), QString("%1 %2").arg(GTA5SYNC_APPSTR, GTA5SYNC_APPVER), QApplication::tr("<h4>Welcome to %1!</h4>You want to configure %1 before you start using it?").arg(GTA5SYNC_APPSTR), QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
||||||
|
if (button == QMessageBox::Yes)
|
||||||
|
{
|
||||||
|
ProfileDatabase profileDB;
|
||||||
|
OptionsDialog optionsDialog(&profileDB);
|
||||||
|
optionsDialog.setWindowIcon(IconLoader::loadingAppIcon());
|
||||||
|
optionsDialog.show();
|
||||||
|
optionsDialog.exec();
|
||||||
|
}
|
||||||
|
settings.setValue("IsFirstStart", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef GTA5SYNC_TELEMETRY
|
||||||
|
bool telemetryWindowLaunched = settings.value("PersonalUsageDataWindowLaunched", false).toBool();
|
||||||
|
bool pushUsageData = settings.value("PushUsageData", false).toBool();
|
||||||
|
if (!telemetryWindowLaunched && !pushUsageData)
|
||||||
|
{
|
||||||
|
QDialog *telemetryDialog = new QDialog();
|
||||||
|
telemetryDialog->setObjectName(QStringLiteral("TelemetryDialog"));
|
||||||
|
telemetryDialog->setWindowTitle(QString("%1 %2").arg(GTA5SYNC_APPSTR, GTA5SYNC_APPVER));
|
||||||
|
telemetryDialog->setWindowFlags(telemetryDialog->windowFlags()^Qt::WindowContextHelpButtonHint^Qt::WindowCloseButtonHint);
|
||||||
|
telemetryDialog->setWindowIcon(IconLoader::loadingAppIcon());
|
||||||
|
QVBoxLayout *telemetryLayout = new QVBoxLayout(telemetryDialog);
|
||||||
|
telemetryLayout->setObjectName(QStringLiteral("TelemetryLayout"));
|
||||||
|
telemetryDialog->setLayout(telemetryLayout);
|
||||||
|
UiModLabel *telemetryLabel = new UiModLabel(telemetryDialog);
|
||||||
|
telemetryLabel->setObjectName(QStringLiteral("TelemetryLabel"));
|
||||||
|
telemetryLabel->setText(QString("<h4>%2</h4>%1").arg(
|
||||||
|
QApplication::translate("TelemetryDialog", "You want help %1 to improve in the future by including personal usage data in your submission?").arg(GTA5SYNC_APPSTR),
|
||||||
|
QApplication::translate("TelemetryDialog", "%1 User Statistics").arg(GTA5SYNC_APPSTR)));
|
||||||
|
telemetryLayout->addWidget(telemetryLabel);
|
||||||
|
QCheckBox *telemetryCheckBox = new QCheckBox(telemetryDialog);
|
||||||
|
telemetryCheckBox->setObjectName(QStringLiteral("TelemetryCheckBox"));
|
||||||
|
telemetryCheckBox->setText(QApplication::translate("TelemetryDialog", "Yes, I want include personal usage data."));
|
||||||
|
telemetryLayout->addWidget(telemetryCheckBox);
|
||||||
|
QHBoxLayout *telemetryButtonLayout = new QHBoxLayout();
|
||||||
|
telemetryButtonLayout->setObjectName(QStringLiteral("TelemetryButtonLayout"));
|
||||||
|
telemetryLayout->addLayout(telemetryButtonLayout);
|
||||||
|
QSpacerItem *telemetryButtonSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||||
|
telemetryButtonLayout->addSpacerItem(telemetryButtonSpacer);
|
||||||
|
QPushButton *telemetryButton = new QPushButton(telemetryDialog);
|
||||||
|
telemetryButton->setObjectName(QStringLiteral("TelemetryButton"));
|
||||||
|
telemetryButton->setText(QApplication::translate("TelemetryDialog", "&OK"));
|
||||||
|
telemetryButtonLayout->addWidget(telemetryButton);
|
||||||
|
QObject::connect(telemetryButton, SIGNAL(clicked(bool)), telemetryDialog, SLOT(close()));
|
||||||
|
telemetryDialog->setFixedSize(telemetryDialog->sizeHint());
|
||||||
|
telemetryDialog->exec();
|
||||||
|
QObject::disconnect(telemetryButton, SIGNAL(clicked(bool)), telemetryDialog, SLOT(close()));
|
||||||
|
if (telemetryCheckBox->isChecked())
|
||||||
|
{
|
||||||
|
QSettings telemetrySettings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||||
|
telemetrySettings.beginGroup("Telemetry");
|
||||||
|
telemetrySettings.setValue("PushUsageData", true);
|
||||||
|
telemetrySettings.setValue("PushAppConf", true);
|
||||||
|
telemetrySettings.endGroup();
|
||||||
|
telemetrySettings.sync();
|
||||||
|
Telemetry->init();
|
||||||
|
Telemetry->work();
|
||||||
|
}
|
||||||
|
settings.setValue("PersonalUsageDataWindowLaunched", true);
|
||||||
|
delete telemetryDialog;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
settings.endGroup();
|
||||||
|
|
||||||
|
for (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 == "PRDR" || argumentFileExt == ".r5e")
|
||||||
|
{
|
||||||
|
arg1 = currentArg;
|
||||||
|
selectedAction = "showpic";
|
||||||
|
}
|
||||||
|
else if (argumentFileType == "SRDR")
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
#ifndef Q_OS_LINUX
|
||||||
|
picDialog.setWindowFlags(picDialog.windowFlags()^Qt::Dialog^Qt::Window);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int crewID = picture.getSnapmaticProperties().crewID;
|
||||||
|
if (crewID != 0) { crewDB.addCrew(crewID); }
|
||||||
|
if (!readOk) { return 1; }
|
||||||
|
|
||||||
|
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()), &a, SLOT(quit()));
|
||||||
|
QObject::connect(&picDialog, SIGNAL(endDatabaseThread()), &threadDB, SLOT(terminateThread()));
|
||||||
|
threadDB.start();
|
||||||
|
|
||||||
|
picDialog.show();
|
||||||
|
|
||||||
|
return a.exec();
|
||||||
|
}
|
||||||
|
else if (selectedAction == "showsgd")
|
||||||
|
{
|
||||||
|
SavegameDialog savegameDialog;
|
||||||
|
SavegameData savegame;
|
||||||
|
|
||||||
|
bool readOk = savegame.readingSavegameFromFile(arg1);
|
||||||
|
savegameDialog.setWindowIcon(IconLoader::loadingAppIcon());
|
||||||
|
savegameDialog.setSavegameData(&savegame, arg1, readOk);
|
||||||
|
savegameDialog.setWindowFlags(savegameDialog.windowFlags()^Qt::Dialog^Qt::Window);
|
||||||
|
|
||||||
|
if (!readOk) { return 1; }
|
||||||
|
|
||||||
|
a.setQuitOnLastWindowClosed(true);
|
||||||
|
savegameDialog.show();
|
||||||
|
|
||||||
|
return a.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
CrewDatabase crewDB;
|
||||||
|
ProfileDatabase profileDB;
|
||||||
|
DatabaseThread threadDB(&crewDB);
|
||||||
|
|
||||||
|
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()), &a, 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
|
||||||
|
|
||||||
|
return a.exec();
|
||||||
|
}
|
201
pcg/LICENSE.txt
Normal file
201
pcg/LICENSE.txt
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright {yyyy} {name of copyright owner}
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
116
pcg/pcg_basic.c
Normal file
116
pcg/pcg_basic.c
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
/*
|
||||||
|
* PCG Random Number Generation for C.
|
||||||
|
*
|
||||||
|
* Copyright 2014 Melissa O'Neill <oneill@pcg-random.org>
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For additional information about the PCG random number generation scheme,
|
||||||
|
* including its license and other licensing options, visit
|
||||||
|
*
|
||||||
|
* http://www.pcg-random.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is derived from the full C implementation, which is in turn
|
||||||
|
* derived from the canonical C++ PCG implementation. The C++ version
|
||||||
|
* has many additional features and is preferable if you can use C++ in
|
||||||
|
* your project.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pcg_basic.h"
|
||||||
|
|
||||||
|
// state for global RNGs
|
||||||
|
|
||||||
|
static pcg32_random_t pcg32_global = PCG32_INITIALIZER;
|
||||||
|
|
||||||
|
// pcg32_srandom(initstate, initseq)
|
||||||
|
// pcg32_srandom_r(rng, initstate, initseq):
|
||||||
|
// Seed the rng. Specified in two parts, state initializer and a
|
||||||
|
// sequence selection constant (a.k.a. stream id)
|
||||||
|
|
||||||
|
void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initstate, uint64_t initseq)
|
||||||
|
{
|
||||||
|
rng->state = 0U;
|
||||||
|
rng->inc = (initseq << 1u) | 1u;
|
||||||
|
pcg32_random_r(rng);
|
||||||
|
rng->state += initstate;
|
||||||
|
pcg32_random_r(rng);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pcg32_srandom(uint64_t seed, uint64_t seq)
|
||||||
|
{
|
||||||
|
pcg32_srandom_r(&pcg32_global, seed, seq);
|
||||||
|
}
|
||||||
|
|
||||||
|
// pcg32_random()
|
||||||
|
// pcg32_random_r(rng)
|
||||||
|
// Generate a uniformly distributed 32-bit random number
|
||||||
|
|
||||||
|
uint32_t pcg32_random_r(pcg32_random_t* rng)
|
||||||
|
{
|
||||||
|
uint64_t oldstate = rng->state;
|
||||||
|
rng->state = oldstate * 6364136223846793005ULL + rng->inc;
|
||||||
|
uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
|
||||||
|
uint32_t rot = oldstate >> 59u;
|
||||||
|
return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t pcg32_random()
|
||||||
|
{
|
||||||
|
return pcg32_random_r(&pcg32_global);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// pcg32_boundedrand(bound):
|
||||||
|
// pcg32_boundedrand_r(rng, bound):
|
||||||
|
// Generate a uniformly distributed number, r, where 0 <= r < bound
|
||||||
|
|
||||||
|
uint32_t pcg32_boundedrand_r(pcg32_random_t* rng, uint32_t bound)
|
||||||
|
{
|
||||||
|
// To avoid bias, we need to make the range of the RNG a multiple of
|
||||||
|
// bound, which we do by dropping output less than a threshold.
|
||||||
|
// A naive scheme to calculate the threshold would be to do
|
||||||
|
//
|
||||||
|
// uint32_t threshold = 0x100000000ull % bound;
|
||||||
|
//
|
||||||
|
// but 64-bit div/mod is slower than 32-bit div/mod (especially on
|
||||||
|
// 32-bit platforms). In essence, we do
|
||||||
|
//
|
||||||
|
// uint32_t threshold = (0x100000000ull-bound) % bound;
|
||||||
|
//
|
||||||
|
// because this version will calculate the same modulus, but the LHS
|
||||||
|
// value is less than 2^32.
|
||||||
|
|
||||||
|
uint32_t threshold = -bound % bound;
|
||||||
|
|
||||||
|
// Uniformity guarantees that this loop will terminate. In practice, it
|
||||||
|
// should usually terminate quickly; on average (assuming all bounds are
|
||||||
|
// equally likely), 82.25% of the time, we can expect it to require just
|
||||||
|
// one iteration. In the worst case, someone passes a bound of 2^31 + 1
|
||||||
|
// (i.e., 2147483649), which invalidates almost 50% of the range. In
|
||||||
|
// practice, bounds are typically small and only a tiny amount of the range
|
||||||
|
// is eliminated.
|
||||||
|
for (;;) {
|
||||||
|
uint32_t r = pcg32_random_r(rng);
|
||||||
|
if (r >= threshold)
|
||||||
|
return r % bound;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t pcg32_boundedrand(uint32_t bound)
|
||||||
|
{
|
||||||
|
return pcg32_boundedrand_r(&pcg32_global, bound);
|
||||||
|
}
|
||||||
|
|
78
pcg/pcg_basic.h
Normal file
78
pcg/pcg_basic.h
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* PCG Random Number Generation for C.
|
||||||
|
*
|
||||||
|
* Copyright 2014 Melissa O'Neill <oneill@pcg-random.org>
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For additional information about the PCG random number generation scheme,
|
||||||
|
* including its license and other licensing options, visit
|
||||||
|
*
|
||||||
|
* http://www.pcg-random.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is derived from the full C implementation, which is in turn
|
||||||
|
* derived from the canonical C++ PCG implementation. The C++ version
|
||||||
|
* has many additional features and is preferable if you can use C++ in
|
||||||
|
* your project.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PCG_BASIC_H_INCLUDED
|
||||||
|
#define PCG_BASIC_H_INCLUDED 1
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#if __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct pcg_state_setseq_64 { // Internals are *Private*.
|
||||||
|
uint64_t state; // RNG state. All values are possible.
|
||||||
|
uint64_t inc; // Controls which RNG sequence (stream) is
|
||||||
|
// selected. Must *always* be odd.
|
||||||
|
};
|
||||||
|
typedef struct pcg_state_setseq_64 pcg32_random_t;
|
||||||
|
|
||||||
|
// If you *must* statically initialize it, here's one.
|
||||||
|
|
||||||
|
#define PCG32_INITIALIZER { 0x853c49e6748fea9bULL, 0xda3e39cb94b95bdbULL }
|
||||||
|
|
||||||
|
// pcg32_srandom(initstate, initseq)
|
||||||
|
// pcg32_srandom_r(rng, initstate, initseq):
|
||||||
|
// Seed the rng. Specified in two parts, state initializer and a
|
||||||
|
// sequence selection constant (a.k.a. stream id)
|
||||||
|
|
||||||
|
void pcg32_srandom(uint64_t initstate, uint64_t initseq);
|
||||||
|
void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initstate,
|
||||||
|
uint64_t initseq);
|
||||||
|
|
||||||
|
// pcg32_random()
|
||||||
|
// pcg32_random_r(rng)
|
||||||
|
// Generate a uniformly distributed 32-bit random number
|
||||||
|
|
||||||
|
uint32_t pcg32_random(void);
|
||||||
|
uint32_t pcg32_random_r(pcg32_random_t* rng);
|
||||||
|
|
||||||
|
// pcg32_boundedrand(bound):
|
||||||
|
// pcg32_boundedrand_r(rng, bound):
|
||||||
|
// Generate a uniformly distributed number, r, where 0 <= r < bound
|
||||||
|
|
||||||
|
uint32_t pcg32_boundedrand(uint32_t bound);
|
||||||
|
uint32_t pcg32_boundedrand_r(pcg32_random_t* rng, uint32_t bound);
|
||||||
|
|
||||||
|
#if __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // PCG_BASIC_H_INCLUDED
|
1
qjson4/QJsonArray
Normal file
1
qjson4/QJsonArray
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#include "QJsonArray.h"
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue