Open Source Snapmatic picture and Savegame viewer/editor for GTA V https://gta5view.syping.de/

SnapmaticWidget.cpp 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. /*****************************************************************************
  2. * gta5view Grand Theft Auto V Profile Viewer
  3. * Copyright (C) 2016-2018 Syping
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *****************************************************************************/
  18. #include "SnapmaticWidget.h"
  19. #include "ui_SnapmaticWidget.h"
  20. #include "ImageEditorDialog.h"
  21. #include "MapLocationDialog.h"
  22. #include "JsonEditorDialog.h"
  23. #include "SnapmaticPicture.h"
  24. #include "SnapmaticEditor.h"
  25. #include "DatabaseThread.h"
  26. #include "PictureDialog.h"
  27. #include "PictureExport.h"
  28. #include "StringParser.h"
  29. #include "ImportDialog.h"
  30. #include "AppEnv.h"
  31. #include "config.h"
  32. #include <QStringBuilder>
  33. #include <QMessageBox>
  34. #include <QPixmap>
  35. #include <QTimer>
  36. #include <QDebug>
  37. #include <QMenu>
  38. #include <QFile>
  39. #ifdef GTA5SYNC_TELEMETRY
  40. #include "TelemetryClass.h"
  41. #include <QJsonDocument>
  42. #include <QJsonObject>
  43. #endif
  44. SnapmaticWidget::SnapmaticWidget(ProfileDatabase *profileDB, CrewDatabase *crewDB, DatabaseThread *threadDB, QString profileName, QWidget *parent) :
  45. ProfileWidget(parent), profileDB(profileDB), crewDB(crewDB), threadDB(threadDB), profileName(profileName),
  46. ui(new Ui::SnapmaticWidget)
  47. {
  48. ui->setupUi(this);
  49. ui->cmdView->setVisible(false);
  50. ui->cmdCopy->setVisible(false);
  51. ui->cmdExport->setVisible(false);
  52. ui->cmdDelete->setVisible(false);
  53. ui->cbSelected->setVisible(false);
  54. QPalette palette;
  55. palette.setCurrentColorGroup(QPalette::Disabled);
  56. highlightHiddenColor = palette.text().color();
  57. ui->SnapmaticFrame->setMouseTracking(true);
  58. ui->labPicture->setMouseTracking(true);
  59. ui->labPicStr->setMouseTracking(true);
  60. ui->cbSelected->setMouseTracking(true);
  61. smpic = nullptr;
  62. }
  63. SnapmaticWidget::~SnapmaticWidget()
  64. {
  65. delete ui;
  66. }
  67. void SnapmaticWidget::setSnapmaticPicture(SnapmaticPicture *picture)
  68. {
  69. smpic = picture;
  70. QObject::connect(picture, SIGNAL(updated()), this, SLOT(snapmaticUpdated()));
  71. QObject::connect(picture, SIGNAL(customSignal(QString)), this, SLOT(customSignal(QString)));
  72. qreal screenRatio = AppEnv::screenRatio();
  73. ui->labPicture->setFixedSize(48 * screenRatio, 27 * screenRatio);
  74. QPixmap SnapmaticPixmap = QPixmap::fromImage(picture->getImage().scaled(ui->labPicture->width(), ui->labPicture->height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::AutoColor);
  75. ui->labPicStr->setText(smpic->getPictureStr() % "\n" % smpic->getPictureTitl());
  76. ui->labPicture->setPixmap(SnapmaticPixmap);
  77. picture->clearCache();
  78. adjustTextColor();
  79. }
  80. void SnapmaticWidget::snapmaticUpdated()
  81. {
  82. ui->labPicStr->setText(smpic->getPictureStr() % "\n" % smpic->getPictureTitl());
  83. }
  84. void SnapmaticWidget::customSignal(QString signal)
  85. {
  86. if (signal == "PictureUpdated")
  87. {
  88. QPixmap SnapmaticPixmap = QPixmap::fromImage(smpic->getImage().scaled(ui->labPicture->width(), ui->labPicture->height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::AutoColor);
  89. ui->labPicture->setPixmap(SnapmaticPixmap);
  90. }
  91. }
  92. void SnapmaticWidget::retranslate()
  93. {
  94. smpic->updateStrings();
  95. ui->labPicStr->setText(smpic->getPictureStr() % "\n" % smpic->getPictureTitl());
  96. }
  97. void SnapmaticWidget::on_cmdView_clicked()
  98. {
  99. QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
  100. settings.beginGroup("Interface");
  101. bool navigationBar = settings.value("NavigationBar", false).toBool();
  102. settings.endGroup();
  103. PictureDialog *picDialog = new PictureDialog(profileDB, crewDB, profileName, this);
  104. picDialog->setSnapmaticPicture(smpic, true);
  105. picDialog->setModal(true);
  106. // be ready for crewName and playerName updated
  107. QObject::connect(threadDB, SIGNAL(crewNameUpdated()), picDialog, SLOT(crewNameUpdated()));
  108. QObject::connect(threadDB, SIGNAL(playerNameUpdated()), picDialog, SLOT(playerNameUpdated()));
  109. QObject::connect(picDialog, SIGNAL(nextPictureRequested()), this, SLOT(dialogNextPictureRequested()));
  110. QObject::connect(picDialog, SIGNAL(previousPictureRequested()), this, SLOT(dialogPreviousPictureRequested()));
  111. // add previous next buttons
  112. if (navigationBar) picDialog->addPreviousNextButtons();
  113. // show picture dialog
  114. #ifdef Q_OS_ANDROID
  115. // Android ...
  116. picDialog->showMaximized();
  117. #else
  118. picDialog->show();
  119. if (navigationBar) picDialog->stylizeDialog();
  120. //picDialog->adaptNewDialogSize();
  121. picDialog->setMinimumSize(picDialog->size());
  122. picDialog->setMaximumSize(picDialog->size());
  123. #endif
  124. picDialog->exec();
  125. delete picDialog;
  126. }
  127. void SnapmaticWidget::on_cmdCopy_clicked()
  128. {
  129. PictureExport::exportAsSnapmatic(this, smpic);
  130. }
  131. void SnapmaticWidget::on_cmdExport_clicked()
  132. {
  133. PictureExport::exportAsPicture(this, smpic);
  134. }
  135. void SnapmaticWidget::on_cmdDelete_clicked()
  136. {
  137. if (deletePicture()) emit pictureDeleted();
  138. }
  139. bool SnapmaticWidget::deletePicture()
  140. {
  141. 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);
  142. if (uchoice == QMessageBox::Yes)
  143. {
  144. if (smpic->deletePictureFile())
  145. {
  146. #ifdef GTA5SYNC_TELEMETRY
  147. QSettings telemetrySettings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
  148. telemetrySettings.beginGroup("Telemetry");
  149. bool pushUsageData = telemetrySettings.value("PushUsageData", false).toBool();
  150. telemetrySettings.endGroup();
  151. if (pushUsageData && Telemetry->canPush())
  152. {
  153. QJsonDocument jsonDocument;
  154. QJsonObject jsonObject;
  155. jsonObject["Type"] = "DeleteSuccess";
  156. jsonObject["ExtraFlags"] = "Snapmatic";
  157. jsonObject["DeletedSize"] = QString::number(smpic->getContentMaxLength());
  158. jsonObject["DeletedTime"] = QString::number(QDateTime::currentDateTimeUtc().toTime_t());
  159. jsonDocument.setObject(jsonObject);
  160. Telemetry->push(TelemetryCategory::PersonalData, jsonDocument);
  161. }
  162. #endif
  163. return true;
  164. }
  165. else
  166. {
  167. QMessageBox::warning(this, tr("Delete picture"), tr("Failed at deleting %1 from your Snapmatic pictures").arg("\""+smpic->getPictureTitle()+"\""));
  168. }
  169. }
  170. return false;
  171. }
  172. void SnapmaticWidget::mousePressEvent(QMouseEvent *ev)
  173. {
  174. ProfileWidget::mousePressEvent(ev);
  175. }
  176. void SnapmaticWidget::mouseReleaseEvent(QMouseEvent *ev)
  177. {
  178. ProfileWidget::mouseReleaseEvent(ev);
  179. if (ui->cbSelected->isVisible())
  180. {
  181. if (rect().contains(ev->pos()) && ev->button() == Qt::LeftButton)
  182. {
  183. ui->cbSelected->setChecked(!ui->cbSelected->isChecked());
  184. }
  185. }
  186. else
  187. {
  188. if (getContentMode() == 0 && rect().contains(ev->pos()) && ev->button() == Qt::LeftButton)
  189. {
  190. if (ev->modifiers().testFlag(Qt::ShiftModifier))
  191. {
  192. ui->cbSelected->setChecked(!ui->cbSelected->isChecked());
  193. }
  194. else
  195. {
  196. on_cmdView_clicked();
  197. }
  198. }
  199. else if (!ui->cbSelected->isVisible() && getContentMode() == 1 && ev->button() == Qt::LeftButton && ev->modifiers().testFlag(Qt::ShiftModifier))
  200. {
  201. ui->cbSelected->setChecked(!ui->cbSelected->isChecked());
  202. }
  203. }
  204. }
  205. void SnapmaticWidget::mouseDoubleClickEvent(QMouseEvent *ev)
  206. {
  207. ProfileWidget::mouseDoubleClickEvent(ev);
  208. if (!ui->cbSelected->isVisible() && getContentMode() == 1 && ev->button() == Qt::LeftButton)
  209. {
  210. on_cmdView_clicked();
  211. }
  212. }
  213. void SnapmaticWidget::setSelected(bool isSelected)
  214. {
  215. ui->cbSelected->setChecked(isSelected);
  216. }
  217. void SnapmaticWidget::pictureSelected()
  218. {
  219. setSelected(!ui->cbSelected->isChecked());
  220. }
  221. void SnapmaticWidget::contextMenuEvent(QContextMenuEvent *ev)
  222. {
  223. emit contextMenuTriggered(ev);
  224. }
  225. void SnapmaticWidget::dialogNextPictureRequested()
  226. {
  227. emit nextPictureRequested((QWidget*)sender());
  228. }
  229. void SnapmaticWidget::dialogPreviousPictureRequested()
  230. {
  231. emit previousPictureRequested((QWidget*)sender());
  232. }
  233. void SnapmaticWidget::on_cbSelected_stateChanged(int arg1)
  234. {
  235. if (arg1 == Qt::Checked)
  236. {
  237. emit widgetSelected();
  238. }
  239. else if (arg1 == Qt::Unchecked)
  240. {
  241. emit widgetDeselected();
  242. }
  243. }
  244. void SnapmaticWidget::adjustTextColor()
  245. {
  246. if (isHidden())
  247. {
  248. ui->labPicStr->setStyleSheet(QString("QLabel{color: rgb(%1, %2, %3);}").arg(QString::number(highlightHiddenColor.red()), QString::number(highlightHiddenColor.green()), QString::number(highlightHiddenColor.blue())));
  249. }
  250. else
  251. {
  252. ui->labPicStr->setStyleSheet("");
  253. }
  254. }
  255. bool SnapmaticWidget::makePictureHidden()
  256. {
  257. if (smpic->setPictureHidden())
  258. {
  259. adjustTextColor();
  260. return true;
  261. }
  262. return false;
  263. }
  264. bool SnapmaticWidget::makePictureVisible()
  265. {
  266. if (smpic->setPictureVisible())
  267. {
  268. adjustTextColor();
  269. return true;
  270. }
  271. return false;
  272. }
  273. void SnapmaticWidget::makePictureHiddenSlot()
  274. {
  275. if (!makePictureHidden())
  276. {
  277. 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()+"\""));
  278. }
  279. }
  280. void SnapmaticWidget::makePictureVisibleSlot()
  281. {
  282. if (!makePictureVisible())
  283. {
  284. 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()+"\""));
  285. }
  286. }
  287. void SnapmaticWidget::editSnapmaticProperties()
  288. {
  289. SnapmaticEditor *snapmaticEditor = new SnapmaticEditor(crewDB, profileDB, this);
  290. snapmaticEditor->setSnapmaticPicture(smpic);
  291. snapmaticEditor->setModal(true);
  292. snapmaticEditor->show();
  293. snapmaticEditor->exec();
  294. delete snapmaticEditor;
  295. }
  296. void SnapmaticWidget::editSnapmaticRawJson()
  297. {
  298. JsonEditorDialog *jsonEditor = new JsonEditorDialog(smpic, this);
  299. jsonEditor->setModal(true);
  300. jsonEditor->show();
  301. jsonEditor->exec();
  302. delete jsonEditor;
  303. }
  304. void SnapmaticWidget::editSnapmaticImage()
  305. {
  306. QImage *currentImage = new QImage(smpic->getImage());
  307. ImportDialog *importDialog = new ImportDialog(profileName, this);
  308. importDialog->setImage(currentImage);
  309. importDialog->enableOverwriteMode();
  310. importDialog->setModal(true);
  311. importDialog->exec();
  312. if (importDialog->isImportAgreed())
  313. {
  314. const QByteArray previousPicture = smpic->getPictureStream();
  315. bool success = smpic->setImage(importDialog->image());
  316. if (success)
  317. {
  318. QString currentFilePath = smpic->getPictureFilePath();
  319. QString originalFilePath = smpic->getOriginalPictureFilePath();
  320. QString backupFileName = originalFilePath % ".bak";
  321. if (!QFile::exists(backupFileName))
  322. {
  323. QFile::copy(currentFilePath, backupFileName);
  324. }
  325. if (!smpic->exportPicture(currentFilePath))
  326. {
  327. smpic->setPictureStream(previousPicture);
  328. QMessageBox::warning(this, QApplication::translate("ImageEditorDialog", "Snapmatic Image Editor"), QApplication::translate("ImageEditorDialog", "Patching of Snapmatic Image failed because of I/O Error"));
  329. return;
  330. }
  331. smpic->emitCustomSignal("PictureUpdated");
  332. #ifdef GTA5SYNC_TELEMETRY
  333. QSettings telemetrySettings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
  334. telemetrySettings.beginGroup("Telemetry");
  335. bool pushUsageData = telemetrySettings.value("PushUsageData", false).toBool();
  336. telemetrySettings.endGroup();
  337. if (pushUsageData && Telemetry->canPush())
  338. {
  339. QJsonDocument jsonDocument;
  340. QJsonObject jsonObject;
  341. jsonObject["Type"] = "ImageEdited";
  342. jsonObject["ExtraFlags"] = "Interface";
  343. jsonObject["EditedSize"] = QString::number(smpic->getContentMaxLength());
  344. jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toTime_t());
  345. jsonDocument.setObject(jsonObject);
  346. Telemetry->push(TelemetryCategory::PersonalData, jsonDocument);
  347. }
  348. #endif
  349. }
  350. else
  351. {
  352. QMessageBox::warning(this, QApplication::translate("ImageEditorDialog", "Snapmatic Image Editor"), QApplication::translate("ImageEditorDialog", "Patching of Snapmatic Image failed because of Image Error"));
  353. return;
  354. }
  355. }
  356. delete importDialog;
  357. }
  358. void SnapmaticWidget::openMapViewer()
  359. {
  360. SnapmaticPicture *picture = smpic;
  361. MapLocationDialog *mapLocDialog = new MapLocationDialog(picture->getSnapmaticProperties().location.x, picture->getSnapmaticProperties().location.y, this);
  362. mapLocDialog->setModal(true);
  363. mapLocDialog->show();
  364. mapLocDialog->exec();
  365. if (mapLocDialog->propUpdated())
  366. {
  367. // Update Snapmatic Properties
  368. SnapmaticProperties localSpJson = picture->getSnapmaticProperties();
  369. localSpJson.location.x = mapLocDialog->getXpos();
  370. localSpJson.location.y = mapLocDialog->getYpos();
  371. localSpJson.location.z = 0;
  372. // Update Snapmatic Picture
  373. QString currentFilePath = picture->getPictureFilePath();
  374. QString originalFilePath = picture->getOriginalPictureFilePath();
  375. QString backupFileName = originalFilePath % ".bak";
  376. if (!QFile::exists(backupFileName))
  377. {
  378. QFile::copy(currentFilePath, backupFileName);
  379. }
  380. SnapmaticProperties fallbackProperties = picture->getSnapmaticProperties();
  381. picture->setSnapmaticProperties(localSpJson);
  382. if (!picture->exportPicture(currentFilePath))
  383. {
  384. QMessageBox::warning(this, SnapmaticEditor::tr("Snapmatic Properties"), SnapmaticEditor::tr("Patching of Snapmatic Properties failed because of I/O Error"));
  385. picture->setSnapmaticProperties(fallbackProperties);
  386. }
  387. #ifdef GTA5SYNC_TELEMETRY
  388. else
  389. {
  390. QSettings telemetrySettings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
  391. telemetrySettings.beginGroup("Telemetry");
  392. bool pushUsageData = telemetrySettings.value("PushUsageData", false).toBool();
  393. telemetrySettings.endGroup();
  394. if (pushUsageData && Telemetry->canPush())
  395. {
  396. QJsonDocument jsonDocument;
  397. QJsonObject jsonObject;
  398. jsonObject["Type"] = "LocationEdited";
  399. jsonObject["ExtraFlags"] = "Interface";
  400. jsonObject["EditedSize"] = QString::number(picture->getContentMaxLength());
  401. jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toTime_t());
  402. jsonDocument.setObject(jsonObject);
  403. Telemetry->push(TelemetryCategory::PersonalData, jsonDocument);
  404. }
  405. }
  406. #endif
  407. }
  408. delete mapLocDialog;
  409. }
  410. bool SnapmaticWidget::isSelected()
  411. {
  412. return ui->cbSelected->isChecked();
  413. }
  414. bool SnapmaticWidget::isHidden()
  415. {
  416. return smpic->isHidden();
  417. }
  418. void SnapmaticWidget::setSelectionMode(bool selectionMode)
  419. {
  420. ui->cbSelected->setVisible(selectionMode);
  421. }
  422. void SnapmaticWidget::selectAllWidgets()
  423. {
  424. emit allWidgetsSelected();
  425. }
  426. void SnapmaticWidget::deselectAllWidgets()
  427. {
  428. emit allWidgetsDeselected();
  429. }
  430. SnapmaticPicture* SnapmaticWidget::getPicture()
  431. {
  432. return smpic;
  433. }
  434. QString SnapmaticWidget::getPicturePath()
  435. {
  436. return smpic->getPictureFilePath();
  437. }
  438. QString SnapmaticWidget::getWidgetType()
  439. {
  440. return "SnapmaticWidget";
  441. }