summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorisanae <14251494+isanae@users.noreply.github.com>2020-11-06 13:56:04 -0500
committerisanae <14251494+isanae@users.noreply.github.com>2020-11-07 20:16:25 -0500
commitdc2ada2a4249917f538938298deb193ed1dd6bb9 (patch)
tree9f5564aae12004e4a55ed63f1ce294c0c75d7816 /src
parentb7cb63ddb1e2b263d5e485c97faea527c7c0af44 (diff)
added ... to the "Delete Instance" button to make it less scary
merged InstanceInfo into Instance, most of it was redundant added logging before deleting instance added Instance::readFromIni(), contains stuff that used to be in setup(), used by instance dialog replaced QDir with QString in a few places, I hate QDir
Diffstat (limited to 'src')
-rw-r--r--src/instancemanager.cpp278
-rw-r--r--src/instancemanager.h109
-rw-r--r--src/instancemanagerdialog.cpp347
-rw-r--r--src/instancemanagerdialog.h80
-rw-r--r--src/instancemanagerdialog.ui2
-rw-r--r--src/main.cpp8
6 files changed, 456 insertions, 368 deletions
diff --git a/src/instancemanager.cpp b/src/instancemanager.cpp
index e7c2a611..fbafc6e8 100644
--- a/src/instancemanager.cpp
+++ b/src/instancemanager.cpp
@@ -38,7 +38,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
using namespace MOBase;
-Instance::Instance(QDir dir, bool portable, QString profileName) :
+Instance::Instance(QString dir, bool portable, QString profileName) :
m_dir(std::move(dir)), m_portable(portable), m_plugin(nullptr),
m_profile(std::move(profileName))
{
@@ -49,7 +49,7 @@ QString Instance::name() const
if (isPortable())
return QObject::tr("Portable");
else
- return m_dir.dirName();
+ return QDir(m_dir).dirName();
}
QString Instance::gameName() const
@@ -62,11 +62,16 @@ QString Instance::gameDirectory() const
return m_gameDir;
}
-QDir Instance::directory() const
+QString Instance::directory() const
{
return m_dir;
}
+QString Instance::baseDirectory() const
+{
+ return m_baseDir;
+}
+
MOBase::IPluginGame* Instance::gamePlugin() const
{
return m_plugin;
@@ -87,13 +92,29 @@ bool Instance::isPortable() const
return m_portable;
}
-Instance::SetupResults Instance::setup(PluginContainer& plugins)
+bool Instance::isActive() const
+{
+ auto& m = InstanceManager::singleton();
+
+ if (auto i=m.currentInstance())
+ {
+ if (m_portable) {
+ return i->isPortable();
+ } else {
+ return (i->name() == name());
+ }
+ }
+
+ return false;
+}
+
+bool Instance::readFromIni()
{
Settings s(iniPath());
if (s.iniStatus() != QSettings::NoError) {
log::error("can't read ini {}", iniPath());
- return SetupResults::BadIni;
+ return false;
}
// game name and directory are from ini unless overridden by setGame()
@@ -107,27 +128,61 @@ Instance::SetupResults Instance::setup(PluginContainer& plugins)
m_gameDir = *v;
}
- // getting game plugin
- const auto r = getGamePlugin(plugins);
- if (r != SetupResults::Ok) {
- return r;
- }
-
- // getting game variant, error if it's missing and required by the plugin
if (m_gameVariant.isEmpty()) {
if (auto v=s.game().edition()) {
m_gameVariant = *v;
}
}
+ if (m_baseDir.isEmpty()) {
+ m_baseDir = s.paths().base();
+ }
+
+ // figuring out profile from ini if it's missing
+ getProfile(s);
+
+ return true;
+}
+
+Instance::SetupResults Instance::setup(PluginContainer& plugins)
+{
+ // read initial values from the ini
+ if (!readFromIni()) {
+ return SetupResults::BadIni;
+ }
+
+ // getting game plugin
+ const auto r = getGamePlugin(plugins);
+ if (r != SetupResults::Ok) {
+ return r;
+ }
+
+ // error if the variant missing and required by the plugin
if (m_gameVariant.isEmpty() && m_plugin->gameVariants().size() > 1) {
return SetupResults::MissingVariant;
} else {
m_plugin->setGameVariant(m_gameVariant);
}
- // figuring out profile from ini if it's missing
- getProfile(s);
+ // update the ini in case anything was missing
+ updateIni();
+
+ // the game directory may be different than what the plugin detected, the user
+ // can change it in the settings and might have multiple versions of the game
+ // installed
+ m_plugin->setGamePath(m_gameDir);
+
+ return SetupResults::Ok;
+}
+
+void Instance::updateIni()
+{
+ Settings s(iniPath());
+
+ if (s.iniStatus() != QSettings::NoError) {
+ log::error("can't open ini {}", iniPath());
+ return;
+ }
// updating the settings since some of these values might have been missing
s.game().setName(m_gameName);
@@ -138,13 +193,6 @@ Instance::SetupResults Instance::setup(PluginContainer& plugins)
// don't write a variant to the ini if the plugin doesn't require one
s.game().setEdition(m_gameVariant);
}
-
- // the game directory may be different than what the plugin detected, the user
- // can change it in the settings and might have multiple versions of the game
- // installed
- m_plugin->setGamePath(m_gameDir);
-
- return SetupResults::Ok;
}
void Instance::setGame(const QString& name, const QString& dir)
@@ -272,7 +320,6 @@ Instance::SetupResults Instance::getGamePlugin(PluginContainer& plugins)
}
}
-
void Instance::getProfile(const Settings& s)
{
if (!m_profile.isEmpty()) {
@@ -294,6 +341,176 @@ void Instance::getProfile(const Settings& s)
iniPath(), m_profile);
}
+// returns a list of files and folders that must be deleted when deleting
+// this instance
+//
+std::vector<Instance::Object> Instance::objectsForDeletion() const
+{
+ // native separators and ending slash
+ auto prettyDir = [](auto s) {
+ if (!s.endsWith("/") || !s.endsWith("\\")) {
+ s += "/";
+ }
+
+ return QDir::toNativeSeparators(s);
+ };
+
+ // native separators
+ auto prettyFile = [](auto s) {
+ return QDir::toNativeSeparators(s);
+ };
+
+
+ // lowercase, native separators and ending slash
+ auto canonicalDir = [](QString s) {
+ s = s.toLower();
+
+ if (!s.endsWith("/") || !s.endsWith("\\")) {
+ s += "/";
+ }
+
+ return QDir::toNativeSeparators(s);
+ };
+
+ // lower and native separators
+ auto canonicalFile = [](auto s) {
+ return QDir::toNativeSeparators(s.toLower());
+ };
+
+
+
+ // whether the given directory is contained in the root
+ auto dirInRoot = [&](const QString& root, const QString& dir) {
+ return canonicalDir(dir).startsWith(canonicalDir(root));
+ };
+
+ // whether the given file is contained in the root
+ auto fileInRoot = [&](const QString& root, const QString& file) {
+ return canonicalFile(file).startsWith(canonicalDir(root));
+ };
+
+
+ Settings settings(iniPath());
+
+ if (settings.iniStatus() != QSettings::NoError) {
+ log::error("can't read ini {}", iniPath());
+ return {};
+ }
+
+
+
+ const QString loc = directory();
+ const QString base = settings.paths().base();
+
+
+ // directories that might contain the individual files and directories
+ // set in the path settings
+ std::vector<Object> roots;
+
+ // a portable instance has its location in the installation directory,
+ // don't delete that
+ if (!isPortable()) {
+ if (QDir(loc).exists()) {
+ roots.push_back({loc, true});
+ }
+ }
+
+ // the base directory is the location directory by default, don't add it
+ // if it's the same
+ if (canonicalDir(base) != canonicalDir(loc)) {
+ if (QDir(base).exists()) {
+ roots.push_back({base, false});
+ }
+ }
+
+
+ // all the directories that are part of an instance; none of them are
+ // mandatory for deletion
+ const std::vector<Object> dirs = {
+ settings.paths().downloads(),
+ settings.paths().mods(),
+ settings.paths().cache(),
+ settings.paths().profiles(),
+ settings.paths().overwrite(),
+ QDir(m_dir).filePath(QString::fromStdWString(AppConfig::dumpsDir())),
+ QDir(m_dir).filePath(QString::fromStdWString(AppConfig::logPath())),
+ };
+
+ // all the files that are part of an instance
+ const std::vector<Object> files = {
+ {iniPath(), true}, // the ini file must be deleted
+ };
+
+
+ // this will contain the root directories, plus all the individual
+ // directories that are not inside these roots
+ std::vector<Object> cleanDirs;
+
+ for (const auto& f : dirs) {
+ bool inRoots = false;
+
+ for (const auto& root : roots) {
+ if (dirInRoot(root.path, f.path)) {
+ inRoots = true;
+ break;
+ }
+ }
+
+ if (!inRoots) {
+ // not in roots, this is a path that was changed by the user; make
+ // sure it exists
+ if (QDir(f.path).exists()) {
+ cleanDirs.push_back({prettyDir(f.path), f.mandatoryDelete});
+ }
+ }
+ }
+
+ // prepending the roots
+ for (auto itor=roots.rbegin(); itor!=roots.rend(); ++itor) {
+ cleanDirs.insert(
+ cleanDirs.begin(),
+ {prettyDir(itor->path), itor->mandatoryDelete});
+ }
+
+
+
+ // this will contain the individual files that are not inside the roots;
+ // not that this only contains the INI file for now, so most of this is
+ // useless
+ std::vector<Object> cleanFiles;
+
+ for (const auto& f : files) {
+ bool inRoots = false;
+
+ for (const auto& root : roots) {
+ if (fileInRoot(root.path, f.path)) {
+ inRoots = true;
+ break;
+ }
+ }
+
+ if (!inRoots) {
+ // not in roots, this is a path that was changed by the user; make
+ // sure it exists
+ if (QFileInfo(f.path).exists()) {
+ cleanFiles.push_back({prettyFile(f.path), f.mandatoryDelete});
+ }
+ }
+ }
+
+
+ // contains all the directories and files to be deleted
+ std::vector<Object> all;
+ all.insert(all.end(), cleanDirs.begin(), cleanDirs.end());
+ all.insert(all.end(), cleanFiles.begin(), cleanFiles.end());
+
+ // mandatory on top
+ std::stable_sort(all.begin(), all.end());
+
+ return all;
+}
+
+
InstanceManager::InstanceManager()
{
@@ -327,20 +544,20 @@ std::optional<Instance> InstanceManager::currentInstance() const
if (!allowedToChangeInstance()) {
// force portable instance
- return Instance(QDir(portablePath()), true, profile);
+ return Instance(portablePath(), true, profile);
}
if (name.isEmpty()) {
if (portableInstanceExists()) {
// use portable
- return Instance(QDir(portablePath()), true, profile);
+ return Instance(portablePath(), true, profile);
} else {
// no instance set
return {};
}
}
- return Instance(QDir(instancePath(name)), false, profile);
+ return Instance(instancePath(name), false, profile);
}
void InstanceManager::clearCurrentInstance()
@@ -365,12 +582,13 @@ QString InstanceManager::globalInstancesRootPath() const
QStandardPaths::writableLocation(QStandardPaths::DataLocation));
}
-QString InstanceManager::iniPath(const QDir& instanceDir) const
+QString InstanceManager::iniPath(const QString& instanceDir) const
{
- return instanceDir.filePath(QString::fromStdWString(AppConfig::iniFileName()));
+ return QDir(instanceDir).filePath(
+ QString::fromStdWString(AppConfig::iniFileName()));
}
-std::vector<QDir> InstanceManager::globalInstancePaths() const
+std::vector<QString> InstanceManager::globalInstancePaths() const
{
const std::set<QString> ignore = {
"cache", "qtwebengine",
@@ -379,7 +597,7 @@ std::vector<QDir> InstanceManager::globalInstancePaths() const
const QDir root(globalInstancesRootPath());
const auto dirs = root.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
- std::vector<QDir> list;
+ std::vector<QString> list;
for (auto&& d : dirs) {
if (!ignore.contains(QFileInfo(d).fileName().toLower())) {
@@ -416,7 +634,7 @@ bool InstanceManager::allowedToChangeInstance() const
}
const MOBase::IPluginGame* InstanceManager::gamePluginForDirectory(
- const QDir& instanceDir, const PluginContainer& plugins) const
+ const QString& instanceDir, const PluginContainer& plugins) const
{
const QString ini = iniPath(instanceDir);
diff --git a/src/instancemanager.h b/src/instancemanager.h
index e2ceb743..161df739 100644
--- a/src/instancemanager.h
+++ b/src/instancemanager.h
@@ -55,15 +55,64 @@ public:
};
+ // a file or directory owned by this instance, used by objectsForDeletion()
+ //
+ struct Object
+ {
+ // path to the file or directory
+ QString path;
+
+ // whether this object must be deleted to properly delete the instance;
+ // typically true only for the instance directory itself, but not for the
+ // base directory, etc.
+ bool mandatoryDelete;
+
+
+ Object(QString p, bool d=false)
+ : path(std::move(p)), mandatoryDelete(d)
+ {
+ }
+
+ // puts mandatory delete on top
+ //
+ bool operator<(const Object& o) const
+ {
+ if (mandatoryDelete && !o.mandatoryDelete) {
+ return true;
+ } else if (!mandatoryDelete && o.mandatoryDelete) {
+ return false;
+ }
+
+ return false;
+ }
+ };
+
+
+
// an instance that lives in the given directory; `portable` must be `true`
// if this is a portable instance
//
// `profileName` can be given to override what's in the INI; this typically
// happens when the profile is overriden on the command line
//
- Instance(QDir dir, bool portable, QString profileName={});
+ Instance(QString dir, bool portable, QString profileName={});
+
+
+ // reads in values from the INI if they were not given yet:
+ // - game name
+ // - game directory
+ // - game variant
+ // - profile name
+ //
+ // note that setup() already calls this
+ //
+ // returns false if the ini couldn't be read from
+ //
+ bool readFromIni();
- // finds the appropriate game plugin and sets it up so MO can use it
+
+ // finds the appropriate game plugin and sets it up so MO can use it; this
+ // calls readFromIni() first
//
// setup() tries to recover from some errors, but can fail for a variety of
// reasons, see SetupResults
@@ -88,22 +137,32 @@ public:
QString name() const;
// returns either:
- // 1) the game name from the INI,
- // 2) gameName() from the game plugin if it was missing, or
- // 3) whatever was given in setGame()
+ // 1) the game name from the INI, if readFromIni() was called;
+ // 2) gameName() from the game plugin if it was missing and setup() was
+ // called; or
+ // 3) whatever was given in setGame()
//
QString gameName() const;
// returns either:
- // 1) the game directory from the INI,
- // 2) gameDirectory() from the game plugin if it was missing, or
- // 3) whatever was given in setGame()
+ // 1) the game directory from the INI, if readFromIni() was called;
+ // 2) gameDirectory() from the game plugin if it was missing and setup()
+ // was called; or
+ // 3) whatever was given in setGame()
//
QString gameDirectory() const;
- // returns the instance directory; can be called without setup()
+ // returns the instance directory as given in the constructor
+ //
+ QString directory() const;
+
+ // returns the base directory; empty if readFromIni() hasn't been called
+ //
+ QString baseDirectory() const;
+
+ // returns whether this is a portable instance, as given in the constructor
//
- QDir directory() const;
+ bool isPortable() const;
// returns the selected game plugin; will return null if setup() hasn't been
// called, or if it failed
@@ -111,8 +170,8 @@ public:
MOBase::IPluginGame* gamePlugin() const;
// returns either:
- // 1) the profile name given in the constructor,
- // 2) the profile name from the INI, or
+ // 1) the profile name given in the constructor if not empty;
+ // 2) the profile name from the INI if readFromIni() was called, or
// 3) the default profile name if it's missing (see
// AppConfig::defaultProfileName())
//
@@ -123,15 +182,21 @@ public:
//
QString iniPath() const;
- // returns whether this is a portable instance; this is the flag given in the
- // constructor
+ // whether this is the currently active instance in MO
//
- bool isPortable() const;
+ bool isActive() const;
+
+ // returns a list of files and directories that must be deleted when deleting
+ // this instance; this will read the INI and fail if it's not accessible
+ //
+ // returns an empty list on failure
+ //
+ std::vector<Object> objectsForDeletion() const;
private:
- QDir m_dir;
+ QString m_dir;
bool m_portable;
- QString m_gameName, m_gameDir, m_gameVariant;
+ QString m_gameName, m_gameDir, m_gameVariant, m_baseDir;
MOBase::IPluginGame* m_plugin;
QString m_profile;
@@ -142,6 +207,10 @@ private:
// figures out the profile name for this instance
//
void getProfile(const Settings& s);
+
+ // updates the ini with the given values and the ones found by setup()
+ //
+ void updateIni();
};
@@ -175,7 +244,7 @@ public:
// returns null if all of this fails
//
const MOBase::IPluginGame* gamePluginForDirectory(
- const QDir& dir, const PluginContainer& plugins) const;
+ const QString& dir, const PluginContainer& plugins) const;
// clears the instance name from the registry; on restart, this will make MO
// either select the portable instance if it exists, or display the instance
@@ -221,7 +290,7 @@ public:
// returns the list of absolute path to all existing global instances; this
// does not include the portable instance
//
- std::vector<QDir> globalInstancePaths() const;
+ std::vector<QString> globalInstancePaths() const;
// returns `name` modified so that it is a valid instance name
//
@@ -253,7 +322,7 @@ public:
// returns the absolute path to the INI file for the given instance directory;
// the file may not exist
//
- QString iniPath(const QDir& instanceDir) const;
+ QString iniPath(const QString& instanceDir) const;
private:
InstanceManager();
diff --git a/src/instancemanagerdialog.cpp b/src/instancemanagerdialog.cpp
index c2108f9d..c199fa7b 100644
--- a/src/instancemanagerdialog.cpp
+++ b/src/instancemanagerdialog.cpp
@@ -13,292 +13,19 @@
using namespace MOBase;
-class InstanceInfo
-{
-public:
- struct Object
- {
- QString path;
- bool mandatoryDelete;
-
- Object(QString p, bool d=false)
- : path(std::move(p)), mandatoryDelete(d)
- {
- }
-
- bool operator<(const Object& o) const
- {
- if (mandatoryDelete && !o.mandatoryDelete) {
- return true;
- } else if (!mandatoryDelete && o.mandatoryDelete) {
- return false;
- }
-
- return false;
- }
- };
-
-
- InstanceInfo(QDir dir, bool isPortable)
- : m_portable(isPortable)
- {
- setDir(dir);
- }
-
- void setDir(const QDir& dir)
- {
- m_dir = dir;
- m_settings.reset(new Settings(InstanceManager::singleton().iniPath(dir)));
- }
-
- QString name() const
- {
- if (m_portable) {
- return QObject::tr("Portable");
- } else {
- return m_dir.dirName();
- }
- }
-
- QString gameName() const
- {
- if (auto n=m_settings->game().name()) {
- if (auto e=m_settings->game().edition()) {
- if (!e->isEmpty()) {
- return *n + " (" + *e + ")";
- }
- }
-
- return *n;
- } else {
- return {};
- }
- }
-
- QString gamePath() const
- {
- if (auto n=m_settings->game().directory()) {
- return QDir::toNativeSeparators(*n);
- } else {
- return {};
- }
- }
-
- QString location() const
- {
- return QDir::toNativeSeparators(m_dir.path());
- }
-
- QString baseDirectory() const
- {
- return QDir::toNativeSeparators(m_settings->paths().base());
- }
-
- QString iniFile() const
- {
- return InstanceManager::singleton().iniPath(m_dir);
- }
-
- QIcon icon(const PluginContainer& plugins) const
- {
- const auto* game = InstanceManager::singleton().gamePluginForDirectory(
- m_dir, plugins);
-
- if (game)
- return game->gameIcon();
-
- QPixmap empty(32, 32);
- empty.fill(QColor(0, 0, 0, 0));
- return QIcon(empty);
- }
-
- bool isPortable() const
- {
- return m_portable;
- }
-
- bool isActive() const
- {
- auto& m = InstanceManager::singleton();
-
- if (auto i=m.currentInstance())
- {
- if (m_portable) {
- return i->isPortable();
- } else {
- return (i->name() == name());
- }
- }
-
- return false;
- }
-
- // returns a list of files and folders that must be deleted when deleting
- // this instance
- //
- std::vector<Object> objectsForDeletion() const
- {
- // native separators and ending slash
- auto prettyDir = [](auto s) {
- if (!s.endsWith("/") || !s.endsWith("\\")) {
- s += "/";
- }
-
- return QDir::toNativeSeparators(s);
- };
-
- // native separators
- auto prettyFile = [](auto s) {
- return QDir::toNativeSeparators(s);
- };
-
-
- // lowercase, native separators and ending slash
- auto canonicalDir = [](auto s) {
- s = s.toLower();
- if (!s.endsWith("/") || !s.endsWith("\\")) {
- s += "/";
- }
-
- return QDir::toNativeSeparators(s);
- };
-
- // lower and native separators
- auto canonicalFile = [](auto s) {
- return QDir::toNativeSeparators(s.toLower());
- };
-
-
-
- // whether the given directory is contained in the root
- auto dirInRoot = [&](auto root, auto dir) {
- return canonicalDir(dir).startsWith(canonicalDir(root));
- };
-
- // whether the given file is contained in the root
- auto fileInRoot = [&](auto root, auto file) {
- return canonicalFile(file).startsWith(canonicalDir(root));
- };
+QIcon instanceIcon(const PluginContainer& pc, const Instance& i)
+{
+ const auto* game = InstanceManager::singleton()
+ .gamePluginForDirectory(i.directory(), pc);
+ if (game)
+ return game->gameIcon();
-
- const auto loc = location();
- const auto base = m_settings->paths().base();
-
-
- // directories that might contain the individual files and directories
- // set in the path settings
- std::vector<Object> roots;
-
- // a portable instance has its location in the installation directory,
- // don't delete that
- if (!isPortable()) {
- if (QDir(loc).exists()) {
- roots.push_back({loc, true});
- }
- }
-
- // the base directory is the location directory by default, don't add it
- // if it's the same
- if (canonicalDir(base) != canonicalDir(loc)) {
- if (QDir(base).exists()) {
- roots.push_back({base, false});
- }
- }
-
-
- // all the directories that are part of an instance; none of them are
- // mandatory for deletion
- const std::vector<Object> dirs = {
- m_settings->paths().downloads(),
- m_settings->paths().mods(),
- m_settings->paths().cache(),
- m_settings->paths().profiles(),
- m_settings->paths().overwrite(),
- m_dir.filePath(QString::fromStdWString(AppConfig::dumpsDir())),
- m_dir.filePath(QString::fromStdWString(AppConfig::logPath())),
- };
-
- // all the files that are part of an instance
- const std::vector<Object> files = {
- {iniFile(), true}, // the ini file must be deleted
- };
-
-
- // this will contain the root directories, plus all the individual
- // directories that are not inside these roots
- std::vector<Object> cleanDirs;
-
- for (const auto& f : dirs) {
- bool inRoots = false;
-
- for (const auto& root : roots) {
- if (dirInRoot(root.path, f.path)) {
- inRoots = true;
- break;
- }
- }
-
- if (!inRoots) {
- // not in roots, this is a path that was changed by the user; make
- // sure it exists
- if (QDir(f.path).exists()) {
- cleanDirs.push_back({prettyDir(f.path), f.mandatoryDelete});
- }
- }
- }
-
- // prepending the roots
- for (auto itor=roots.rbegin(); itor!=roots.rend(); ++itor) {
- cleanDirs.insert(
- cleanDirs.begin(),
- {prettyDir(itor->path), itor->mandatoryDelete});
- }
-
-
-
- // this will contain the individual files that are not inside the roots;
- // not that this only contains the INI file for now, so most of this is
- // useless
- std::vector<Object> cleanFiles;
-
- for (const auto& f : files) {
- bool inRoots = false;
-
- for (const auto& root : roots) {
- if (fileInRoot(root.path, f.path)) {
- inRoots = true;
- break;
- }
- }
-
- if (!inRoots) {
- // not in roots, this is a path that was changed by the user; make
- // sure it exists
- if (QFileInfo(f.path).exists()) {
- cleanFiles.push_back({prettyFile(f.path), f.mandatoryDelete});
- }
- }
- }
-
-
- // contains all the directories and files to be deleted
- std::vector<Object> all;
- all.insert(all.end(), cleanDirs.begin(), cleanDirs.end());
- all.insert(all.end(), cleanFiles.begin(), cleanFiles.end());
-
- // mandatory on top
- std::stable_sort(all.begin(), all.end());
-
- return all;
- }
-
-private:
- const bool m_portable;
- QDir m_dir;
- std::unique_ptr<Settings> m_settings;
-};
+ QPixmap empty(32, 32);
+ empty.fill(QColor(0, 0, 0, 0));
+ return QIcon(empty);
+}
InstanceManagerDialog::~InstanceManagerDialog() = default;
@@ -352,7 +79,7 @@ void InstanceManagerDialog::updateInstances()
m_instances.clear();
for (auto&& d : m.globalInstancePaths()) {
- m_instances.push_back(std::make_unique<InstanceInfo>(d, false));
+ m_instances.push_back(std::make_unique<Instance>(d, false));
}
// sort first, prepend portable after so it's always on top
@@ -363,7 +90,12 @@ void InstanceManagerDialog::updateInstances()
if (m.portableInstanceExists()) {
m_instances.insert(
m_instances.begin(),
- std::make_unique<InstanceInfo>(m.portablePath(), true));
+ std::make_unique<Instance>(m.portablePath(), true));
+ }
+
+ // read all inis, ignore errors
+ for (auto&& i : m_instances) {
+ i->readFromIni();
}
}
@@ -381,7 +113,7 @@ void InstanceManagerDialog::updateList()
const auto& ii = *m_instances[i];
auto* item = new QStandardItem(ii.name());
- item->setIcon(ii.icon(m_pc));
+ item->setIcon(instanceIcon(m_pc, ii));
m_model->appendRow(item);
@@ -568,9 +300,9 @@ void InstanceManagerDialog::rename()
return;
}
- const QString src = i->location();
+ const QString src = i->directory();
const QString dest = QDir::toNativeSeparators(
- QFileInfo(i->location()).dir().path() + "/" + newName);
+ QFileInfo(src).dir().path() + "/" + newName);
const auto r = shell::Rename(src, dest, false);
if (!r) {
@@ -582,15 +314,19 @@ void InstanceManagerDialog::rename()
return;
}
+ auto newInstance = std::make_unique<Instance>(dest, false);
+ i = newInstance.get();
+
m_model->item(selIndex)->setText(newName);
- i->setDir(dest);
+ m_instances[selIndex] = std::move(newInstance);
+
fillData(*i);
}
void InstanceManagerDialog::exploreLocation()
{
if (const auto* i=singleSelection()) {
- shell::Explore(i->location());
+ shell::Explore(i->directory());
}
}
@@ -604,14 +340,14 @@ void InstanceManagerDialog::exploreBaseDirectory()
void InstanceManagerDialog::exploreGame()
{
if (const auto* i=singleSelection()) {
- shell::Explore(i->gamePath());
+ shell::Explore(i->gameDirectory());
}
}
void InstanceManagerDialog::openINI()
{
if (const auto* i=singleSelection()) {
- shell::Open(i->iniFile());
+ shell::Open(i->iniPath());
}
}
@@ -707,6 +443,15 @@ void InstanceManagerDialog::setRestartOnSelect(bool b)
bool InstanceManagerDialog::doDelete(const QStringList& files, bool recycle)
{
+ // logging
+ for (auto&& f : files) {
+ if (recycle) {
+ log::info("will recycle {}", f);
+ } else {
+ log::info("will delete {}", f);
+ }
+ }
+
if (MOBase::shellDelete(files, recycle, this)) {
return true;
}
@@ -771,17 +516,7 @@ std::size_t InstanceManagerDialog::singleSelectionIndex() const
return static_cast<std::size_t>(sel.indexes()[0].row());
}
-InstanceInfo* InstanceManagerDialog::singleSelection()
-{
- const auto i = singleSelectionIndex();
- if (i == NoSelection) {
- return nullptr;
- }
-
- return m_instances[i].get();
-}
-
-const InstanceInfo* InstanceManagerDialog::singleSelection() const
+const Instance* InstanceManagerDialog::singleSelection() const
{
const auto i = singleSelectionIndex();
if (i == NoSelection) {
@@ -791,13 +526,13 @@ const InstanceInfo* InstanceManagerDialog::singleSelection() const
return m_instances[i].get();
}
-void InstanceManagerDialog::fillData(const InstanceInfo& ii)
+void InstanceManagerDialog::fillData(const Instance& ii)
{
ui->name->setText(ii.name());
- ui->location->setText(ii.location());
+ ui->location->setText(ii.directory());
ui->baseDirectory->setText(ii.baseDirectory());
ui->gameName->setText(ii.gameName());
- ui->gameDir->setText(ii.gamePath());
+ ui->gameDir->setText(ii.gameDirectory());
setButtonsEnabled(true);
const auto& m = InstanceManager::singleton();
diff --git a/src/instancemanagerdialog.h b/src/instancemanagerdialog.h
index 5b08ffc2..94f379ca 100644
--- a/src/instancemanagerdialog.h
+++ b/src/instancemanagerdialog.h
@@ -6,9 +6,11 @@
namespace Ui { class InstanceManagerDialog; };
-class InstanceInfo;
+class Instance;
class PluginContainer;
+// a dialog to manage existing instances
+//
class InstanceManagerDialog : public QDialog
{
Q_OBJECT
@@ -19,21 +21,61 @@ public:
~InstanceManagerDialog();
+ // selects the instance having the given index in the list
+ //
void select(std::size_t i);
+
+ // selects the instance by name
+ //
void select(const QString& name);
+
+ // select the instance that is currently in use in MO
+ //
void selectActiveInstance();
+
+ // switches to the selected instance; restarts MO, unless
+ // was called setRestartOnSelect(false)
+ //
void openSelectedInstance();
+
+ // renames the currently selected instance
+ //
void rename();
+
+ // explores the directory of the selected instance
+ //
void exploreLocation();
+
+ // explores the base directory of the selected instance
+ //
void exploreBaseDirectory();
+
+ // explores the game directory of the selected instance
+ //
void exploreGame();
+
+ // converts the selected, portable instance to a global one; not implemented
+ //
void convertToGlobal();
+
+ // converts the selected, global instance to a portable one; not implemented
+ //
void convertToPortable();
+
+ // opens the ini of the selected instance in the shell
+ //
void openINI();
+
+ // deletes the selected instance
+ //
void deleteInstance();
+
+ // sets whether the dialog should restart MO when selecting an instance; this
+ // is false on startup when no instances exist
+ //
void setRestartOnSelect(bool b);
private:
@@ -41,27 +83,51 @@ private:
std::unique_ptr<Ui::InstanceManagerDialog> ui;
const PluginContainer& m_pc;
- std::vector<std::unique_ptr<InstanceInfo>> m_instances;
+ std::vector<std::unique_ptr<Instance>> m_instances;
MOBase::FilterWidget m_filter;
QStandardItemModel* m_model;
bool m_restartOnSelect;
+ // refreshes the list instances from disk
+ //
void updateInstances();
+ // updates the ui for the selected instance
+ //
void onSelection();
+
+ // opens the create instance dialog
+ //
void createNew();
+
+ // returns the index of selected instance, NoSelection if none
+ //
std::size_t singleSelectionIndex() const;
- InstanceInfo* singleSelection();
- const InstanceInfo* singleSelection() const;
+ // returns the InstanceInfo associated with the selected instance, null if
+ // none
+ //
+ const Instance* singleSelection() const;
+
+ // fills the instance list on the ui
+ //
void updateList();
- void fillData(const InstanceInfo& ii);
+
+ // fills the ui for the selected instance
+ //
+ void fillData(const Instance& ii);
+
+ // clears the ui when there's no selection
+ //
void clearData();
+
+ // enables/disables buttons like rename, explore...
+ //
void setButtonsEnabled(bool b);
- bool deletePortable(const InstanceInfo& ii);
- bool deleteGlobal(const InstanceInfo& ii);
+ // deletes the given files, returns false on error
+ //
bool doDelete(const QStringList& files, bool recycle);
};
diff --git a/src/instancemanagerdialog.ui b/src/instancemanagerdialog.ui
index 410b58c1..45b99e21 100644
--- a/src/instancemanagerdialog.ui
+++ b/src/instancemanagerdialog.ui
@@ -330,7 +330,7 @@
<item>
<widget class="QPushButton" name="deleteInstance">
<property name="text">
- <string>Delete instance</string>
+ <string>Delete instance...</string>
</property>
<property name="icon">
<iconset resource="resources.qrc">
diff --git a/src/main.cpp b/src/main.cpp
index 7f0886f6..a2653685 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -662,17 +662,17 @@ int doOneRun(
}
else
{
- if (!currentInstance->directory().exists()) {
+ if (!QDir(currentInstance->directory()).exists()) {
// the previously used instance doesn't exist anymore
if (m.hasAnyInstances()) {
criticalOnTop(QObject::tr(
"Instance at '%1' not found. Select another instance.")
- .arg(currentInstance->directory().absolutePath()));
+ .arg(currentInstance->directory()));
} else {
criticalOnTop(QObject::tr(
"Instance at '%1' not found. You must create a new instance")
- .arg(currentInstance->directory().absolutePath()));
+ .arg(currentInstance->directory()));
}
currentInstance = selectInstance();
@@ -682,7 +682,7 @@ int doOneRun(
}
}
- const QString dataPath = currentInstance->directory().path();
+ const QString dataPath = currentInstance->directory();
application.setProperty("dataPath", dataPath);
setExceptionHandlers();