diff --git a/CMakeLists.txt b/CMakeLists.txt index 3939dff..3de8a4b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ qt_add_executable(minecraft-launcher settingsdialog.h settingsdialog.cpp settingsdialog.ui mainwindow.ui - + profiledialog.h profiledialog.cpp profiledialog.ui ) diff --git a/mainwindow.cpp b/mainwindow.cpp index bf0ae4d..11a6fdb 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -1,6 +1,7 @@ #include "mainwindow.h" #include "ui_mainwindow.h" // Подключаем сгенерированный заголовочный файл #include "settingsdialog.h" +#include "profiledialog.h" // Подключаем новый диалог #include #include @@ -12,6 +13,8 @@ #include // Для работы с JSON #include // Для работы с JSON #include // Для работы с JSON +#include // Для генерации ID профиля +#include // Для поиска папки с данными MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) @@ -32,6 +35,9 @@ MainWindow::MainWindow(QWidget *parent) connect(process, &QProcess::readyReadStandardError, this, &MainWindow::readProcessOutput); connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(onProcessFinished(int, QProcess::ExitStatus))); connect(process, SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(onProcessError(QProcess::ProcessError))); + // Загружаем профили при старте + profilesPath = "/launcher_profiles.json"; + loadProfiles(); } MainWindow::~MainWindow() @@ -86,8 +92,146 @@ bool checkRules(const QJsonObject &item) { return isAllowed; } +void MainWindow::loadProfiles() +{ + QFile profilesFile(profilesPath); + if (profilesFile.exists() && profilesFile.open(QIODevice::ReadOnly)) { + QJsonDocument doc = QJsonDocument::fromJson(profilesFile.readAll()); + profilesData = doc.object(); + profilesFile.close(); + } else { + // Создаем базовую структуру, если файла нет + profilesData = QJsonObject({{"profiles", QJsonObject()}}); + } + + QJsonObject profiles = profilesData["profiles"].toObject(); + ui->profileComboBox->clear(); + + if (profiles.isEmpty()) { + // Если профилей нет, принудительно открываем диалог создания + QMessageBox::information(this, "Настройка", "Не найдено ни одного профиля. Давайте создадим новый."); + createNewProfile(); + return; // createNewProfile вызовет loadProfiles() повторно + } + + // Заполняем ComboBox + for (const QString &key : profiles.keys()) { + QJsonObject profile = profiles[key].toObject(); + ui->profileComboBox->addItem(profile["name"].toString(), key); // Имя и UUID + } +} + +void MainWindow::saveProfiles() +{ + QFile profilesFile(profilesPath); + if (profilesFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + QJsonDocument doc(profilesData); + profilesFile.write(doc.toJson(QJsonDocument::Indented)); + profilesFile.close(); + } else { + QMessageBox::critical(this, "Ошибка", "Не удалось сохранить файл профилей: " + profilesFile.errorString()); + } +} + +void MainWindow::on_editProfileButton_clicked() +{ + // 1. Проверяем, выбран ли профиль + QString currentProfileId = ui->profileComboBox->currentData().toString(); + if (currentProfileId.isEmpty()) { + QMessageBox::warning(this, "Нет профиля", "Пожалуйста, выберите профиль для редактирования."); + return; + } + + // 2. Получаем данные текущего профиля + QJsonObject profiles = profilesData["profiles"].toObject(); + QJsonObject currentProfile = profiles[currentProfileId].toObject(); + + // 3. Создаем диалог и заполняем его данными + ProfileDialog dialog(this); + dialog.setWindowTitle("Редактирование профиля"); + dialog.setProfileName(currentProfile["name"].toString()); + dialog.setJavaPath(currentProfile["javaDir"].toString()); + + // 4. Показываем диалог и обрабатываем результат + if (dialog.exec() == QDialog::Accepted) { + if (dialog.profileName().isEmpty() || dialog.javaPath().isEmpty()) { + QMessageBox::warning(this, "Ошибка", "Имя профиля и путь к Java не могут быть пустыми."); + return; + } + + // 5. Обновляем данные в нашем JSON объекте + currentProfile["name"] = dialog.profileName(); + currentProfile["javaDir"] = dialog.javaPath(); + + // 6. Записываем обновленный профиль обратно + profiles[currentProfileId] = currentProfile; + profilesData["profiles"] = profiles; + + // 7. Сохраняем и перезагружаем список + saveProfiles(); + + // Сохраняем ID, чтобы восстановить выбор после перезагрузки + QString previouslySelectedId = currentProfileId; + loadProfiles(); + int indexToSelect = ui->profileComboBox->findData(previouslySelectedId); + if (indexToSelect != -1) { + ui->profileComboBox->setCurrentIndex(indexToSelect); + } + } +} + +void MainWindow::createNewProfile() +{ + ProfileDialog dialog(this); + if (dialog.exec() == QDialog::Accepted) { + if (dialog.profileName().isEmpty() || dialog.javaPath().isEmpty()) { + QMessageBox::warning(this, "Ошибка", "Имя профиля и путь к Java не могут быть пустыми."); + return; + } + + QString uuid = QUuid::createUuid().toString(QUuid::WithoutBraces); + QJsonObject newProfile; + newProfile["name"] = dialog.profileName(); + newProfile["javaDir"] = dialog.javaPath(); + newProfile["lastVersionId"] = ""; + newProfile["created"] = QDateTime::currentDateTime().toString(Qt::ISODate); + newProfile["lastUsed"] = QDateTime::currentDateTime().toString(Qt::ISODate); + newProfile["icon"] = "Bedrock"; + newProfile["type"] = "custom"; + + QJsonObject profiles = profilesData["profiles"].toObject(); + profiles[uuid] = newProfile; + profilesData["profiles"] = profiles; + + saveProfiles(); + loadProfiles(); // Перезагружаем список профилей + } +} + +void MainWindow::on_addProfileButton_clicked() +{ + createNewProfile(); +} + +void MainWindow::on_profileComboBox_currentIndexChanged(int index) +{ + // Пока ничего не делаем, но слот полезен для будущего + Q_UNUSED(index); +} + void MainWindow::on_launchButton_clicked() { + QString currentProfileId = ui->profileComboBox->currentData().toString(); + if (currentProfileId.isEmpty()) { + QMessageBox::critical(this, "Ошибка", "Не выбран профиль для запуска!"); + return; + } + QJsonObject profile = profilesData["profiles"].toObject()[currentProfileId].toObject(); + QString javaPath = profile["javaDir"].toString(); + if (!QFileInfo::exists(javaPath)) { + QMessageBox::critical(this, "Ошибка", "Не найден исполняемый файл Java, указанный в профиле:\n" + javaPath); + return; + } // --- 1. Выбор версии (остается без изменений) --- QString minecraftPath = getMinecraftPath(); if (minecraftPath.isEmpty()) { @@ -229,7 +373,7 @@ void MainWindow::on_launchButton_clicked() // --- 6. Финальная сборка и запуск --- QString mainClass = rootObj["mainClass"].toString(); - QString javaPath = "java"; + //QString javaPath = "java"; QStringList finalArguments; finalArguments << jvmArgs << mainClass << gameArgs; diff --git a/mainwindow.h b/mainwindow.h index 0bce635..fcf731e 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -4,6 +4,7 @@ #include #include #include +#include // Важно: добавить для хранения данных профилей // Предварительное объявление класса, сгенерированного из mainwindow.ui QT_BEGIN_NAMESPACE @@ -24,6 +25,9 @@ private slots: void on_modsFolderButton_clicked(); void on_updateModsButton_clicked(); void on_settingsButton_clicked(); + void on_addProfileButton_clicked(); // Слот для кнопки "Новый..." + void on_editProfileButton_clicked(); // <-- ДОБАВЬТЕ ЭТОТ СЛОТ + void on_profileComboBox_currentIndexChanged(int index); // Слот для смены профиля // Слоты для QProcess (подключаются вручную) void onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); @@ -33,6 +37,13 @@ private slots: private: QString getMinecraftPath(); + // Новые методы для работы с профилями + void loadProfiles(); + void saveProfiles(); + void createNewProfile(); + QString profilesPath; // Путь к launcher_profiles.json + QJsonObject profilesData; // JSON данные из файла + Ui::MainWindow *ui; // Указатель на объект интерфейса QProcess *process; QSettings *settings; diff --git a/mainwindow.ui b/mainwindow.ui index 9cce9c2..0e95b55 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -15,6 +15,34 @@ + + + + + + Профиль: + + + + + + + + + + Новый... + + + + + + + Редактировать... + + + + + @@ -65,4 +93,4 @@ - \ No newline at end of file + diff --git a/profiledialog.cpp b/profiledialog.cpp new file mode 100644 index 0000000..e5fd062 --- /dev/null +++ b/profiledialog.cpp @@ -0,0 +1,48 @@ +#include "profiledialog.h" +#include "ui_profiledialog.h" +#include + +ProfileDialog::ProfileDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::ProfileDialog) +{ + ui->setupUi(this); +} + +ProfileDialog::~ProfileDialog() +{ + delete ui; +} + +QString ProfileDialog::profileName() const +{ + return ui->profileNameEdit->text(); +} + +QString ProfileDialog::javaPath() const +{ + return ui->javaPathEdit->text(); +} +// === РЕАЛИЗАЦИЯ НОВЫХ ФУНКЦИЙ === +void ProfileDialog::setProfileName(const QString &name) +{ + ui->profileNameEdit->setText(name); +} + +void ProfileDialog::setJavaPath(const QString &path) +{ + ui->javaPathEdit->setText(path); +} +// =============================== + +void ProfileDialog::on_browseButton_clicked() +{ + QString filter = "Исполняемый файл (java.exe)"; +#if !defined(Q_OS_WIN) + filter = "Все файлы (*)"; +#endif + QString path = QFileDialog::getOpenFileName(this, "Выберите java.exe", QDir::homePath(), filter); + if (!path.isEmpty()) { + ui->javaPathEdit->setText(QDir::toNativeSeparators(path)); + } +} diff --git a/profiledialog.h b/profiledialog.h new file mode 100644 index 0000000..ea6368e --- /dev/null +++ b/profiledialog.h @@ -0,0 +1,32 @@ +#ifndef PROFILEDIALOG_H +#define PROFILEDIALOG_H + +#include + +namespace Ui { +class ProfileDialog; +} + +class ProfileDialog : public QDialog +{ + Q_OBJECT + +public: + explicit ProfileDialog(QWidget *parent = nullptr); + ~ProfileDialog(); + + QString profileName() const; + QString javaPath() const; + // === НОВЫЕ ФУНКЦИИ === + void setProfileName(const QString &name); + void setJavaPath(const QString &path); + + +private slots: + void on_browseButton_clicked(); + +private: + Ui::ProfileDialog *ui; +}; + +#endif // PROFILEDIALOG_H diff --git a/profiledialog.ui b/profiledialog.ui new file mode 100644 index 0000000..0b923a5 --- /dev/null +++ b/profiledialog.ui @@ -0,0 +1,99 @@ + + + ProfileDialog + + + + 0 + 0 + 450 + 150 + + + + Настройка профиля + + + + + + + + Имя профиля: + + + + + + + + + + Путь к Java: + + + + + + + + + + + + ... + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + ProfileDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ProfileDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + \ No newline at end of file