Huge Java detection refactor, version dialogs on first run (no JavaPath set) and "auto detect" button

This commit is contained in:
Sky 2013-10-14 02:59:21 +01:00
parent 0ae8073d41
commit 40a2456646
13 changed files with 421 additions and 50 deletions

View File

@ -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

View File

@ -5,8 +5,10 @@
#include <QNetworkAccessManager>
#include <QTranslator>
#include <QLibraryInfo>
#include <QMessageBox>
#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<JI_PATH>(javas.at(0)));
}
m_settings->registerSetting(new Setting("JvmArgs", ""));
// Custom Commands
@ -342,6 +333,15 @@ std::shared_ptr<MinecraftVersionList> MultiMC::minecraftlist()
return m_minecraftlist;
}
std::shared_ptr<JavaVersionList> 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())
{

View File

@ -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<MinecraftVersionList> minecraftlist();
std::shared_ptr<JavaVersionList> javalist();
private:
void initLogger();
@ -95,6 +98,7 @@ private:
std::shared_ptr<LWJGLVersionList> m_lwjgllist;
std::shared_ptr<ForgeVersionList> m_forgelist;
std::shared_ptr<MinecraftVersionList> m_minecraftlist;
std::shared_ptr<JavaVersionList> m_javalist;
QsLogging::DestinationPtr m_fileDestination;
QsLogging::DestinationPtr m_debugDestination;

View File

@ -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<JavaVersion>(vselect.selectedVersion());
MMC->settings()->set("JavaPath", java->path);
}
}

View File

@ -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;

View File

@ -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 <settingsobject.h>
#include <QFileDialog>
@ -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<JI_PATH>(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<JavaVersion>(vselect.selectedVersion());
ui->javaPathTextBox->setText(java->path);
}
}
void SettingsDialog::on_btnBrowse_clicked()

View File

@ -423,7 +423,7 @@
</sizepolicy>
</property>
<property name="text">
<string>Auto-detect</string>
<string>Auto-detect...</string>
</property>
</widget>
</item>

View File

@ -26,7 +26,7 @@
#include <logic/lists/BaseVersionList.h>
#include <logic/tasks/Task.h>
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();

View File

@ -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

View File

@ -15,29 +15,37 @@
#include "JavaUtils.h"
#include "pathutils.h"
#include "MultiMC.h"
#include <QStringList>
#include <QString>
#include <QDir>
#include <QMessageBox>
#include <logger/QsLog.h>
#include <gui/versionselectdialog.h>
#include <setting.h>
JavaUtils::JavaUtils()
{
}
std::vector<java_install> JavaUtils::GetDefaultJava()
JavaVersionPtr JavaUtils::GetDefaultJava()
{
std::vector<java_install> 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<java_install> JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString keyName)
QList<JavaVersionPtr> JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString keyName)
{
std::vector<java_install> javas;
QList<JavaVersionPtr> javas;
QString archType = "unknown";
if(keyType == KEY_WOW64_64KEY) archType = "64";
@ -87,7 +95,14 @@ std::vector<java_install> 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<java_install> JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QStr
return javas;
}
std::vector<java_install> JavaUtils::FindJavaPaths()
{
std::vector<java_install> JRE64s = this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Runtime Environment");
std::vector<java_install> JDK64s = this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Development Kit");
std::vector<java_install> JRE32s = this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\Java Runtime Environment");
std::vector<java_install> JDK32s = this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\Java Development Kit");
QList<JavaVersionPtr> JavaUtils::FindJavaPaths()
{
QList<JavaVersionPtr> javas;
std::vector<java_install> 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<JavaVersionPtr> JRE64s = this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Runtime Environment");
QList<JavaVersionPtr> JDK64s = this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Development Kit");
QList<JavaVersionPtr> JRE32s = this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\Java Runtime Environment");
QList<JavaVersionPtr> 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<java_install> JavaUtils::FindJavaPaths()
for(auto &java : javas)
{
QString sRec;
if(std::get<JI_REC>(java)) sRec = "(Recommended)";
QLOG_INFO() << std::get<JI_ID>(java) << std::get<JI_ARCH>(java) << " at " << std::get<JI_PATH>(java) << sRec;
if(java->recommended) sRec = "(Recommended)";
QLOG_INFO() << java->id << java->arch << " at " << java->path << sRec;
}
return javas;

View File

@ -16,29 +16,25 @@
#pragma once
#include <QStringList>
#include <QWidget>
#include <logic/lists/JavaVersionList.h>
#include "osutils.h"
#if WINDOWS
#include <windows.h>
#endif
#define JI_ID 0
#define JI_ARCH 1
#define JI_PATH 2
#define JI_REC 3
typedef std::tuple<QString, QString, QString, bool> java_install;
class JavaUtils
{
public:
JavaUtils();
std::vector<java_install> FindJavaPaths();
QList<JavaVersionPtr> FindJavaPaths();
JavaVersionPtr GetDefaultJava();
private:
std::vector<java_install> GetDefaultJava();
#if WINDOWS
std::vector<java_install> FindJavaFromRegistryKey(DWORD keyType, QString keyName);
QList<JavaVersionPtr> FindJavaFromRegistryKey(DWORD keyType, QString keyName);
#endif
};

View File

@ -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 <QtNetwork>
#include <QtXml>
#include <QRegExp>
#include <logger/QsLog.h>
#include <logic/JavaUtils.h>
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<JavaVersion>(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<JavaVersion>(m_vlist.at(i));
if (ver->recommended)
{
return m_vlist.at(i);
}
}
return BaseVersionPtr();
}
void JavaVersionList::updateListData(QList<BaseVersionPtr> 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<JavaVersionPtr> javas = ju.FindJavaPaths();
QList<BaseVersionPtr> javas_bvp;
for(int i = 0; i < javas.length(); i++)
{
BaseVersionPtr java = std::dynamic_pointer_cast<BaseVersion>(javas.at(i));
if(java)
{
javas_bvp.append(java);
}
}
m_list->updateListData(javas_bvp);
emitSucceeded();
}

View File

@ -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 <QObject>
#include <QAbstractListModel>
#include <QSharedPointer>
#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<JavaVersion> 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<BaseVersionPtr> versions);
protected:
QList<BaseVersionPtr> 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;
};