/*
Copyright (C) 2012 Sebastian Herbord. All rights reserved.
This file is part of Mod Organizer.
Mod Organizer is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Mod Organizer 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.
You should have received a copy of the GNU General Public License
along with Mod Organizer. If not, see .
*/
#ifndef PROFILE_H
#define PROFILE_H
#include "executableinfo.h"
#include "modinfo.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace MOBase
{
class IPluginGame;
}
class GameFeatures;
/**
* @brief represents a profile
**/
class Profile : public QObject, public MOBase::IProfile
{
Q_OBJECT
public:
using Ptr = boost::shared_ptr;
public:
// the minimum and maximum priority achievable by mods
//
static constexpr int MinimumPriority = 0;
static constexpr int MaximumPriority = std::numeric_limits::max();
public:
/**
* @brief constructor
*
* This constructor is used to create a new profile so it is to be assumed a profile
* by this name does not yet exist
* @param name name of the new profile
* @param filter save game filter. Defaults to <no filter>.
**/
Profile(const QString& name, MOBase::IPluginGame const* gamePlugin,
GameFeatures const& features, bool useDefaultSettings);
/**
* @brief constructor
*
* This constructor is used to open an existing profile though it will also try to
*repair the profile if important files are missing (including the directory itself)
*so technically, invoking this should always produce a working profile
* @param directory directory to read the profile from
**/
Profile(const QDir& directory, MOBase::IPluginGame const* gamePlugin,
GameFeatures const& features);
Profile(const Profile& reference);
~Profile();
/**
* Determines the default settings for the profile based on the current state of the
*profile's files. This function should remain backwards compatible as much as
*possible.
**/
void findProfileSettings(void);
/**
* @return true if this profile (still) exists on disc
*/
bool exists() const;
/**
* @param name of the new profile
* @param reference profile to copy from
**/
static Profile* createPtrFrom(const QString& name, const Profile& reference,
MOBase::IPluginGame const* gamePlugin);
static void renameModInAllProfiles(const QString& oldName, const QString& newName);
void writeModlist();
void writeModlistNow(bool onlyIfPending = false);
void cancelModlistWrite();
/**
* @brief test if this profile uses archive invalidation
*
* @param supported if this is not null, the parameter will be set to false if
*invalidation is not supported in this profile
* @return true if archive invalidation is active
* @note currently, invalidation is not supported if the relevant entry in the ini
*file does not exist
**/
bool invalidationActive(bool* supported) const;
/**
* @brief deactivate archive invalidation if it was active
**/
void deactivateInvalidation();
/**
* @brief activate archive invalidation
**/
void activateInvalidation();
/**
* @return true if this profile uses local save games
*/
virtual bool localSavesEnabled() const override;
/**
* @brief enables or disables the use of local save games for this profile
* when disabling the user will be asked if he wants to remove the save games
* in the profile
* @param enable if true, local saves are enabled, otherewise they are disabled
*/
bool enableLocalSaves(bool enable);
/**
* @return true if this profile uses local ini files
*/
virtual bool localSettingsEnabled() const override;
/**
* @brief enables or disables the use of local ini files for this profile
* disabling this does not delete existing ini files but the global ones will be used
* @param enable
*/
bool enableLocalSettings(bool enable);
/**
* @return name of the profile (this is identical to its directory name)
**/
virtual QString name() const override { return m_Directory.dirName(); }
/**
* @return the path of the plugins file in this profile
* @todo is this required? can the functionality using this function be moved to the
*Profile-class?
**/
QString getPluginsFileName() const;
/**
* @return the path of the loadorder file in this profile
**/
QString getLoadOrderFileName() const;
/**
* @return the path of the file containing locked mod indices
*/
QString getLockedOrderFileName() const;
/**
* @return the path of the modlist file in this profile
*/
QString getModlistFileName() const;
/**
* @return path of the archives file in this profile
*/
QString getArchivesFileName() const;
/**
* @return the path of the ini file in this profile
* @todo since the game can contain multiple ini files (i.e. skyrim.ini
*skyrimprefs.ini) the concept of this function is somewhat broken
**/
QString getIniFileName() const;
/**
* @brief Retrieve the absolute file to the corresponding file.
*
* @param iniFile INI file to retrieve a path for. This can either be the
* name of a file or a path to the absolute file outside of the profile.
*
* @return the absolute path for the given INI file for this profile.
*/
QString absoluteIniFilePath(QString iniFile) const override;
/**
* @return the path of the tweak ini in this profile
*/
QString getProfileTweaks() const;
/**
* @return path to this profile
**/
virtual QString absolutePath() const override;
/**
* @return path to this profile's save games
**/
QString savePath() const;
/**
* @brief rename profile
* @param newName new name of profile
*/
void rename(const QString& newName);
/**
* @brief create the ini file to be used by the game
*
* the tweaked ini file constructed by this file is a merger
* of the game-ini of this profile with ini tweaks applied */
void createTweakedIniFile();
/**
* @brief re-read the modlist.txt and update the mod status from it
**/
void refreshModStatus();
/**
* @brief retrieve a list of mods that are enabled in this profile
*
* @return list of active mods sorted by priority (ascending). "first" is the mod
*name, "second" is its path
**/
std::vector> getActiveMods();
/**
* @brief retrieve a mod of the indexes ordered by priority
*
* @return map of indexes by priority
**/
const std::map& getAllIndexesByPriority()
{
return m_ModIndexByPriority;
}
/**
* retrieve the number of mods for which this object has status information.
* This is usually the same as ModInfo::getNumMods() except between
* calls to ModInfo::updateFromDisc() and the Profile::refreshModStatus()
*
* @return number of mods for which the profile has status information
**/
size_t numMods() const { return m_ModStatus.size(); }
/**
* @brief enable or disable a mod
*
* @param index index of the mod to enable/disable
* @param enabled true if the mod is to be enabled, false if it is to be disabled
**/
void setModEnabled(unsigned int index, bool enabled);
/**
* @brief enable or disable multiple mods at once
* This is an abbreviated process and should be immediately followed by a full refresh
* to maintain data consistency.
*
* @param modsToEnable list of mod indicies to enable
* @param modsToDisable list of mod indicies to disable
**/
void setModsEnabled(const QList& modsToEnable,
const QList& modsToDisable);
// set the priority of a mod, and the priority of other mods in the range
// [old priority, new priority] such that no gaps are possible
//
// the priority is clamped in the range of valid priority (>= 0, and lower than
// the number of "regular" mods), you should use MinimumPriority or MaximumPriority
// to send a mod to the "top" or "bottom" of the priority list
//
// the function returns true if the priority was changed, or false if the mod
// was already at the given priority (or if the priority of the mod cannot be
// set)
//
bool setModPriority(unsigned int index, int& newPriority);
/**
* @brief determine if a mod is enabled
*
* @param index index of the mod to look up
* @return true if the mod is enabled, false otherwise
**/
bool modEnabled(unsigned int index) const;
/**
* @brief query the priority of a mod
*
* @param index index of the mod to look up
* @return priority of the specified mod
**/
int getModPriority(unsigned int index) const;
void dumpModStatus() const;
QVariant setting(const QString& section, const QString& name,
const QVariant& fallback = {}) const;
void storeSetting(const QString& section, const QString& name,
const QVariant& value = {});
void removeSetting(const QString& section, const QString& name);
QVariantMap settingsByGroup(const QString& section) const;
void storeSettingsByGroup(const QString& section, const QVariantMap& values);
QList settingsByArray(const QString& prefix) const;
void storeSettingsByArray(const QString& prefix, const QList& values);
bool forcedLibrariesEnabled(const QString& executable) const;
void setForcedLibrariesEnabled(const QString& executable, bool enabled);
QList
determineForcedLibraries(const QString& executable) const;
void storeForcedLibraries(const QString& executable,
const QList& values);
void removeForcedLibraries(const QString& executable);
void debugDump() const;
Profile& operator=(const Profile& reference) = delete;
signals:
/**
* @brief emitted whenever the status (enabled/disabled) of a mod changed
*
* @param index index of the mod that changed
**/
void modStatusChanged(unsigned int index);
/**
* @brief emitted whenever the status (enabled/disabled) of multiple mods change
*
* @param index list of indices of the mods that changed
**/
void modStatusChanged(QList index);
protected slots:
// should only be called by DelayedFileWriter, use writeModlist() and
// writeModlistNow() instead
void doWriteModlist();
private:
class ModStatus
{
friend class Profile;
public:
ModStatus() : m_Enabled(false), m_Priority(-1) {}
private:
bool m_Enabled;
int m_Priority;
};
private:
void updateIndices();
void copyFilesTo(QString& target) const;
std::vector splitDZString(const wchar_t* buffer) const;
void mergeTweak(const QString& tweakName, const QString& tweakedIni) const;
void mergeTweaks(ModInfo::Ptr modInfo, const QString& tweakedIni) const;
void touchFile(QString fileName);
static void renameModInList(QFile& modList, const QString& oldName,
const QString& newName);
private:
QDir m_Directory;
QSettings* m_Settings;
const GameFeatures& m_GameFeatures;
const MOBase::IPluginGame* m_GamePlugin;
std::vector m_ModStatus;
std::map m_ModIndexByPriority;
// "regular" here means mods with modifiable priority (i.e. not backups
// or overwrite)
std::size_t m_NumRegularMods;
MOBase::DelayedFileWriter m_ModListWriter;
};
#endif // PROFILE_H