swg-launchpad/mainwindow.cpp
2015-10-20 23:17:12 +02:00

1412 lines
45 KiB
C++

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "settings.h"
#include <QNetworkReply>
#include <QtXml>
#include "statusxmlcontenthandler.h"
#include <QProcess>
#include <QMessageBox>
#include <iostream>
#include <QDesktopWidget>
#include "loginservers.h"
#include "configparser.h"
#include "gameprocess.h"
#ifdef Q_OS_WIN32
#include "windebugmonitor.h"
#endif
#include "selfupdater.h"
#include <QCloseEvent>
#include "installfromswg.h"
#include "utils.h"
#include "filescanner.h"
#include "macroeditor.h"
#include <QWebElement>
#include <QWebFrame>
#if QT_VERSION >= 0x050000
#include <QtConcurrent/QtConcurrentRun>
#endif
#include "gamemods.h"
//#define ENABLE_MACRO_EDITOR
QString MainWindow::patchUrl = "http://www.launchpad2.net/SWGEmu/"; // Insert download URL here
//QString MainWindow::newsUrl = "http://www.swgemu.com/forums/index.php#bd";
QString MainWindow::newsUrl = "http://www.swgemu.com/forums/forum.php";
QString MainWindow::gameExecutable = "SWGEmu.exe";
#ifdef Q_OS_WIN32
QString MainWindow::selfUpdateUrl = "http://launchpad2.net/setup.cfg"; // Insert update URL here
#else
QString MainWindow::selfUpdateUrl = "http://launchpad2.net/setuplinux86_64.cfg"; // Insert linux update URL here
#endif
const QString MainWindow::version = "0.23";
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow), networkAccessManager(this), clientFilesNetworkAccessManager(this),
novaNetworkAccessManager(this), requiredFilesNetworkManager(this), patchesNetworkManager(this),
fullScanWorkingThreads(0) {
ui->setupUi(this);
QCoreApplication::setOrganizationName("SWGEmu");
QCoreApplication::setOrganizationDomain("swgemu.com");
QCoreApplication::setApplicationName("Launchpad");
requiredFilesCount = 0;
nextFileToDownload = 0;
updateTimeCounter = 5;
gameProcessesCount = 0;
runningFullScan = false;
fileScanner = new FileScanner(this);
settings = new Settings(this);
loginServers = new LoginServers(this);
systemTrayIcon = new QSystemTrayIcon(this);
systemTrayIcon->setIcon(QIcon(":/img/swgemu.svg"));
systemTrayMenu = new QMenu();
closeAction = new QAction("Close", NULL);
systemTrayMenu->addAction(closeAction);
systemTrayIcon->setContextMenu(systemTrayMenu);
QToolButton* newsButton = new QToolButton(ui->mainToolBar);
newsButton->setIcon(QIcon(":/img/globe.svg"));
newsButton->setText("News");
newsButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
newsButton->setCheckable(true);
ui->mainToolBar->addWidget(newsButton);
connect(newsButton, SIGNAL(clicked()), this, SLOT(triggerNews()));
toolButtons.append(newsButton);
QToolButton* updateStatusButton = new QToolButton(ui->mainToolBar);
updateStatusButton->setIcon(QIcon(":/img/update_status.svg"));
updateStatusButton->setText("Update status");
updateStatusButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
ui->mainToolBar->addWidget(updateStatusButton);
connect(updateStatusButton, SIGNAL(clicked()), this, SLOT(updateServerStatus()));
toolButtons.append(updateStatusButton);
QToolButton* gameSettingsButton = new QToolButton(ui->mainToolBar);
gameSettingsButton->setIcon(QIcon(":/img/game_settings.svg"));
gameSettingsButton->setText("Game settings");
gameSettingsButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
ui->mainToolBar->addWidget(gameSettingsButton);
connect(gameSettingsButton, SIGNAL(clicked()), this, SLOT(startSWGSetup()));
toolButtons.append(gameSettingsButton);
QToolButton* gameModsButton = new QToolButton(ui->mainToolBar);
gameModsButton->setIcon(QIcon(":/img/magic.svg"));
gameModsButton->setText("Game mods");
gameModsButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
ui->mainToolBar->addWidget(gameModsButton);
connect(gameModsButton, SIGNAL(clicked()), this, SLOT(showGameModsOptions()));
toolButtons.append(gameModsButton);
#ifdef ENABLE_MACRO_EDITOR
QToolButton* macroEditorButton = new QToolButton(ui->mainToolBar);
macroEditorButton->setIcon(QIcon(":/img/book.svg"));
macroEditorButton->setText("Macro Editor");
macroEditorButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
ui->mainToolBar->addWidget(macroEditorButton);
connect(macroEditorButton, SIGNAL(clicked()), this, SLOT(showMacroEditor()));
toolButtons.append(macroEditorButton);
#endif
QToolButton* profCalculatorButton = new QToolButton(ui->mainToolBar);
profCalculatorButton->setIcon(QIcon(":/img/design.svg"));
profCalculatorButton->setText("Profession Calculator");
profCalculatorButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
ui->mainToolBar->addWidget(profCalculatorButton);
connect(profCalculatorButton, SIGNAL(clicked()), this, SLOT(startKodanCalculator()));
toolButtons.append(profCalculatorButton);
QToolButton* deleteProfilesButton = new QToolButton(ui->mainToolBar);
deleteProfilesButton->setIcon(QIcon(":/img/bin.svg"));
deleteProfilesButton->setText("Delete game profiles");
deleteProfilesButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
ui->mainToolBar->addWidget(deleteProfilesButton);
connect(deleteProfilesButton, SIGNAL(clicked()), this, SLOT(deleteProfiles()));
toolButtons.append(deleteProfilesButton);
QToolButton* updateButton = new QToolButton(ui->mainToolBar);
updateButton->setIcon(QIcon(":/img/cloud_down.svg"));
updateButton->setText("Check for updates");
updateButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
ui->mainToolBar->addWidget(updateButton);
connect(updateButton, SIGNAL(clicked()), this, SLOT(checkForUpdates()));
toolButtons.append(updateButton);
cancelWorkingThreads = false;
connect(ui->mainToolBar, SIGNAL(orientationChanged(Qt::Orientation)), this, SLOT(toolBarOrientationChanged(Qt::Orientation)));
connect(systemTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(systemTrayActivated(QSystemTrayIcon::ActivationReason)));
connect(closeAction, SIGNAL(triggered()), qApp, SLOT(quit()));
connect(ui->actionFolders, SIGNAL(triggered()), this, SLOT(showSettings()));
connect(&networkAccessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(statusXmlIsReady(QNetworkReply*)) );
connect(&novaNetworkAccessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(statusXmlIsReady(QNetworkReply*)) );
connect(&clientFilesNetworkAccessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(downloadFileFinished(QNetworkReply*)));
connect(&requiredFilesNetworkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requiredFileDownloadFileFinished(QNetworkReply*)));
connect(&patchesNetworkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(patchesDownloadFileFinished(QNetworkReply*)));
connect(ui->webView, SIGNAL(loadFinished(bool)), this, SLOT(webPageLoadFinished(bool)));
connect(ui->pushButton_Start, SIGNAL(clicked()), this, SLOT(startSWG()));
connect(fileScanner, SIGNAL(requiredFileExists(QString)), this, SLOT(updateBasicLoadProgress(QString)));
connect(fileScanner, SIGNAL(fullScannedFile(QString, bool)), this, SLOT(updateFullScanProgress(QString, bool)));
connect(this, SIGNAL(startDownload()), this, SLOT(startFileDownload()));
connect(ui->actionLogin_Servers, SIGNAL(triggered()), loginServers, SLOT(show()));
connect(ui->actionShow_news, SIGNAL(triggered()), this, SLOT(triggerNews()));
connect(ui->checkBox_instances, SIGNAL(toggled(bool)), this, SLOT(triggerMultipleInstances(bool)));
connect(ui->actionUpdate_Status, SIGNAL(triggered()), this, SLOT(updateServerStatus()));
connect(ui->tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));
connect(ui->actionCheck_for_updates, SIGNAL(triggered()), this, SLOT(checkForUpdates()));
connect(ui->actionGame_Settings, SIGNAL(triggered()), this, SLOT(startSWGSetup()));
connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(showAboutDialog()));
connect(ui->actionDelete_Profiles, SIGNAL(triggered()), this, SLOT(deleteProfiles()));
connect(fileScanner, SIGNAL(addFileToDownload(QString)), this, SLOT(addFileToDownloadSlot(QString)));
connect(ui->actionInstall_from_SWG, SIGNAL(triggered()), this, SLOT(installSWGEmu()));
ui->groupBox_browser->hide();
QTabBar* tabBar = ui->tabWidget->tabBar();
tabBar->setTabButton(0, QTabBar::RightSide, 0);
tabBar->setTabButton(0, QTabBar::LeftSide, 0);
QSettings settingsOptions;
QString swgFolder = settingsOptions.value("swg_folder").toString();
bool multipleInstances = settingsOptions.value("multiple_instances").toBool();
ui->checkBox_instances->setChecked(multipleInstances);
ui->textBrowser->viewport()->setAutoFillBackground(false);
ui->textBrowser->setAutoFillBackground(false);
updateServerStatus();
connect(&loadWatcher, SIGNAL(finished()), this, SLOT(loadFinished()));
//connect(&fullScanWatcher, SIGNAL(finished()), this, SLOT(fullScanFinished()));
connect(ui->pushButton_FullScan, SIGNAL(clicked()), this, SLOT(startFullScan()));
loginServers->reloadServers();
updateLoginServerList();
silentSelfUpdater = new SelfUpdater(true, this);
if (!swgFolder.isEmpty())
startLoadBasicCheck();
else {
#ifdef Q_OS_WIN32
QDir dir("C:/SWGEmu");
if (dir.exists() && FileScanner::checkSwgFolder("C:/SWGEmu")) {
settingsOptions.setValue("swg_folder", "C:/SWGEmu");
startLoadBasicCheck();
} else
#endif
QMessageBox::warning(this, "Error", "Please set the swgemu folder in Settings->Options or install using Settings->Install From SWG option");
}
restoreGeometry(settingsOptions.value("mainWindowGeometry").toByteArray());
restoreState(settingsOptions.value("mainWindowState").toByteArray());
QString savedLogin = settingsOptions.value("selected_login_server", "").toString();
if (!savedLogin.isEmpty()) {
int idx = ui->comboBox_login->findText(savedLogin);
if (idx >= 0) {
ui->comboBox_login->setCurrentIndex(idx);
}
}
requiredFilesNetworkManager.get(QNetworkRequest(QUrl(patchUrl + "required2.txt")));
//patchesNetworkManager.get(QNetworkRequest(QUrl(patchUrl + "patches.txt")));
silentSelfUpdater->silentCheck();
//ui->webView->setUrl(newsUrl);
//gameMods = new GameMods(this);
}
MainWindow::~MainWindow() {
delete ui;
ui = NULL;
//delete fileScanner;
fileScanner = NULL;
//delete settings;
settings = NULL;
//delete loginServers;
loginServers = NULL;
while (gameProcesses.size() > 0) {
GameProcess* process = gameProcesses[0];
gameProcesses.remove(0);
delete process;
}
#ifdef Q_OS_WIN32
if (GameProcess::debugMonitor) {
delete GameProcess::debugMonitor;
GameProcess::debugMonitor = NULL;
}
#endif
//delete silentSelfUpdater;
silentSelfUpdater = NULL;
//gameMods = NULL;
}
void MainWindow::toolBarOrientationChanged(Qt::Orientation ) {
/*
Qt::ToolButtonStyle style = Qt::ToolButtonTextBesideIcon;
switch (orientation) {
case Qt::Horizontal:
style = Qt::ToolButtonTextBesideIcon;
break;
case Qt::Vertical:
style = Qt::ToolButtonTextUnderIcon;
break;
}
for (int i = 0; i < toolButtons.size(); ++i) {
QToolButton* button = toolButtons.at(i);
button->setToolButtonStyle(style);
button->set
// button->set
}
*/
}
void MainWindow::systemTrayActivated(QSystemTrayIcon::ActivationReason reason) {
if (reason == QSystemTrayIcon::Trigger) {
this->showNormal();
this->raise();
}
}
void MainWindow::deleteProfiles() {
if (QMessageBox::question(this, "Warning", "Are you sure you want to delete the game profiles folder?") != QMessageBox::Yes )
return;
QSettings settings;
QString folder = settings.value("swg_folder").toString();
#ifdef Q_OS_WIN32
QDir dir(folder + "\\profiles");
#else
QDir dir(folder + "/profiles");
#endif
if (!dir.exists()) {
QMessageBox::warning(this, "Warning", "No profiles folder found");
return;
}
if (dir.removeRecursively()) {
QMessageBox::information(this, "Success", "Profiles directory deleted!");
} else {
QMessageBox::warning(this, "Warning", "There was an error deleting the profiles directory!");
}
}
void MainWindow::readBasiliskServerStatus() {
networkAccessManager.get(QNetworkRequest(QUrl("http://www.swgemu.com/status/basilisk.xml")));
}
void MainWindow::readNovaServerStatus() {
novaNetworkAccessManager.get(QNetworkRequest(QUrl("http://www.swgemu.com/status/nova.xml")));
}
void MainWindow::checkForUpdates() {
SelfUpdater updater(false, this);
updater.execUpdate();
}
void MainWindow::updateLoginServerList() {
ui->comboBox_login->clear();
QSettings settings;
settings.beginWriteArray("login_servers");
for (int i = 0; i < loginServers->count(); ++i) {
LoginServer* server = loginServers->getServer(i);
settings.setArrayIndex(i);
ui->comboBox_login->addItem(server->text());
settings.setValue("name", server->text());
settings.setValue("host", server->getHost());
settings.setValue("port", server->getPort());
}
settings.endArray();
}
void MainWindow::updateServerStatus() {
//ui->statusBar->showMessage("Updating server status..");
ui->textBrowser->clear();
readBasiliskServerStatus();
readNovaServerStatus();
}
void MainWindow::triggerMultipleInstances(bool newValue) {
QSettings settings;
settings.setValue("multiple_instances", newValue);
}
void MainWindow::triggerNews() {
if (ui->groupBox_browser->isHidden()) {
ui->statusBar->showMessage("Loading page...");
ui->webView->setUrl(newsUrl);
if (!isMaximized()) {
QDesktopWidget* mydesk = QApplication::desktop();
int screen = mydesk->screenNumber(this);
QRect screenSize = mydesk->screenGeometry(screen);
QRect windowGeometry = this->geometry();
int difference = 811 - 356;
if (windowGeometry.height() + difference + pos().y() > screenSize.bottom()) {
this->move(pos().x(), pos().y() - (windowGeometry.height() + difference + pos().y() - screenSize.bottom()));
}
this->resize(907, 811);
}
ui->actionShow_news->setText("Hide news");
//ui->actionShow_news->setChecked(true);
ui->groupBox_browser->show();
} else {
ui->groupBox_browser->hide();
if (!isMaximized())
this->resize(907, 256);
//ui->actionShow_news->setChecked(false);
ui->actionShow_news->setText("Show news");
}
}
QFile* MainWindow::getRequiredFilesFile() {
QSettings settings;
//QString folder = settings.value("swg_folder").toString();
QFile* file = NULL;
//if (QDir(folder).exists()) {
file = new QFile("required2.txt");
if (file->exists()) {
if (file->open(QIODevice::ReadOnly | QIODevice::Text)) {
return file;
} else
delete file;
} else {
delete file;
}
//}
file = new QFile(":/files/required2.txt");
file->open(QIODevice::ReadOnly | QIODevice::Text);
return file;
}
void MainWindow::addFileToDownloadSlot(QString file) {
filesToDownload.append(file);
}
void MainWindow::showAboutDialog() {
QMessageBox::about(this, "SWGemu", "SWGEmu Launchpad version " + version + "\n\nThis 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.");
}
void MainWindow::requiredFileDownloadFileFinished(QNetworkReply* reply) {
if (reply && reply->error() != QNetworkReply::NoError) {
// QMessageBox::warning(this, "ERROR getting new patch information", reply->errorString());
return;
}
qDebug() << "got required2.txt";
QString data = reply->readAll();
// qDebug() << data;
QSettings settings;
// QString folder = settings.value("swg_folder").toString();
// if (QDir(folder).exists()) {
QFile file("required2.txt");
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream stream(&file);
stream << data;
file.close();
return;
}
//}
startLoadBasicCheck();
/*
ui->pushButton_FullScan->setEnabled(false);
ui->pushButton_Start->setEnabled(false);
ui->label_current_work->setText("Checking for new client updates...");
QStringList currentFiles = getRequiredFiles();
*/
}
void MainWindow::patchesDownloadFileFinished(QNetworkReply* reply) {
if (reply && reply->error() != QNetworkReply::NoError) {
// QMessageBox::warning(this, "ERROR getting new patch information", reply->errorString());
updateTimeCounter = -1;
enableStart();
return;
}
try {
QString data = reply->readAll();
qDebug() << "got patches.txt" << data;
QTextStream file(&data);
QSettings settings;
QString swgFolder = settings.value("swg_folder").toString();
while (!file.atEnd()) {
QString fileString = file.readLine();
QByteArray line(fileString.toStdString().c_str());
//process_line(line);
//QRegExp rx("(\\ |\\,|\\.|\\;|\\t)"); //RegEx for ' ' or ',' or '.' or ':' or '\t'
QList<QByteArray> query = line.split(';');
//QListIterator<QByteArray>
QString name = query.at(0);
QString size = query.at(1);
QString md5 = query.at(2).trimmed();
QString action = query.at(3);
QString file = swgFolder + "/" + name;
QFile fileObject(file);
if ((action == "A") && !fileObject.exists()) {
qDebug() << file << "doesnt exist";
//return -1;
//filesToDownload.append(MainWindow::patchUrl + name);
appendToFilesToDownloadStringList(MainWindow::patchUrl + name);
continue;
} else if ((action == "D") && fileObject.exists()) {
fileObject.remove();
}
}
}
catch (...) {
enableStart();
}
if (filesToDownload.size() > 0) {
startFileDownload();
updateTimeCounter = -2;
} else {
updateTimeCounter = -1;
enableStart();
}
}
void MainWindow::updateBasicLoadProgress(QString successFile) {
//ui->progressBar_loading->set
ui->progressBar_loading->setValue(++currentReadFiles);
}
void MainWindow::updateFullScanProgress(QString successFile, bool success) {
/*if (success)
ui->label_current_work->setText(successFile + " valid.");
else
ui->label_current_work->setText(successFile + " invalid!");*/
if (!success) {
//ui->label_current_work->setPalette(QPalette::);
ui->label_current_work->setStyleSheet("color:red");
ui->label_current_work->setText(successFile + " invalid!");
}
ui->progressBar_FullScan->setValue(++currentReadFiles);
if (currentReadFiles == requiredFilesCount) {
qDebug() << "full scan finished";
runningFullScan = false;
if (filesToDownload.size() == 0)
ui->label_current_work->setText("Full scan successfull");
if (!cancelWorkingThreads)
emit startDownload();
}
}
void MainWindow::startFullScan(bool forceConfigRestore) {
if (!forceConfigRestore) {
if (QMessageBox::question(this, "Warning", "This will restore your files to their original state removing any mods you might have. Do you want to continue?") != QMessageBox::Yes)
return;
}
requiredFilesCount = getRequiredFiles().size();
currentReadFiles = 0;
QSettings settings;
QString folder = settings.value("swg_folder").toString();
QDir checkDir(folder);
if (!checkDir.exists() || folder.isEmpty() || !FileScanner::checkSwgFolder(folder)) {
QMessageBox::warning(this, "ERROR", "Invalid game folder!");
return;
}
bool restoreConfigFiles = forceConfigRestore ? true : QMessageBox::question(this, "Config files", "Do you want to restore the config files too?") == QMessageBox::Yes;
if (requiredFilesCount == 0 && !restoreConfigFiles)
return;
ui->pushButton_Start->setEnabled(false);
ui->pushButton_FullScan->setEnabled(false);
ui->progressBar_FullScan->setMaximum(requiredFilesCount);
ui->progressBar_FullScan->setValue(0);
ui->label_current_work->setStyleSheet("color:black");
ui->label_current_work->setText("Doing full scan..");
ui->actionFolders->setEnabled(false);
filesToDownload.clear();
if (restoreConfigFiles || !QFile(folder + "/swgemu.cfg").exists()) {
filesToDownload.append(patchUrl + "swgemu.cfg");
filesToDownload.append(patchUrl + "swgemu_live.cfg");
filesToDownload.append(patchUrl + "swgemu_login.cfg");
filesToDownload.append(patchUrl + "swgemu_preload.cfg");
//filesToDownload.append(patchUrl + "Emu_opt.cfg");
filesToDownload.append(patchUrl + "swgemu_machineoptions.iff");
filesToDownload.append(patchUrl + "options.cfg");
//filesToDownload.append(patchUrl + "user.cfg");
}
bool multiThreaded = settings.value("multi_threaded_full_scan", false).toBool();
if (multiThreaded) {
fullScanWorkingThreads = getRequiredFiles().size();
runningFullScan = true;
QtConcurrent::run(fileScanner, &FileScanner::fullScanMultiThreaded, restoreConfigFiles);
} else {
runningFullScan = true;
QFuture<int> future = QtConcurrent::run(fileScanner, &FileScanner::fullScanSingleThreaded, restoreConfigFiles);
fullScanWatcher.setFuture(future);
}
}
void MainWindow::startLoadBasicCheck() {
if (runningFullScan)
return;
ui->pushButton_Start->setEnabled(false);
// ui->pushButton_Start->setText("Start (" + QString::number(updateTimeCounter) + ")");
ui->label_current_work->setStyleSheet("color:black");
ui->label_current_work->setText("Checking files and updates..");
requiredFilesCount = getRequiredFiles().size();
currentReadFiles = 0;
ui->progressBar_loading->setMaximum(requiredFilesCount);
ui->progressBar_loading->setValue(0);
QSettings settingsOptions;
QString swgFolder = settingsOptions.value("swg_folder").toString();
QFuture<int> future = QtConcurrent::run(fileScanner, &FileScanner::loadAndBasicCheckFiles, swgFolder);
loadWatcher.setFuture(future);
//QTimer::singleShot(1000, this, SLOT(runUpdateCheckTimer()));
}
void MainWindow::runUpdateCheckTimer() {
if (--updateTimeCounter >= 0) {
QTimer::singleShot(1000, this, SLOT(runUpdateCheckTimer()));
ui->pushButton_Start->setText("Start (" + QString::number(updateTimeCounter) + ")");
} else {
ui->pushButton_Start->setText("Start");
//ui->pushButton_Start->setEnabled(true);
// qDebug() << "hui is: " << updateTimeCounter;
if (updateTimeCounter == -1) {
enableStart();
}
}
}
void MainWindow::startFileDownload() {
requiredFilesCount = filesToDownload.count();
currentReadFiles = 0;
if (filesToDownload.length() == 0) {
ui->actionFolders->setEnabled(true);
ui->pushButton_Start->setEnabled(true);
ui->pushButton_FullScan->setEnabled(true);
return;
}
ui->progressBar_loading->setMaximum(requiredFilesCount);
ui->progressBar_loading->setValue(0);
//filesToDownload = files;
nextFileToDownload = 0;
QString downloadingFile = filesToDownload.at(nextFileToDownload);
downloadingFile = downloadingFile.mid(downloadingFile.lastIndexOf("/"));
ui->label_current_work->setStyleSheet("color:black");
ui->label_current_work->setText("Downloading: " + downloadingFile);
qDebug() << "downloading " << filesToDownload.at(nextFileToDownload);
QNetworkReply* reply = clientFilesNetworkAccessManager.get(QNetworkRequest(filesToDownload.at(nextFileToDownload)));
connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(downloadProgress(qint64,qint64)));
lastReceivedBytesTime.restart();
lastReceivedBytes = 0;
}
void MainWindow::downloadFileFinished(QNetworkReply* reply) {
if (reply->error() != QNetworkReply::NoError) {
QMessageBox::critical(this, "ERROR", reply->errorString());
filesToDownload.clear();
nextFileToDownload = 0;
return;
}
int bufferSize = 8192 * 2;
char* buffer = (char*) malloc(bufferSize);
QSettings settings;
QString swgFolder = settings.value("swg_folder").toString();
QString downloadedFile = filesToDownload.at(nextFileToDownload);
downloadedFile = downloadedFile.remove(0, patchUrl.length());
QString dir;
if (downloadedFile.contains("/")) {
dir = downloadedFile.mid(0, downloadedFile.lastIndexOf("/"));
}
downloadedFile = downloadedFile.mid(downloadedFile.lastIndexOf("/") + 1);
QString fullPath;
if (dir.isEmpty())
fullPath = swgFolder + "/" + downloadedFile;
else
fullPath = swgFolder + "/" + dir + "/" + downloadedFile;
if (!QDir(swgFolder + "/" + dir).exists())
QDir(swgFolder + "/" + dir).mkpath(".");
QFile fileObject(fullPath);
//fileObject.set
if (!fileObject.open(QIODevice::WriteOnly)) {
QMessageBox::critical(this, "ERROR", "Could not open to write downloaded file to disk! " + swgFolder + "/" + downloadedFile);
filesToDownload.clear();
nextFileToDownload = 0;
free(buffer);
return;
}
int read = 0;
while ((read = reply->read(buffer, bufferSize)) > 0) {
if (fileObject.write(buffer, read) == -1) {
QMessageBox::critical(this, "ERROR", "Could not write downloaded file to disk!");
filesToDownload.clear();
nextFileToDownload = 0;
free(buffer);
return;
}
}
fileObject.close();
free(buffer);
qDebug() << "downloading file:" << downloadedFile << " finished!";
if (++nextFileToDownload < filesToDownload.size()) {
QString downloadingFile = filesToDownload.at(nextFileToDownload);
downloadingFile = downloadingFile.mid(downloadingFile.lastIndexOf("/") + 1);
ui->label_current_work->setStyleSheet("color:black");
ui->label_current_work->setText("Downloading: " + downloadingFile);
QNetworkReply* reply = clientFilesNetworkAccessManager.get(QNetworkRequest(filesToDownload.at(nextFileToDownload)));
connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(downloadProgress(qint64,qint64)));
lastReceivedBytesTime.restart();
lastReceivedBytes = 0;
ui->progressBar_loading->setValue(nextFileToDownload);
} else {
ui->progressBar_loading->setValue(nextFileToDownload);
downloadFinished();
}
}
void MainWindow::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) {
if (lastReceivedBytes == 0) {
ui->progressBar_FullScan->setMaximum(bytesTotal);
}
ui->progressBar_FullScan->setValue(bytesReceived);
QTime nowTime;
nowTime.restart();
int delta = lastReceivedBytesTime.msecsTo(nowTime);
if (delta < 500 && bytesReceived < bytesTotal)
return;
QString downloadingFile = filesToDownload.at(nextFileToDownload);
downloadingFile = downloadingFile.mid(downloadingFile.lastIndexOf("/") + 1);
int speed = 0;
if (delta != 0)
speed = ((bytesReceived - lastReceivedBytes) / delta);
QString label = "Downloading: " + downloadingFile + " " + QString::number(bytesReceived / 1000) + " kB / " + QString::number(bytesTotal / 1000) + " kB " + QString::number(speed) + " kB/s";
ui->label_current_work->setStyleSheet("color:black");
ui->label_current_work->setText(label);
lastReceivedBytesTime.restart();
lastReceivedBytes = bytesReceived;
}
void MainWindow::startKodanCalculator() {
#ifdef Q_OS_WIN32
if (!QProcess::startDetached("KSWGProfCalcEditor.exe", QStringList(), QDir::currentPath())) {
QMessageBox::warning(this, "ERROR", "Could not launch profession calculator!");
}
#else
QSettings settings;
QString wineBinary = settings.value("wine_binary").toString();
if (wineBinary.isEmpty())
wineBinary = "wine";
QString args = settings.value("wine_args").toString();
QStringList argsList;
if (!args.isEmpty())
argsList = Utils::getArgumentList(args);
argsList.append("KSWGProfCalcEditor.exe");
qDebug() << argsList;
if (!QProcess::startDetached(wineBinary, argsList, QDir::currentPath())) {
QMessageBox::warning(this, "ERROR", "Could not launch game settings!");
}
#endif
}
void MainWindow::startSWGSetup() {
//QMessageBox::
//QProcess* process = new QProcess();
QSettings settings;
QString folder = settings.value("swg_folder").toString();
#ifdef Q_OS_WIN32
//qDebug() << folder;
/*process->setWorkingDirectory(folder);
process->start(folder + "\\" + "SWGEmu_Setup.exe");*/
if (!QProcess::startDetached(folder + "\\" + "SWGEmu_Setup.exe", QStringList(), folder)) {
QMessageBox::warning(this, "ERROR", "Could not launch game settings!");
}
#else
QString wineBinary = settings.value("wine_binary").toString();
if (wineBinary.isEmpty())
wineBinary = "wine";
QString args = settings.value("wine_args").toString();
QStringList argsList;
if (!args.isEmpty())
argsList = Utils::getArgumentList(args);
argsList.append(folder + "/" + "SWGEmu_Setup.exe");
qDebug() << argsList;
if (!QProcess::startDetached(wineBinary, argsList, folder)) {
QMessageBox::warning(this, "ERROR", "Could not launch game settings!");
}
#endif
}
void MainWindow::downloadFinished() {
nextFileToDownload = 0;
if (filesToDownload.contains(patchUrl + "swgemu.cfg")) {
QMessageBox::information(this, "Game Settings", "SWGEmu game settings application will now launch, please set your resolution in the Graphics tab!");
startSWGSetup();
}
filesToDownload.clear();
ui->label_current_work->setStyleSheet("color:green");
ui->label_current_work->setText("Download finished");
ui->pushButton_Start->setEnabled(true);
ui->actionFolders->setEnabled(true);
ui->pushButton_FullScan->setEnabled(true);
qDebug() << "download finished";
//startLoadBasicCheck();
}
void MainWindow::showSettings() {
settings->exec();
}
/*
void MainWindow::fullScanFinished() {
if (cancelWorkingThreads)
return;
int res = fullScanWatcher.result();
qDebug() << "full scan finished with result " << res;
if (res == 0)
ui->label_current_work->setText("Full scan successfull");
}
*/
void MainWindow::enableStart() {
ui->pushButton_Start->setEnabled(true);
ui->pushButton_Start->setText("Start");
ui->actionFolders->setEnabled(true);
ui->label_current_work->setStyleSheet("color:green");
ui->label_current_work->setText("Basic checks passed.");
}
void MainWindow::loadFinished() {
if (cancelWorkingThreads)
return;
int res = loadWatcher.result();
if (res == 0) {
if (updateTimeCounter < 0) {
enableStart();
} else {
updateTimeCounter = 5;
ui->pushButton_Start->setText("Start (" + QString::number(updateTimeCounter) + ")");
QTimer::singleShot(1000, this, SLOT(runUpdateCheckTimer()));
patchesNetworkManager.get(QNetworkRequest(QUrl(patchUrl + "patches.txt")));
}
} else {
ui->pushButton_Start->setEnabled(false);
ui->actionFolders->setEnabled(true);
ui->label_current_work->setStyleSheet("color:red");
ui->label_current_work->setText("Basic checks failed. Please run full scan to try and fix the issues.");
ui->progressBar_loading->setValue(ui->progressBar_loading->maximum());
}
}
QVector<QPair<QString, qint64> > MainWindow::getRequiredFiles() {
QSettings settings;
//QString folder = settings.value("swg_folder").toString();
QVector<QPair<QString, qint64> > data;
//QStringList files;
//if (QDir(folder).exists()) {
{
QFile file("required2.txt");
if (file.exists()) {
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
while (!file.atEnd()) {
QByteArray line = file.readLine();
QList<QByteArray> query = line.split(';');
//QListIterator<QByteArray>
QString name = query.at(0);
QString size = query.at(1);
QString md5 = query.at(2);
//files.append(name);
data.append(QPair<QString, qint64>(name, size.toLongLong()));
}
return data;
}
}
}
QFile file(":/files/required2.txt");
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return data;
while (!file.atEnd()) {
QByteArray line = file.readLine();
//process_line(line);
//QRegExp rx("(\\ |\\,|\\.|\\;|\\t)"); //RegEx for ' ' or ',' or '.' or ':' or '\t'
QList<QByteArray> query = line.split(';');
//QListIterator<QByteArray>
QString name = query.at(0);
QString size = query.at(1);
QString md5 = query.at(2);
//files.append(name);
//line.
data.append(QPair<QString, qint64>(name, size.toLongLong()));
}
return data;
}
void MainWindow::startSWG() {
QStringList arguments;
QSettings settings;
QString folder = settings.value("swg_folder").toString();
bool multiple = settings.value("multiple_instances").toBool();
ConfigParser* parser = new ConfigParser();
GameProcess* process = new GameProcess(parser, NULL);
parser->connect(parser, SIGNAL(errorSignal(QString)), process, SLOT(outputDebugString(QString)));
try {
if (parser->loadFile(folder, "swgemu.cfg") != 0) {
QMessageBox::warning(this, "Warning", "There was an issue parsing the swg config files! To restore them run full scan!");
}
} catch (...) {
QMessageBox::warning(this, "Warning", "There was an issue parsing the swg config files! To restore them run full scan!");
}
QVector<ConfigValue> loginServerAddresses = parser->getConfigValues("ClientGame", "loginServerAddress0");
QVector<ConfigValue> loginServerPorts = parser->getConfigValues("ClientGame", "loginServerPort0");
if (loginServerAddresses.size() > 1) {
QString warningString;
QTextStream stream(&warningString);
stream << "You have several login server addresses defined in the following swg config files: ";
for (int i = 0; i < loginServerAddresses.size(); ++i) {
const ConfigValue val = loginServerAddresses.at(i);
stream << val.fileName << " ";
}
stream << " client will use the value: " << parser->getStringConfigValue("ClientGame", "loginServerAddress0");
QMessageBox::warning(this, "Warning", warningString);
}
if (loginServerPorts.size() > 1) {
QString warningString;
QTextStream stream(&warningString);
stream << "You have several login server ports defined in the following swg config files: ";
for (int i = 0; i < loginServerPorts.size(); ++i) {
const ConfigValue val = loginServerPorts.at(i);
stream << val.fileName << " ";
}
stream << " client will use the value: " << parser->getStringConfigValue("ClientGame", "loginServerPort0");
QMessageBox::warning(this, "Warning", warningString);
}
LoginServer* server = loginServers->getServer(ui->comboBox_login->currentText());
QString loginAddress = parser->getStringConfigValue("ClientGame", "loginServerAddress0", "loginServerAddress0");
QString port = parser->getStringConfigValue("ClientGame", "loginServerAddress0", "loginServerPort0");
if (loginAddress != server->getHost() || port != QString::number(server->getPort())) {
#ifdef Q_OS_WIN32
QFile loginFile(folder + "\\swgemu_login.cfg");
#else
QFile loginFile(folder + "/swgemu_login.cfg");
#endif
if (loginFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream stream(&loginFile);
stream << "[ClientGame]" << endl;
stream << "loginServerAddress0=" << server->getHost() << endl;
stream << "loginServerPort0=" << server->getPort();
loginFile.close();
} else {
QMessageBox::warning(this, "Error", "Could not write swgemu_login.cfg!");
}
}
/*
arguments.append("--");
arguments.append("-s");
arguments.append("ClientGame");
arguments.append("cameraFarPlane=4096");
*/
/*
arguments.append("--");
arguments.append("-s");
arguments.append("SharedFoundation");
arguments.append("minFrameRate=60");
*/
// QFile executable()
/*
arguments.append("--");
arguments.append("-s");
arguments.append("ClientTerrain");
arguments.append("dynamicNearFloraDistance=128");
arguments.append("--");
arguments.append("-s");
arguments.append("ClientTerrain");
arguments.append("staticNonCollidableFloraDistance=2048");
arguments.append("--");
arguments.append("-s");
arguments.append("ClientProceduralTerrainAppearance_LevelOfDetail");
arguments.append("forceHighThreshold=40");
arguments.append("--");
arguments.append("-s");
arguments.append("ClientProceduralTerrainAppearance_LevelOfDetail");
arguments.append("threshold=40");
arguments.append("--");
arguments.append("-s");
arguments.append("ClientProceduralTerrainAppearance_LevelOfDetail");
arguments.append("heightBiasMax=4096");
*/
//ClientProceduralTerrainAppearance_LevelOfDetail.heightBiasMax
//ClientGame.cameraFarPlane
/*ClientProceduralTerrainAppearance_LevelOfDetail.threshold*/
/*ClientProceduralTerrainAppearance_LevelOfDetail.forceHighThreshold*/
arguments.append("--");
arguments.append("-s");
arguments.append("ClientGame");
if (server != NULL)
arguments.append("loginServerAddress0=" + server->getHost());
else
arguments.append("loginServerAddress0=" + LoginServers::defaultLoginAddress);
if (server == NULL)
arguments.append("loginServerPort0=" + QString::number(LoginServers::defaultLoginPort));
else
arguments.append("loginServerPort0=" + QString::number(server->getPort()));
arguments.append("-s");
arguments.append("Station");
arguments.append("gameFeatures=34929");
if (multiple) {
if (parser->hasConfigValue("SwgClient", "allowMultipleInstances")) {
bool val = parser->getBooleanConfigValue("SwgClient", "allowMultipleInstances");
if (!val) {
QMessageBox::warning(this, "Warning", "You selected the multiple instances option but you have set it to false in the swg config files!");
}
}
arguments.append("-s");
arguments.append("SwgClient");
arguments.append("allowMultipleInstances=true");
}
qDebug() << "start swg with arguments " << arguments;
connect(process, SIGNAL(processFinished(GameProcess*,int)), this, SLOT(gameProcessFinished(GameProcess*,int)));
ui->tabWidget->addTab(process, "Process " + QString::number(++gameProcessesCount));
gameProcesses.append(process);
QTabBar* bar = ui->tabWidget->tabBar();
int tabIndex = ui->tabWidget->indexOf(process);
bar->setTabTextColor(tabIndex, Qt::green);
bar->setTabIcon(tabIndex, QIcon(":/img/tab.svg"));
//process->show();
bool startResult = process->start(folder, gameExecutable, arguments);
if (startResult) {
//showMinimized();
if (settings.value("minimize_after_start", false).toBool()) {
systemTrayIcon->show();
QTimer::singleShot(0, this, SLOT(hide()));
}
}
}
void MainWindow::gameProcessFinished(GameProcess* process, int ) {
//ui->tabWidget->fi
int index = ui->tabWidget->indexOf(process);
//ui->tabWidget->setTabText(index, "");
if (index < 1)
return;
QTabBar* bar = ui->tabWidget->tabBar();
bar->setTabTextColor(index, Qt::red);
}
void MainWindow::statusXmlIsReady(QNetworkReply* reply) {
qDebug() << "updating server status";
if (reply->error() != QNetworkReply::NoError) {
QString errorStr = reply->errorString();
if (!errorStr.isEmpty()) {
ui->textBrowser->setText("Error while fetching server status:" + errorStr);
return;
}
}
QXmlSimpleReader xmlReader;
QXmlInputSource inputSource;
inputSource.setData(reply->readAll());
//StatusXmlContentHandler* handler = new StatusXmlContentHandler(this);
StatusXmlContentHandler handler(this);
xmlReader.setContentHandler(&handler);
xmlReader.parse(&inputSource);
QMap<QString, QString>* values = handler.getValues();
QString labelText;
QTextStream stream(&labelText);
bool up = values->value("status") == "up";
stream << "<div align=\"center\"><b>" << values->value("name") << "</b></div>";
if (up) {
stream << "<div align=\"center\" style=\"color:green\">Status: " << values->value("status") << "</div>";
stream << "<div align=\"center\">Current online connections: " << values->value("connected") << "</div>";
stream << "<div align=\"center\">Max allowed connections: " << values->value("cap") << "</div>";
/*QDateTime upTime;
upTime.addSecs(values->value("uptime").toULong());*/
//upTime.
//stream << "<div align=\"center\">Uptime: " << values->value("uptime") << " seconds</div>";
QString uptimeString;
QTextStream uptimeStream(&uptimeString);
qint64 uptimeSeconds = values->value("uptime").toULongLong();
//if (uptimeSeconds % )
qint64 minutes = uptimeSeconds / 60 % 60;
qint64 hours = uptimeSeconds / 3600 % 24;
qint64 days = uptimeSeconds / 86400;
if (days != 0) {
uptimeStream << days << (days == 1 ? " day " : " days ") << hours << (hours == 1 ? " hour " : " hours ") << minutes << (minutes == 1 ? " minute " : " minutes" );
} else if (hours != 0) {
uptimeStream << hours << (hours == 1 ? " hour " : " hours ") << minutes << (minutes == 1 ? " minute " : " minutes ");
} else {
uptimeStream << minutes << (minutes == 1 ? " minute " : " minutes ") << uptimeSeconds % 60 << " seconds";
}
stream << "<div align=\"center\">Uptime: " << uptimeString << " </div>";
} else
stream << "<div align=\"center\" style=\"color:red\">Status: " << values->value("status") << "</div>";
QDateTime timestamp;
timestamp.setTime_t(values->value("timestamp").toULong());
stream << "<div align=\"center\">Last updated: " << timestamp.toString(Qt::SystemLocaleShortDate) << "</div><br><br>";
ui->textBrowser->insertHtml(labelText);
}
void MainWindow::webPageLoadFinished(bool ok) {
if (!ok) {
ui->statusBar->showMessage("Error loading swgemu.com");
return;
}
ui->statusBar->showMessage("swgemu.com loaded.");
//updateDonationMeter();
//e.
}
void MainWindow::updateDonationMeter() {
QWebElement e = ui->webView->page()->mainFrame()->findFirstElement("span#ds_bar_67_percentText");
QString value = e.toPlainText();
QString num = value.mid(0, value.indexOf("%"));
ui->donationBar->setValue(num.toInt());
ui->label_current_work->setText("Donation meter loaded.");
}
void MainWindow::closeEvent(QCloseEvent *event) {
if (QMessageBox::question(this, "Close", "Are you sure you want to exit the launchpad?") != QMessageBox::Yes) {
event->ignore();
return;
}
cancelWorkingThreads = true;
ui->statusBar->showMessage("Shutting down working threads..");
if (loadWatcher.isRunning()) {
loadWatcher.cancel();
loadWatcher.waitForFinished();
}
if (fullScanWatcher.isRunning()) {
fullScanWatcher.cancel();
fullScanWatcher.waitForFinished();
}
while (!fullScanWorkingThreads.testAndSetAcquire(0, 0)) {
QThread::yieldCurrentThread();
QThread::msleep(500);
}
ui->statusBar->showMessage("Threads canceled.");
QSettings settings;
settings.setValue("mainWindowGeometry", saveGeometry());
settings.setValue("mainWindowState", saveState());
QString currentLogin = ui->comboBox_login->currentText();
settings.setValue("selected_login_server", currentLogin);
QMainWindow::closeEvent(event);
}
void MainWindow::closeTab(int index) {
if (index == 0)
return;
GameProcess* widget = dynamic_cast<GameProcess*>(ui->tabWidget->widget(index));
ui->tabWidget->removeTab(index);
if (widget != NULL) {
int idx = gameProcesses.indexOf(widget);
if (idx >= 0) {
qDebug() << "removing game process from vector";
gameProcesses.remove(idx);
}
widget->disconnect();
widget->clearOutputLogScreen();
widget->deleteLater();
//delete widget;
}
}
void MainWindow::installSWGEmu() {
InstallFromSWG installation(this);
int result = installation.installFiles();
if (result == 0) {
QSettings settingsVals;
settingsVals.setValue("swg_folder", installation.getEmuFolder());
settings->restoreFolder();
startFullScan(true);
}
}
void MainWindow::showGameModsOptions() {
GameMods dialog(this);
dialog.exec();
}
void MainWindow::showMacroEditor() {
MacroEditor dialog(this);
dialog.exec();
}