diff --git a/CMakeLists.txt b/CMakeLists.txt index 5503c5ca..64823772 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -302,6 +302,8 @@ logic/lists/LwjglVersionList.h logic/lists/LwjglVersionList.cpp logic/lists/ForgeVersionList.h logic/lists/ForgeVersionList.cpp +logic/lists/JavaVersionList.h +logic/lists/JavaVersionList.cpp # misc model/view logic/EnabledItemFilter.h diff --git a/MultiMC.cpp b/MultiMC.cpp index be1b86da..481bb0bb 100644 --- a/MultiMC.cpp +++ b/MultiMC.cpp @@ -5,8 +5,10 @@ #include #include #include +#include #include "gui/mainwindow.h" +#include "gui/versionselectdialog.h" #include "logic/lists/InstanceList.h" #include "logic/lists/IconList.h" #include "logic/lists/LwjglVersionList.h" @@ -263,17 +265,6 @@ void MultiMC::initGlobalSettings() // Java Settings m_settings->registerSetting(new Setting("JavaPath", "")); - QString currentJavaPath = m_settings->get("JavaPath").toString(); - if(currentJavaPath.isEmpty()) - { - QLOG_INFO() << "Java path not set, attempting to set it automatically..."; - - JavaUtils jut; - auto javas = jut.FindJavaPaths(); - - m_settings->set("JavaPath", std::get(javas.at(0))); - } - m_settings->registerSetting(new Setting("JvmArgs", "")); // Custom Commands @@ -342,6 +333,15 @@ std::shared_ptr MultiMC::minecraftlist() return m_minecraftlist; } +std::shared_ptr MultiMC::javalist() +{ + if (!m_javalist) + { + m_javalist.reset(new JavaVersionList()); + } + return m_javalist; +} + int main(int argc, char *argv[]) { // initialize Qt @@ -350,6 +350,7 @@ int main(int argc, char *argv[]) // show main window MainWindow mainWin; mainWin.show(); + mainWin.checkSetDefaultJava(); switch (app.status()) { diff --git a/MultiMC.h b/MultiMC.h index ec28cab2..62375cba 100644 --- a/MultiMC.h +++ b/MultiMC.h @@ -16,6 +16,7 @@ class InstanceList; class IconList; class QNetworkAccessManager; class ForgeVersionList; +class JavaVersionList; #if defined(MMC) #undef MMC @@ -75,6 +76,8 @@ public: std::shared_ptr minecraftlist(); + std::shared_ptr javalist(); + private: void initLogger(); @@ -95,6 +98,7 @@ private: std::shared_ptr m_lwjgllist; std::shared_ptr m_forgelist; std::shared_ptr m_minecraftlist; + std::shared_ptr m_javalist; QsLogging::DestinationPtr m_fileDestination; QsLogging::DestinationPtr m_debugDestination; diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index c726591d..06329140 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -53,6 +53,7 @@ #include "logic/lists/MinecraftVersionList.h" #include "logic/lists/LwjglVersionList.h" #include "logic/lists/IconList.h" +#include "logic/lists/JavaVersionList.h" #include "logic/net/LoginTask.h" #include "logic/BaseInstance.h" @@ -60,6 +61,7 @@ #include "logic/MinecraftProcess.h" #include "logic/OneSixAssets.h" #include "logic/OneSixUpdate.h" +#include "logic/JavaUtils.h" #include "logic/LegacyInstance.h" @@ -701,3 +703,31 @@ void MainWindow::instanceEnded() this->show(); ui->actionLaunchInstance->setEnabled(m_selectedInstance); } + +void MainWindow::checkSetDefaultJava() +{ + QString currentJavaPath = MMC->settings()->get("JavaPath").toString(); + if(currentJavaPath.isEmpty()) + { + QLOG_DEBUG() << "Java path not set, showing Java selection dialog..."; + + JavaVersionPtr java; + + VersionSelectDialog vselect(MMC->javalist().get(), tr("First run: select a Java version"), this, false); + vselect.setResizeOn(2); + vselect.exec(); + + if (!vselect.selectedVersion()) + { + QMessageBox::warning( + this, tr("Invalid version selected"), tr("You didn't select a valid Java version, so MultiMC will select the default. " + "You can change this in the settings dialog.")); + + JavaUtils ju; + java = ju.GetDefaultJava(); + } + + java = std::dynamic_pointer_cast(vselect.selectedVersion()); + MMC->settings()->set("JavaPath", java->path); + } +} diff --git a/gui/mainwindow.h b/gui/mainwindow.h index 86f21113..dbf7c4c3 100644 --- a/gui/mainwindow.h +++ b/gui/mainwindow.h @@ -49,6 +49,8 @@ public: // Browser Dialog void openWebPage(QUrl url); + void checkSetDefaultJava(); + private slots: void onCatToggled(bool); @@ -128,7 +130,6 @@ protected: void setCatBackground(bool enabled); private: - Ui::MainWindow *ui; KCategoryDrawer *drawer; KCategorizedView *view; diff --git a/gui/settingsdialog.cpp b/gui/settingsdialog.cpp index 011925b7..a3347680 100644 --- a/gui/settingsdialog.cpp +++ b/gui/settingsdialog.cpp @@ -17,6 +17,8 @@ #include "settingsdialog.h" #include "ui_settingsdialog.h" #include "logic/JavaUtils.h" +#include "gui/versionselectdialog.h" +#include "logic/lists/JavaVersionList.h" #include #include @@ -184,10 +186,17 @@ void SettingsDialog::loadSettings(SettingsObject *s) void SettingsDialog::on_pushButton_clicked() { - JavaUtils jut; - auto javas = jut.FindJavaPaths(); + JavaVersionPtr java; - ui->javaPathTextBox->setText(std::get(javas.at(0))); + VersionSelectDialog vselect(MMC->javalist().get(), tr("Select a Java version"), this, true); + vselect.setResizeOn(2); + vselect.exec(); + + if (vselect.result() == QDialog::Accepted && vselect.selectedVersion()) + { + java = std::dynamic_pointer_cast(vselect.selectedVersion()); + ui->javaPathTextBox->setText(java->path); + } } void SettingsDialog::on_btnBrowse_clicked() diff --git a/gui/settingsdialog.ui b/gui/settingsdialog.ui index 0b7985f1..f8e78b4d 100644 --- a/gui/settingsdialog.ui +++ b/gui/settingsdialog.ui @@ -423,7 +423,7 @@ - Auto-detect + Auto-detect... diff --git a/gui/versionselectdialog.cpp b/gui/versionselectdialog.cpp index d975a7b4..900cd092 100644 --- a/gui/versionselectdialog.cpp +++ b/gui/versionselectdialog.cpp @@ -26,7 +26,7 @@ #include #include -VersionSelectDialog::VersionSelectDialog(BaseVersionList *vlist, QString title, QWidget *parent) +VersionSelectDialog::VersionSelectDialog(BaseVersionList *vlist, QString title, QWidget *parent, bool cancelable) : QDialog(parent), ui(new Ui::VersionSelectDialog) { ui->setupUi(this); @@ -40,7 +40,12 @@ VersionSelectDialog::VersionSelectDialog(BaseVersionList *vlist, QString title, ui->listView->setModel(m_proxyModel); ui->listView->header()->setSectionResizeMode(QHeaderView::ResizeToContents); - ui->listView->header()->setSectionResizeMode(0, QHeaderView::Stretch); + ui->listView->header()->setSectionResizeMode(resizeOnColumn, QHeaderView::Stretch); + + if(!cancelable) + { + ui->buttonBox->button(QDialogButtonBox::Cancel)->setEnabled(false); + } } VersionSelectDialog::~VersionSelectDialog() @@ -48,6 +53,13 @@ VersionSelectDialog::~VersionSelectDialog() delete ui; } +void VersionSelectDialog::setResizeOn(int column) +{ + ui->listView->header()->setSectionResizeMode(resizeOnColumn, QHeaderView::ResizeToContents); + resizeOnColumn = column; + ui->listView->header()->setSectionResizeMode(resizeOnColumn, QHeaderView::Stretch); +} + int VersionSelectDialog::exec() { QDialog::open(); diff --git a/gui/versionselectdialog.h b/gui/versionselectdialog.h index 4be048af..319caeca 100644 --- a/gui/versionselectdialog.h +++ b/gui/versionselectdialog.h @@ -33,7 +33,7 @@ class VersionSelectDialog : public QDialog Q_OBJECT public: - explicit VersionSelectDialog(BaseVersionList *vlist, QString title, QWidget *parent = 0); + explicit VersionSelectDialog(BaseVersionList *vlist, QString title, QWidget *parent = 0, bool cancelable = true); ~VersionSelectDialog(); virtual int exec(); @@ -44,6 +44,7 @@ public: BaseVersionPtr selectedVersion() const; void setFilter(int column, QString filter); + void setResizeOn(int column); private slots: void on_refreshButton_clicked(); @@ -53,6 +54,8 @@ private: BaseVersionList *m_vlist; QSortFilterProxyModel *m_proxyModel; + + int resizeOnColumn = 0; }; #endif // VERSIONSELECTDIALOG_H diff --git a/logic/JavaUtils.cpp b/logic/JavaUtils.cpp index 5cec35b6..c0630545 100644 --- a/logic/JavaUtils.cpp +++ b/logic/JavaUtils.cpp @@ -15,29 +15,37 @@ #include "JavaUtils.h" #include "pathutils.h" +#include "MultiMC.h" #include #include #include +#include #include +#include +#include JavaUtils::JavaUtils() { } -std::vector JavaUtils::GetDefaultJava() +JavaVersionPtr JavaUtils::GetDefaultJava() { - std::vector javas; - javas.push_back(std::make_tuple("java", "unknown", "java", false)); + JavaVersionPtr javaVersion(new JavaVersion()); - return javas; + javaVersion->id = "java"; + javaVersion->arch = "unknown"; + javaVersion->path = "java"; + javaVersion->recommended = false; + + return javaVersion; } #if WINDOWS -std::vector JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString keyName) +QList JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString keyName) { - std::vector javas; + QList javas; QString archType = "unknown"; if(keyType == KEY_WOW64_64KEY) archType = "64"; @@ -87,7 +95,14 @@ std::vector JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QStr value = new char[valueSz]; RegQueryValueEx(newKey, "JavaHome", NULL, NULL, (BYTE*)value, &valueSz); - javas.push_back(std::make_tuple(subKeyName, archType, QDir(PathCombine(value, "bin")).absoluteFilePath("java.exe"), (recommended == subKeyName))); + // Now, we construct the version object and add it to the list. + JavaVersionPtr javaVersion(new JavaVersion()); + + javaVersion->id = subKeyName; + javaVersion->arch = archType; + javaVersion->path = QDir(PathCombine(value, "bin")).absoluteFilePath("java.exe"); + javaVersion->recommended = (recommended == subKeyName); + javas.append(javaVersion); } RegCloseKey(newKey); @@ -102,23 +117,25 @@ std::vector JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QStr return javas; } -std::vector JavaUtils::FindJavaPaths() -{ - std::vector JRE64s = this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Runtime Environment"); - std::vector JDK64s = this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Development Kit"); - std::vector JRE32s = this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\Java Runtime Environment"); - std::vector JDK32s = this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\Java Development Kit"); +QList JavaUtils::FindJavaPaths() +{ + QList javas; - std::vector javas; - javas.insert(javas.end(), JRE64s.begin(), JRE64s.end()); - javas.insert(javas.end(), JDK64s.begin(), JDK64s.end()); - javas.insert(javas.end(), JRE32s.begin(), JRE32s.end()); - javas.insert(javas.end(), JDK32s.begin(), JDK32s.end()); + QList JRE64s = this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Runtime Environment"); + QList JDK64s = this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Development Kit"); + QList JRE32s = this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\Java Runtime Environment"); + QList JDK32s = this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\Java Development Kit"); + + javas.append(JRE64s); + javas.append(JDK64s); + javas.append(JRE32s); + javas.append(JDK32s); if(javas.size() <= 0) { QLOG_WARN() << "Failed to find Java in the Windows registry - defaulting to \"java\""; - return this->GetDefaultJava(); + javas.append(this->GetDefaultJava()); + return javas; } QLOG_INFO() << "Found the following Java installations (64 -> 32, JRE -> JDK): "; @@ -126,8 +143,8 @@ std::vector JavaUtils::FindJavaPaths() for(auto &java : javas) { QString sRec; - if(std::get(java)) sRec = "(Recommended)"; - QLOG_INFO() << std::get(java) << std::get(java) << " at " << std::get(java) << sRec; + if(java->recommended) sRec = "(Recommended)"; + QLOG_INFO() << java->id << java->arch << " at " << java->path << sRec; } return javas; diff --git a/logic/JavaUtils.h b/logic/JavaUtils.h index 63daac12..e4f777d0 100644 --- a/logic/JavaUtils.h +++ b/logic/JavaUtils.h @@ -16,29 +16,25 @@ #pragma once #include - +#include +#include #include "osutils.h" #if WINDOWS #include #endif -#define JI_ID 0 -#define JI_ARCH 1 -#define JI_PATH 2 -#define JI_REC 3 -typedef std::tuple java_install; - class JavaUtils { public: JavaUtils(); - std::vector FindJavaPaths(); + QList FindJavaPaths(); + JavaVersionPtr GetDefaultJava(); private: - std::vector GetDefaultJava(); + #if WINDOWS - std::vector FindJavaFromRegistryKey(DWORD keyType, QString keyName); + QList FindJavaFromRegistryKey(DWORD keyType, QString keyName); #endif }; diff --git a/logic/lists/JavaVersionList.cpp b/logic/lists/JavaVersionList.cpp new file mode 100644 index 00000000..5389c4cc --- /dev/null +++ b/logic/lists/JavaVersionList.cpp @@ -0,0 +1,203 @@ +/* Copyright 2013 MultiMC Contributors + * + * 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. + */ + +#include "JavaVersionList.h" +#include "MultiMC.h" + +#include +#include +#include + +#include +#include + +JavaVersionList::JavaVersionList(QObject *parent) : BaseVersionList(parent) +{ +} + +Task *JavaVersionList::getLoadTask() +{ + return new JavaListLoadTask(this); +} + + +const BaseVersionPtr JavaVersionList::at(int i) const +{ + return m_vlist.at(i); +} + +bool JavaVersionList::isLoaded() +{ + return m_loaded; +} + +int JavaVersionList::count() const +{ + return m_vlist.count(); +} + +int JavaVersionList::columnCount(const QModelIndex &parent) const +{ + return 4; +} + +QVariant JavaVersionList::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (index.row() > count()) + return QVariant(); + + auto version = std::dynamic_pointer_cast(m_vlist[index.row()]); + switch (role) + { + case Qt::DisplayRole: + switch (index.column()) + { + case 0: + return version->id; + + case 1: + return version->arch; + + case 2: + return version->path; + + case 3: + return version->recommended ? tr("Yes") : tr("No"); + + default: + return QVariant(); + } + + case Qt::ToolTipRole: + return version->descriptor(); + + case VersionPointerRole: + return qVariantFromValue(m_vlist[index.row()]); + + default: + return QVariant(); + } +} + +QVariant JavaVersionList::headerData(int section, Qt::Orientation orientation, int role) const +{ + switch (role) + { + case Qt::DisplayRole: + switch (section) + { + case 0: + return "Version"; + + case 1: + return "Arch"; + + case 2: + return "Path"; + + case 3: + return "Recommended"; + + default: + return QVariant(); + } + + case Qt::ToolTipRole: + switch (section) + { + case 0: + return "The name of the version."; + + case 1: + return "The architecture this version is for."; + + case 2: + return "Path to this Java version."; + + case 3: + return "Whether the version is recommended or not."; + + default: + return QVariant(); + } + + default: + return QVariant(); + } +} + +BaseVersionPtr JavaVersionList::getTopRecommended() const +{ + for (int i = 0; i < m_vlist.length(); i++) + { + auto ver = std::dynamic_pointer_cast(m_vlist.at(i)); + if (ver->recommended) + { + return m_vlist.at(i); + } + } + return BaseVersionPtr(); +} + +void JavaVersionList::updateListData(QList versions) +{ + beginResetModel(); + m_vlist = versions; + m_loaded = true; + endResetModel(); + // NOW SORT!! + // sort(); +} + +void JavaVersionList::sort() +{ + // NO-OP for now +} + +JavaListLoadTask::JavaListLoadTask(JavaVersionList *vlist) +{ + m_list = vlist; + m_currentRecommended = NULL; +} + +JavaListLoadTask::~JavaListLoadTask() +{ +} + +void JavaListLoadTask::executeTask() +{ + setStatus("Detecting Java installations..."); + + JavaUtils ju; + QList javas = ju.FindJavaPaths(); + + QList javas_bvp; + for(int i = 0; i < javas.length(); i++) + { + BaseVersionPtr java = std::dynamic_pointer_cast(javas.at(i)); + + if(java) + { + javas_bvp.append(java); + } + } + + m_list->updateListData(javas_bvp); + + emitSucceeded(); +} diff --git a/logic/lists/JavaVersionList.h b/logic/lists/JavaVersionList.h new file mode 100644 index 00000000..23bccfe4 --- /dev/null +++ b/logic/lists/JavaVersionList.h @@ -0,0 +1,93 @@ +/* Copyright 2013 MultiMC Contributors + * + * 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. + */ + +#pragma once + +#include +#include +#include + +#include "BaseVersionList.h" +#include "logic/tasks/Task.h" + +class JavaListLoadTask; + +struct JavaVersion : public BaseVersion +{ + virtual QString descriptor() + { + return id; + } + + virtual QString name() + { + return id; + } + + virtual QString typeString() const + { + return arch; + } + + QString id; + QString arch; + QString path; + bool recommended; +}; + +typedef std::shared_ptr JavaVersionPtr; + +class JavaVersionList : public BaseVersionList +{ + Q_OBJECT +public: + explicit JavaVersionList(QObject *parent = 0); + + virtual Task *getLoadTask(); + virtual bool isLoaded(); + virtual const BaseVersionPtr at(int i) const; + virtual int count() const; + virtual void sort(); + + virtual BaseVersionPtr getTopRecommended() const; + + virtual QVariant data(const QModelIndex &index, int role) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, + int role) const; + virtual int columnCount(const QModelIndex &parent) const; + +public slots: + virtual void updateListData(QList versions); + +protected: + QList m_vlist; + + bool m_loaded = false; +}; + +class JavaListLoadTask : public Task +{ + Q_OBJECT + +public: + explicit JavaListLoadTask(JavaVersionList *vlist); + ~JavaListLoadTask(); + + virtual void executeTask(); + +protected: + JavaVersionList *m_list; + JavaVersion *m_currentRecommended; +};