diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/editexecutablesdialog.cpp | 57 | ||||
| -rw-r--r-- | src/editexecutablesdialog.h | 21 | ||||
| -rw-r--r-- | src/editexecutablesdialog.ui | 45 | ||||
| -rw-r--r-- | src/mainwindow.cpp | 55 | ||||
| -rw-r--r-- | src/mainwindow.h | 1 | ||||
| -rw-r--r-- | src/organizercore.cpp | 85 | ||||
| -rw-r--r-- | src/organizercore.h | 20 | ||||
| -rw-r--r-- | src/usvfsconnector.cpp | 1 |
9 files changed, 235 insertions, 52 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a8b43c59..c6c038e8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -84,6 +84,7 @@ SET(organizer_SRCS organizercore.cpp instancemanager.cpp usvfsconnector.cpp + eventfilter.cpp shared/inject.cpp shared/windows_error.cpp @@ -170,6 +171,7 @@ SET(organizer_HDRS iuserinterface.h instancemanager.h usvfsconnector.h + eventfilter.h shared/inject.h shared/windows_error.h diff --git a/src/editexecutablesdialog.cpp b/src/editexecutablesdialog.cpp index 05a7603d..42d6f58b 100644 --- a/src/editexecutablesdialog.cpp +++ b/src/editexecutablesdialog.cpp @@ -29,15 +29,20 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. using namespace MOBase; using namespace MOShared; -EditExecutablesDialog::EditExecutablesDialog(const ExecutablesList &executablesList, QWidget *parent) +EditExecutablesDialog::EditExecutablesDialog( + const ExecutablesList &executablesList, const ModList &modList, + Profile *profile, QWidget *parent) : TutorableDialog("EditExecutables", parent) , ui(new Ui::EditExecutablesDialog) , m_CurrentItem(nullptr) , m_ExecutablesList(executablesList) + , m_Profile(profile) { ui->setupUi(this); refreshExecutablesWidget(); + + ui->newFilesModBox->addItems(modList.allMods()); } EditExecutablesDialog::~EditExecutablesDialog() @@ -86,23 +91,30 @@ void EditExecutablesDialog::resetInput() ui->appIDOverwriteEdit->clear(); ui->overwriteAppIDBox->setChecked(false); ui->useAppIconCheckBox->setChecked(false); + ui->newFilesModCheckBox->setChecked(false); m_CurrentItem = nullptr; } void EditExecutablesDialog::saveExecutable() { - m_ExecutablesList.updateExecutable(ui->titleEdit->text(), - QDir::fromNativeSeparators(ui->binaryEdit->text()), - ui->argumentsEdit->text(), - QDir::fromNativeSeparators(ui->workingDirEdit->text()), - ui->overwriteAppIDBox->isChecked() ? - ui->appIDOverwriteEdit->text() : "", - Executable::UseApplicationIcon | Executable::CustomExecutable, - (ui->useAppIconCheckBox->isChecked() ? - Executable::UseApplicationIcon : Executable::Flags()) - | Executable::CustomExecutable); + m_ExecutablesList.updateExecutable( + ui->titleEdit->text(), + QDir::fromNativeSeparators(ui->binaryEdit->text()), + ui->argumentsEdit->text(), + QDir::fromNativeSeparators(ui->workingDirEdit->text()), + ui->overwriteAppIDBox->isChecked() ? + ui->appIDOverwriteEdit->text() : "", + Executable::UseApplicationIcon | Executable::CustomExecutable, + (ui->useAppIconCheckBox->isChecked() ? + Executable::UseApplicationIcon : Executable::Flags()) + | Executable::CustomExecutable); + + if (ui->newFilesModCheckBox->isChecked()) { + m_Profile->storeSetting("custom_overwrites", ui->titleEdit->text(), + ui->newFilesModBox->currentText()); } +} void EditExecutablesDialog::delayedRefresh() @@ -212,8 +224,13 @@ bool EditExecutablesDialog::executableChanged() { if (m_CurrentItem != nullptr) { Executable const &selectedExecutable(m_ExecutablesList.find(m_CurrentItem->text())); + + QString storedCustomOverwrite = m_Profile->setting("custom_overwrites", selectedExecutable.m_Title).toString(); + return selectedExecutable.m_Arguments != ui->argumentsEdit->text() || selectedExecutable.m_SteamAppID != ui->appIDOverwriteEdit->text() + || !storedCustomOverwrite.isEmpty() != ui->newFilesModCheckBox->isChecked() + || !storedCustomOverwrite.isEmpty() && (storedCustomOverwrite != ui->newFilesModBox->currentText()) || selectedExecutable.m_WorkingDirectory != QDir::fromNativeSeparators(ui->workingDirEdit->text()) || selectedExecutable.m_BinaryInfo.absoluteFilePath() != QDir::fromNativeSeparators(ui->binaryEdit->text()) || selectedExecutable.usesOwnIcon() != ui->useAppIconCheckBox->isChecked(); @@ -296,5 +313,23 @@ void EditExecutablesDialog::on_executablesListBox_clicked(const QModelIndex &cur ui->appIDOverwriteEdit->clear(); } ui->useAppIconCheckBox->setChecked(selectedExecutable.usesOwnIcon()); + + int index = -1; + + QString customOverwrite = m_Profile->setting("custom_overwrites", selectedExecutable.m_Title).toString(); + if (!customOverwrite.isEmpty()) { + index = ui->newFilesModBox->findText(customOverwrite); + qDebug("find %s -> %d", qPrintable(customOverwrite), index); + } + + ui->newFilesModCheckBox->setChecked(index != -1); + if (index != -1) { + ui->newFilesModBox->setCurrentIndex(index); + } } } + +void EditExecutablesDialog::on_newFilesModCheckBox_toggled(bool checked) +{ + ui->newFilesModBox->setEnabled(checked); +} diff --git a/src/editexecutablesdialog.h b/src/editexecutablesdialog.h index 4f6c5315..0f3dbaff 100644 --- a/src/editexecutablesdialog.h +++ b/src/editexecutablesdialog.h @@ -24,11 +24,16 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QListWidgetItem>
#include <QTimer>
#include "executableslist.h"
+#include "profile.h"
namespace Ui {
class EditExecutablesDialog;
}
+
+class ModList;
+
+
/**
* @brief Dialog to manage the list of executables
**/
@@ -44,7 +49,10 @@ public: * @param executablesList current list of executables
* @param parent parent widget
**/
- explicit EditExecutablesDialog(const ExecutablesList &executablesList, QWidget *parent = 0);
+ explicit EditExecutablesDialog(const ExecutablesList &executablesList,
+ const ModList &modList,
+ Profile *profile,
+ QWidget *parent = 0);
~EditExecutablesDialog();
@@ -56,6 +64,10 @@ public: ExecutablesList getExecutablesList() const;
void saveExecutable();
+
+private slots:
+ void on_newFilesModCheckBox_toggled(bool checked);
+
private slots:
void on_binaryEdit_textChanged(const QString &arg1);
@@ -89,12 +101,13 @@ private: bool executableChanged();
private:
- Ui::EditExecutablesDialog *ui;
+ Ui::EditExecutablesDialog *ui;
- QListWidgetItem *m_CurrentItem;
+ QListWidgetItem *m_CurrentItem;
- ExecutablesList m_ExecutablesList;
+ ExecutablesList m_ExecutablesList;
+ Profile *m_Profile;
};
#endif // EDITEXECUTABLESDIALOG_H
diff --git a/src/editexecutablesdialog.ui b/src/editexecutablesdialog.ui index 2640bb15..b3543c95 100644 --- a/src/editexecutablesdialog.ui +++ b/src/editexecutablesdialog.ui @@ -165,6 +165,27 @@ Right now the only case I know of where this needs to be overwritten is for the </layout>
</item>
<item>
+ <layout class="QHBoxLayout" name="horizontalLayout_9" stretch="0,1">
+ <item>
+ <widget class="QCheckBox" name="newFilesModCheckBox">
+ <property name="toolTip">
+ <string>If this is enabled, new files are created in the specified mod instead of the "Overwrite" mod.</string>
+ </property>
+ <property name="text">
+ <string>Create Files in Mod instead of Overwrite (*)</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="newFilesModBox">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
<widget class="QCheckBox" name="useAppIconCheckBox">
<property name="text">
<string>Use Application's Icon for shortcuts</string>
@@ -172,6 +193,13 @@ Right now the only case I know of where this needs to be overwritten is for the </widget>
</item>
<item>
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>(*) This setting is profile-specific</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="addButton">
@@ -235,6 +263,23 @@ Right now the only case I know of where this needs to be overwritten is for the </item>
</layout>
</widget>
+ <tabstops>
+ <tabstop>executablesListBox</tabstop>
+ <tabstop>titleEdit</tabstop>
+ <tabstop>binaryEdit</tabstop>
+ <tabstop>browseButton</tabstop>
+ <tabstop>workingDirEdit</tabstop>
+ <tabstop>browseDirButton</tabstop>
+ <tabstop>argumentsEdit</tabstop>
+ <tabstop>overwriteAppIDBox</tabstop>
+ <tabstop>appIDOverwriteEdit</tabstop>
+ <tabstop>newFilesModCheckBox</tabstop>
+ <tabstop>newFilesModBox</tabstop>
+ <tabstop>useAppIconCheckBox</tabstop>
+ <tabstop>addButton</tabstop>
+ <tabstop>removeButton</tabstop>
+ <tabstop>closeButton</tabstop>
+ </tabstops>
<resources/>
<connections/>
</ui>
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index e174a17c..7944acfc 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1004,13 +1004,8 @@ void MainWindow::startExeAction() {
QAction *action = qobject_cast<QAction*>(sender());
if (action != nullptr) {
- const Executable &selectedExecutable(m_OrganizerCore.executablesList()->find(action->text()));
m_OrganizerCore.spawnBinary(
- selectedExecutable.m_BinaryInfo,
- selectedExecutable.m_Arguments,
- selectedExecutable.m_WorkingDirectory.length() != 0 ? selectedExecutable.m_WorkingDirectory
- : selectedExecutable.m_BinaryInfo.absolutePath(),
- selectedExecutable.m_SteamAppID);
+ m_OrganizerCore.executablesList()->find(action->text()));
} else {
qCritical("not an action?");
}
@@ -1516,14 +1511,7 @@ void MainWindow::installMod(QString fileName) void MainWindow::on_startButton_clicked()
{
- const Executable &selectedExecutable(getSelectedExecutable());
-
- m_OrganizerCore.spawnBinary(
- selectedExecutable.m_BinaryInfo,
- selectedExecutable.m_Arguments,
- selectedExecutable.m_WorkingDirectory.length() != 0 ? selectedExecutable.m_WorkingDirectory
- : selectedExecutable.m_BinaryInfo.absolutePath(),
- selectedExecutable.m_SteamAppID);
+ m_OrganizerCore.spawnBinary(getSelectedExecutable());
}
@@ -1613,7 +1601,9 @@ bool MainWindow::modifyExecutablesDialog() {
bool result = false;
try {
- EditExecutablesDialog dialog(*m_OrganizerCore.executablesList());
+ EditExecutablesDialog dialog(*m_OrganizerCore.executablesList(),
+ *m_OrganizerCore.modList(),
+ m_OrganizerCore.currentProfile());
if (dialog.exec() == QDialog::Accepted) {
m_OrganizerCore.setExecutablesList(dialog.getExecutablesList());
result = true;
@@ -2423,7 +2413,32 @@ void MainWindow::information_clicked() }
}
+void MainWindow::createEmptyMod_clicked()
+{
+ GuessedValue<QString> name;
+ name.setFilter(&fixDirectoryName);
+
+ while (name->isEmpty()) {
+ bool ok;
+ name.update(QInputDialog::getText(this, tr("Create Mod..."),
+ tr("This will create an empty mod.\n"
+ "Please enter a name:"), QLineEdit::Normal, "", &ok),
+ GUESS_USER);
+ if (!ok) {
+ return;
+ }
+ }
+
+ if (m_OrganizerCore.getMod(name) != nullptr) {
+ reportError(tr("A mod with this name already exists"));
+ return;
+ }
+ IModInterface *newMod = m_OrganizerCore.createMod(name);
+ if (newMod == nullptr) {
+ return;
+ }
+}
void MainWindow::createModFromOverwrite()
{
@@ -2862,6 +2877,8 @@ QMenu *MainWindow::modListContextMenu() QMenu *menu = new QMenu(this);
menu->addAction(tr("Install Mod..."), this, SLOT(installMod_clicked()));
+ menu->addAction(tr("Create empty mod"), this, SLOT(createEmptyMod_clicked()));
+
menu->addAction(tr("Enable all visible"), this, SLOT(enableVisibleMods()));
menu->addAction(tr("Disable all visible"), this, SLOT(disableVisibleMods()));
@@ -3529,10 +3546,14 @@ void MainWindow::openDataFile() QString arguments;
switch (getBinaryExecuteInfo(targetInfo, binaryInfo, arguments)) {
case 1: {
- m_OrganizerCore.spawnBinaryDirect(binaryInfo, arguments, m_OrganizerCore.currentProfile()->name(), targetInfo.absolutePath(), "");
+ m_OrganizerCore.spawnBinaryDirect(
+ binaryInfo, arguments, m_OrganizerCore.currentProfile()->name(),
+ targetInfo.absolutePath(), "", "");
} break;
case 2: {
- ::ShellExecuteW(nullptr, L"open", ToWString(targetInfo.absoluteFilePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ ::ShellExecuteW(nullptr, L"open",
+ ToWString(targetInfo.absoluteFilePath()).c_str(),
+ nullptr, nullptr, SW_SHOWNORMAL);
} break;
default: {
// nop
diff --git a/src/mainwindow.h b/src/mainwindow.h index 4e2e8e21..d2f3fb47 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -369,6 +369,7 @@ private slots: // modlist context menu
void installMod_clicked();
+ void createEmptyMod_clicked();
void restoreBackup_clicked();
void renameMod_clicked();
void removeMod_clicked();
diff --git a/src/organizercore.cpp b/src/organizercore.cpp index b1eaaef3..8f308c88 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -596,7 +596,7 @@ void OrganizerCore::createDefaultProfile() void OrganizerCore::prepareVFS()
{
- m_USVFS.updateMapping(fileMapping());
+ m_USVFS.updateMapping(fileMapping(m_CurrentProfile->name(), QString()));
}
void OrganizerCore::setCurrentProfile(const QString &profileName)
@@ -969,10 +969,21 @@ QStringList OrganizerCore::modsSortedByProfilePriority() const return res;
}
+void OrganizerCore::spawnBinary(const Executable &exe)
+{
+ spawnBinary(
+ exe.m_BinaryInfo, exe.m_Arguments,
+ exe.m_WorkingDirectory.length() != 0 ? exe.m_WorkingDirectory
+ : exe.m_BinaryInfo.absolutePath(),
+ exe.m_SteamAppID,
+ m_CurrentProfile->setting("custom_overwrites", exe.m_Title).toString());
+}
+
void OrganizerCore::spawnBinary(const QFileInfo &binary,
const QString &arguments,
const QDir ¤tDirectory,
- const QString &steamAppID)
+ const QString &steamAppID,
+ const QString &customOverwrite)
{
LockedDialog *dialog = new LockedDialog(qApp->activeWindow());
dialog->show();
@@ -983,7 +994,7 @@ void OrganizerCore::spawnBinary(const QFileInfo &binary, HANDLE processHandle
= spawnBinaryDirect(binary, arguments, m_CurrentProfile->name(),
- currentDirectory, steamAppID);
+ currentDirectory, steamAppID, customOverwrite);
if (processHandle != INVALID_HANDLE_VALUE) {
if (m_UserInterface != nullptr) {
m_UserInterface->setWindowEnabled(false);
@@ -1082,7 +1093,8 @@ HANDLE OrganizerCore::spawnBinaryDirect(const QFileInfo &binary, const QString &arguments,
const QString &profileName,
const QDir ¤tDirectory,
- const QString &steamAppID)
+ const QString &steamAppID,
+ const QString &customOverwrite)
{
prepareStart();
@@ -1135,11 +1147,16 @@ HANDLE OrganizerCore::spawnBinaryDirect(const QFileInfo &binary, }
if (m_AboutToRun(binary.absoluteFilePath())) {
- m_USVFS.updateMapping(fileMapping());
+ try {
+ m_USVFS.updateMapping(fileMapping(profileName, customOverwrite));
+ } catch (const std::exception &e) {
+ QMessageBox::warning(qApp->activeWindow(), tr("Error"), e.what());
+ return INVALID_HANDLE_VALUE;
+ }
+
QString modsPath = settings().getModDirectory();
QString binPath = binary.absoluteFilePath();
-
if (binPath.startsWith(modsPath, Qt::CaseInsensitive)) {
// binary was installed as a MO mod. Need to start it through a (hooked)
// proxy to ensure pathes are correct
@@ -1185,6 +1202,7 @@ HANDLE OrganizerCore::startApplication(const QString &executable, }
}
QString steamAppID;
+ QString customOverwrite;
if (executable.contains('\\') || executable.contains('/')) {
// file path
@@ -1200,6 +1218,9 @@ HANDLE OrganizerCore::startApplication(const QString &executable, try {
const Executable &exe = m_ExecutablesList.findByBinary(binary);
steamAppID = exe.m_SteamAppID;
+ customOverwrite
+ = m_CurrentProfile->setting("custom_overwrites", exe.m_Title)
+ .toString();
} catch (const std::runtime_error &) {
// nop
}
@@ -1208,6 +1229,9 @@ HANDLE OrganizerCore::startApplication(const QString &executable, try {
const Executable &exe = m_ExecutablesList.find(executable);
steamAppID = exe.m_SteamAppID;
+ customOverwrite
+ = m_CurrentProfile->setting("custom_overwrites", exe.m_Title)
+ .toString();
if (arguments == "") {
arguments = exe.m_Arguments;
}
@@ -1223,7 +1247,7 @@ HANDLE OrganizerCore::startApplication(const QString &executable, }
return spawnBinaryDirect(binary, arguments, profileName, currentDirectory,
- steamAppID);
+ steamAppID, customOverwrite);
}
bool OrganizerCore::waitForApplication(HANDLE handle, LPDWORD exitCode)
@@ -1781,7 +1805,8 @@ void OrganizerCore::prepareStart() storeSettings();
}
-std::vector<Mapping> OrganizerCore::fileMapping()
+std::vector<Mapping> OrganizerCore::fileMapping(const QString &profileName,
+ const QString &customOverwrite)
{
// need to wait until directory structure
while (m_DirectoryUpdate) {
@@ -1789,12 +1814,39 @@ std::vector<Mapping> OrganizerCore::fileMapping() QCoreApplication::processEvents();
}
- int overwriteId = m_DirectoryStructure->getOriginByName(L"Overwrite").getID();
-
IPluginGame *game = qApp->property("managed_game").value<IPluginGame *>();
- MappingType result = fileMapping(
- QDir::toNativeSeparators(game->dataDirectory().absolutePath()), "\\",
- directoryStructure(), directoryStructure(), overwriteId);
+ Profile profile(QDir(m_Settings.getProfileDirectory() + "/" + profileName),
+ game);
+
+ MappingType result;
+
+ QString dataPath
+ = QDir::toNativeSeparators(game->dataDirectory().absolutePath());
+
+ bool overwriteActive = false;
+
+ for (auto mod : profile.getActiveMods()) {
+ if (std::get<0>(mod).compare("overwrite", Qt::CaseInsensitive) == 0) {
+ continue;
+ }
+
+ unsigned int modIndex = ModInfo::getIndex(std::get<0>(mod));
+ ModInfo::Ptr modPtr = ModInfo::getByIndex(modIndex);
+
+ bool createTarget = customOverwrite == std::get<0>(mod);
+
+ overwriteActive |= createTarget;
+
+ if (modPtr->isRegular()) {
+ result.insert(result.end(), {QDir::toNativeSeparators(std::get<1>(mod)),
+ dataPath, true, createTarget});
+ }
+ }
+
+ if (!overwriteActive && !customOverwrite.isEmpty()) {
+ throw MyException(tr("The designated write target \"%1\" is not enabled.")
+ .arg(customOverwrite));
+ }
if (m_CurrentProfile->localSavesEnabled()) {
LocalSavegames *localSaves = game->feature<LocalSavegames>();
@@ -1808,6 +1860,13 @@ std::vector<Mapping> OrganizerCore::fileMapping() }
}
+ result.insert(result.end(), {
+ QDir::toNativeSeparators(m_Settings.getOverwriteDirectory()),
+ QDir::toNativeSeparators(game->dataDirectory().absolutePath()),
+ true,
+ customOverwrite.isEmpty()
+ });
+
for (MOBase::IPluginFileMapper *mapper :
m_PluginContainer->plugins<MOBase::IPluginFileMapper>()) {
IPlugin *plugin = dynamic_cast<IPlugin *>(mapper);
diff --git a/src/organizercore.h b/src/organizercore.h index ea37d72c..cd7af1b8 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -129,8 +129,8 @@ public: void doAfterLogin(const std::function<void()> &function) { m_PostLoginTasks.append(function); }
- void spawnBinary(const QFileInfo &binary, const QString &arguments = "", const QDir ¤tDirectory = QDir(), const QString &steamAppID = "");
- HANDLE spawnBinaryDirect(const QFileInfo &binary, const QString &arguments, const QString &profileName, const QDir ¤tDirectory, const QString &steamAppID);
+ void spawnBinary(const Executable &exe);
+ HANDLE spawnBinaryDirect(const QFileInfo &binary, const QString &arguments, const QString &profileName, const QDir ¤tDirectory, const QString &steamAppID, const QString &customOverwrite);
void loginSuccessfulUpdate(bool necessary);
void loginFailedUpdate(const QString &message);
@@ -173,11 +173,6 @@ public: void refreshModList(bool saveChanges = true);
QStringList modsSortedByProfilePriority() const;
- /**
- * @brief return a descriptor of the mappings real file->virtual file
- */
- std::vector<Mapping> fileMapping();
-
public: // IPluginDiagnose interface
virtual std::vector<unsigned int> activeProblems() const;
@@ -231,12 +226,23 @@ private: bool testForSteam();
+ /**
+ * @brief return a descriptor of the mappings real file->virtual file
+ */
+ std::vector<Mapping> fileMapping(const QString &profile,
+ const QString &customOverwrite);
+
std::vector<Mapping>
fileMapping(const QString &dataPath, const QString &relPath,
const MOShared::DirectoryEntry *base,
const MOShared::DirectoryEntry *directoryEntry,
int createDestination);
+ void spawnBinary(const QFileInfo &binary, const QString &arguments = "",
+ const QDir ¤tDirectory = QDir(),
+ const QString &steamAppID = "",
+ const QString &customOverwrite = "");
+
private slots:
void directory_refreshed();
diff --git a/src/usvfsconnector.cpp b/src/usvfsconnector.cpp index bc818685..2af28522 100644 --- a/src/usvfsconnector.cpp +++ b/src/usvfsconnector.cpp @@ -136,6 +136,7 @@ UsvfsConnector::~UsvfsConnector() m_WorkerThread.wait(); } + void UsvfsConnector::updateMapping(const MappingType &mapping) { QProgressDialog progress; |
