From b2f3d8e47c2580db5d0b68e61bc37556b9df63a3 Mon Sep 17 00:00:00 2001 From: Tannin Date: Fri, 1 Mar 2013 13:03:30 +0100 Subject: - rewrote the mechanism removing the Archive List limit - openfile is now rerouted - .jar files can now be added as executables directly - bugfix: no message was displayed when checking for updates with no valid credentials configured - added a readme with compilation instructions --- src/mainwindow.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'src/mainwindow.cpp') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index ac368719..4e3fa296 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -441,10 +441,12 @@ void MainWindow::createHelpWidget() typedef std::vector > ActionList; ActionList tutorials; - QDirIterator dirIter("tutorials", QStringList("*.js"), QDir::Files); + + QDirIterator dirIter(QApplication::applicationDirPath() + "/tutorials", QStringList("*.js"), QDir::Files); while (dirIter.hasNext()) { dirIter.next(); QString fileName = dirIter.fileName(); + QFile file(dirIter.filePath()); if (!file.open(QIODevice::ReadOnly)) { qCritical() << "Failed to open " << fileName; @@ -547,7 +549,7 @@ bool MainWindow::addProfile() void MainWindow::hookUpWindowTutorials() { - QDirIterator dirIter("tutorials", QStringList("*.js"), QDir::Files); + QDirIterator dirIter(QApplication::applicationDirPath() + "/tutorials", QStringList("*.js"), QDir::Files); while (dirIter.hasNext()) { dirIter.next(); QString fileName = dirIter.fileName(); @@ -2666,9 +2668,9 @@ void MainWindow::savePrimaryCategory() void MainWindow::checkModsForUpdates() { + statusBar()->show(); if (NexusInterface::instance()->getAccessManager()->loggedIn()) { m_ModsToUpdate = ModInfo::checkAllForUpdate(this); - statusBar()->show(); m_RefreshProgress->setRange(0, m_ModsToUpdate); } else { QString username, password; @@ -3298,7 +3300,7 @@ int MainWindow::getBinaryExecuteInfo(const QFileInfo &targetInfo, { // try to find java automatically WCHAR buffer[MAX_PATH]; - if (FindExecutableW(targetPathW.c_str(), NULL, buffer) > (HINSTANCE)32) { + if (::FindExecutableW(targetPathW.c_str(), NULL, buffer) > (HINSTANCE)32) { DWORD binaryType = 0UL; if (!::GetBinaryTypeW(targetPathW.c_str(), &binaryType)) { qDebug("failed to determine binary type: %lu", ::GetLastError()); @@ -3682,8 +3684,12 @@ void MainWindow::loginFailed(const QString &message) foreach (QString url, m_PendingDownloads) { downloadRequestedNXM(url); } + m_PendingDownloads.clear(); + } else { + MessageDialog::showMessage(tr("login failed: %1").arg(message), this); + m_PostLoginTasks.clear(); + statusBar()->hide(); } - m_PendingDownloads.clear(); } -- cgit v1.3.1 From b3d0fcb2083143dc21c751adafd2523c3555e5d2 Mon Sep 17 00:00:00 2001 From: Tannin Date: Wed, 13 Mar 2013 19:35:20 +0100 Subject: - some more safety checks in the ini-limit removal code - some code cleanup and minor bug fixes based on results from static code analysis - added naemfilter for the esp list - bsa changes are now stored automatically but delayed by up to 0.5 seconds (for performance reasons) - bugfix: buffer overrun when certain functions are called with empty file names - bugfix: reroute for the ini-limit fix was placed in the data segment - bugfix: mod list got mixed up when the mod directory was changed externally - bugfix: plugins.txt reroute on skyrim didn't work on winXP - bugfix: MO could become unresponsive if the tutorial script couldn't be interpreted --- src/categoriesdialog.cpp | 3 +- src/loadmechanism.cpp | 3 +- src/mainwindow.cpp | 56 +++-- src/mainwindow.h | 7 +- src/mainwindow.ui | 21 +- src/modinfo.cpp | 3 + src/modlist.cpp | 2 +- src/organizer.pro | 7 +- src/pluginlist.cpp | 2 +- src/pluginlistsortproxy.cpp | 262 ++++++++++---------- src/pluginlistsortproxy.h | 101 ++++---- src/profile.cpp | 21 +- src/profile.h | 584 ++++++++++++++++++++++---------------------- src/profilesdialog.cpp | 2 +- src/shared/skyriminfo.cpp | 12 +- src/shared/skyriminfo.h | 4 + src/shared/util.cpp | 7 + src/shared/util.h | 3 +- src/version.rc | 4 +- 19 files changed, 593 insertions(+), 511 deletions(-) (limited to 'src/mainwindow.cpp') diff --git a/src/categoriesdialog.cpp b/src/categoriesdialog.cpp index 21e1a5aa..c7f03740 100644 --- a/src/categoriesdialog.cpp +++ b/src/categoriesdialog.cpp @@ -86,7 +86,8 @@ public: { QLineEdit *edit = qobject_cast(editor); int pos = 0; - if (m_Validator->validate(edit->text(), pos) == QValidator::Acceptable) { + QString editText = edit->text(); + if (m_Validator->validate(editText, pos) == QValidator::Acceptable) { QItemDelegate::setModelData(editor, model, index); } } diff --git a/src/loadmechanism.cpp b/src/loadmechanism.cpp index 8eed460f..426b3763 100644 --- a/src/loadmechanism.cpp +++ b/src/loadmechanism.cpp @@ -169,7 +169,8 @@ void LoadMechanism::deactivateProxyDLL() } } - removeHintFile(QDir(gameDirectory)); + QDir dir(gameDirectory); + removeHintFile(dir); } catch (const std::exception &e) { QMessageBox::critical(NULL, QObject::tr("Failed to deactivate proxy-dll loading"), e.what()); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 4e3fa296..2d00580e 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -202,6 +202,7 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget connect(&m_ModList, SIGNAL(showMessage(QString)), this, SLOT(showMessage(QString))); connect(&m_ModList, SIGNAL(modRenamed(QString,QString)), this, SLOT(modRenamed(QString,QString))); connect(ui->modFilterEdit, SIGNAL(textChanged(QString)), m_ModListSortProxy, SLOT(updateFilter(QString))); + connect(ui->espFilterEdit, SIGNAL(textChanged(QString)), m_PluginListSortProxy, SLOT(updateFilter(QString))); connect(&m_ModList, SIGNAL(modlist_changed(int)), m_ModListSortProxy, SLOT(invalidate())); connect(&m_ModList, SIGNAL(removeSelectedMods()), this, SLOT(removeMod_clicked())); @@ -221,6 +222,9 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget connect(&TutorialManager::instance(), SIGNAL(windowTutorialFinished(QString)), this, SLOT(windowTutorialFinished(QString))); + m_CheckBSATimer.setSingleShot(true); + connect(&m_CheckBSATimer, SIGNAL(timeout()), this, SLOT(checkBSAList())); + m_DirectoryRefresher.moveToThread(&m_RefresherThread); m_RefresherThread.start(); @@ -478,6 +482,27 @@ void MainWindow::createHelpWidget() } +void MainWindow::saveArchiveList() +{ + if (m_ArchivesInit) { + QFile archiveFile(m_CurrentProfile->getArchivesFileName()); + if (archiveFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + for (int i = 0; i < ui->bsaList->topLevelItemCount(); ++i) { + QTreeWidgetItem *item = ui->bsaList->topLevelItem(i); + if ((item != NULL) && (item->checkState(0) == Qt::Checked)) { + archiveFile.write(item->text(0).toUtf8().append("\r\n")); + } + } + } else { + reportError(tr("failed to save archives order, do you have write access " + "to \"%1\"?").arg(m_CurrentProfile->getArchivesFileName())); + } + archiveFile.close(); + } else { + qWarning("archive list not initialised"); + } +} + bool MainWindow::saveCurrentLists() { if (m_DirectoryUpdate) { @@ -503,23 +528,6 @@ bool MainWindow::saveCurrentLists() reportError(tr("failed to save load order: %1").arg(e.what())); } - if (m_ArchivesInit) { - QFile archiveFile(m_CurrentProfile->getArchivesFileName()); - if (archiveFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { - for (int i = 0; i < ui->bsaList->topLevelItemCount(); ++i) { - QTreeWidgetItem *item = ui->bsaList->topLevelItem(i); - if ((item != NULL) && (item->checkState(0) == Qt::Checked)) { - archiveFile.write(item->text(0).toUtf8().append("\r\n")); - } - } - } else { - reportError(tr("failed to save archives order, do you have write access " - "to \"%1\"?").arg(m_CurrentProfile->getArchivesFileName())); - } - archiveFile.close(); - } else { - qWarning("archive list not initialised"); - } return true; } @@ -1059,6 +1067,9 @@ void MainWindow::startExeAction() void MainWindow::refreshModList() { + // don't lose changes! + m_CurrentProfile->writeModlistNow(true); + ModInfo::updateFromDisc(m_Settings.getModDirectory(), &m_DirectoryStructure); m_CurrentProfile->refreshModStatus(); @@ -1102,7 +1113,7 @@ void MainWindow::setExecutableIndex(int index) void MainWindow::activateSelectedProfile() { QString profileName = ui->profileBox->currentText(); - qDebug() << "activate profile " << profileName; + qDebug("activate profile \"%s\"", qPrintable(profileName)); QString profileDir = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getProfilesDir())) .append("/").append(profileName); delete m_CurrentProfile; @@ -1650,12 +1661,6 @@ void MainWindow::on_tabWidget_currentChanged(int index) } -static QString guessModName(const QString &fileName) -{ - return QFileInfo(fileName).baseName(); -} - - void MainWindow::installMod(const QString &fileName) { bool hasIniTweaks = false; @@ -3831,7 +3836,8 @@ void MainWindow::on_bsaList_customContextMenuRequested(const QPoint &pos) void MainWindow::on_bsaList_itemChanged(QTreeWidgetItem*, int) { - checkBSAList(); + saveArchiveList(); + m_CheckBSATimer.start(500); } void MainWindow::on_actionProblems_triggered() diff --git a/src/mainwindow.h b/src/mainwindow.h index 26e4c9dc..075c6247 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -103,6 +103,7 @@ public: void addPrimaryCategoryCandidates(QMenu *primaryCategoryMenu, ModInfo::Ptr info); + void saveArchiveList(); public slots: void displayColumnSelection(const QPoint &pos); @@ -197,8 +198,6 @@ private: bool extractProgress(QProgressDialog &extractProgress, int percentage, std::string fileName); - void checkBSAList(); - bool checkForProblems(QString &problemDescription); int getBinaryExecuteInfo(const QFileInfo &targetInfo, QFileInfo &binaryInfo, QString &arguments); @@ -277,6 +276,7 @@ private: QStringList m_ActiveArchives; bool m_DirectoryUpdate; bool m_ArchivesInit; + QTimer m_CheckBSATimer; QTime m_StartTime; SaveGameInfoWidget *m_CurrentSaveView; @@ -394,6 +394,8 @@ private slots: void startExeAction(); + void checkBSAList(); + private slots: // ui slots // actions void on_actionAdd_Profile_triggered(); @@ -425,6 +427,7 @@ private slots: // ui slots void on_espList_customContextMenuRequested(const QPoint &pos); void on_displayCategoriesBtn_toggled(bool checked); + }; #endif // MAINWINDOW_H diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 3493b710..71f0e3c6 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -596,9 +596,18 @@ p, li { white-space: pre-wrap; } ESPs - + + 6 + + 6 + + 6 + + + 0 + @@ -720,6 +729,16 @@ p, li { white-space: pre-wrap; } + + + + + + + Namefilter + + + diff --git a/src/modinfo.cpp b/src/modinfo.cpp index b8ef834f..80f27ccf 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -731,6 +731,9 @@ ModInfoRegular::EConflictType ModInfoRegular::isConflicted() const overwritten = true; break; } + } else if (alternatives.size() == 1) { + // only alternative is data -> no conflict + regular = true; } } } diff --git a/src/modlist.cpp b/src/modlist.cpp index e70e3c31..1f318e0d 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -145,7 +145,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const } else { if ((m_Profile->getModPriority(modIndex) == 0) && (role == Qt::DisplayRole)) { return tr("min"); - } else if ((m_Profile->getModPriority(modIndex) == m_Profile->numRegularMods() - 1) && + } else if ((m_Profile->getModPriority(modIndex) == static_cast(m_Profile->numRegularMods()) - 1) && (role == Qt::DisplayRole)) { return tr("max"); } else { diff --git a/src/organizer.pro b/src/organizer.pro index 723c1e04..86e9c616 100644 --- a/src/organizer.pro +++ b/src/organizer.pro @@ -199,6 +199,11 @@ CONFIG(debug, debug|release) { QMAKE_LFLAGS += /DEBUG } +QMAKE_CXXFLAGS_WARN_ON -= -W3 +QMAKE_CXXFLAGS_WARN_ON += -W4 +QMAKE_CXXFLAGS += -wd4127 -wd4512 -wd4189 + + CONFIG += embed_manifest_exe # QMAKE_CXXFLAGS += /analyze @@ -231,7 +236,7 @@ TRANSLATIONS = organizer_de.ts \ PRE_TARGETDEPS += compiler_TSQM_make_all } else:message(No translation files in project) -LIBS += -lmo_shared -luibase -lshell32 -lole32 -luser32 -ladvapi32 -lgdi32 -lPsapi -lVersion -lbsatk +LIBS += -lmo_shared -luibase -lshell32 -lole32 -luser32 -ladvapi32 -lgdi32 -lPsapi -lVersion -lbsatk -lshlwapi DEFINES += UNICODE _UNICODE _CRT_SECURE_NO_WARNINGS NOMINMAX diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index 486d6f42..25dc69bd 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -602,7 +602,7 @@ QVariant PluginList::data(const QModelIndex &modelIndex, int role) const case COL_PRIORITY: { if (m_ESPs[index].m_Priority == 0) { return tr("min"); - } else if (m_ESPs[index].m_Priority == m_ESPs.size() - 1) { + } else if (m_ESPs[index].m_Priority == static_cast(m_ESPs.size()) - 1) { return tr("max"); } else { return QString::number(m_ESPs[index].m_Priority); diff --git a/src/pluginlistsortproxy.cpp b/src/pluginlistsortproxy.cpp index 788073ab..5bff24f5 100644 --- a/src/pluginlistsortproxy.cpp +++ b/src/pluginlistsortproxy.cpp @@ -17,127 +17,141 @@ You should have received a copy of the GNU General Public License along with Mod Organizer. If not, see . */ -#include "pluginlistsortproxy.h" -#include "pluginlist.h" -#include -#include -#include - - -PluginListSortProxy::PluginListSortProxy(QObject *parent) - : QSortFilterProxyModel(parent), - m_SortIndex(0), m_SortOrder(Qt::AscendingOrder) -{ - m_EnabledColumns.set(PluginList::COL_NAME); - m_EnabledColumns.set(PluginList::COL_PRIORITY); - m_EnabledColumns.set(PluginList::COL_MODINDEX); - this->setDynamicSortFilter(true); -} - - -unsigned int PluginListSortProxy::getEnabledColumns() const -{ - unsigned int result = 0; - for (int i = 0; i <= PluginList::COL_LASTCOLUMN; ++i) { - if (m_EnabledColumns.test(i)) { - result |= 1 << i; - } - } - return result; -} - - -void PluginListSortProxy::setEnabledColumns(unsigned int columns) -{ - emit layoutAboutToBeChanged(); - for (int i = 0; i <= PluginList::COL_LASTCOLUMN; ++i) { - m_EnabledColumns.set(i, (columns & (1 << i)) != 0); - } - emit layoutChanged(); -} - - -Qt::ItemFlags PluginListSortProxy::flags(const QModelIndex &modelIndex) const -{ - Qt::ItemFlags flags = sourceModel()->flags(mapToSource(modelIndex)); - if (sortColumn() == PluginList::COL_NAME) { - flags &= ~Qt::ItemIsDragEnabled; - } - return flags; -} - - -void PluginListSortProxy::displayColumnSelection(const QPoint &pos) -{ - QMenu menu; - - for (int i = 0; i <= PluginList::COL_LASTCOLUMN; ++i) { - QCheckBox *checkBox = new QCheckBox(&menu); - checkBox->setText(PluginList::getColumnName(i)); - checkBox->setChecked(m_EnabledColumns.test(i) ? Qt::Checked : Qt::Unchecked); - QWidgetAction *checkableAction = new QWidgetAction(&menu); - checkableAction->setDefaultWidget(checkBox); - menu.addAction(checkableAction); - } - menu.exec(pos); - int i = 0; - - emit layoutAboutToBeChanged(); - m_EnabledColumns.reset(); - foreach (const QAction *action, menu.actions()) { - const QWidgetAction *widgetAction = qobject_cast(action); - if (widgetAction != NULL) { - const QCheckBox *checkBox = qobject_cast(widgetAction->defaultWidget()); - if (checkBox != NULL) { - m_EnabledColumns.set(i, checkBox->checkState() == Qt::Checked); - } - } - ++i; - } - emit layoutChanged(); -} - - -bool PluginListSortProxy::lessThan(const QModelIndex &left, - const QModelIndex &right) const -{ - PluginList *plugins = qobject_cast(sourceModel()); - switch (left.column()) { - case PluginList::COL_NAME: { - return QString::compare(plugins->getName(left.row()), plugins->getName(right.row()), Qt::CaseInsensitive) < 0; - } break; - case PluginList::COL_PRIORITY: - case PluginList::COL_MODINDEX: { - return plugins->getPriority(left.row()) < plugins->getPriority(right.row()); - } break; - default: { - static bool first = true; - if (first) { - qCritical("invalid sort column %d", left.column()); - first = false; - } - return plugins->getPriority(left.row()) < plugins->getPriority(right.row()); - } break; - } -} - - -bool PluginListSortProxy::dropMimeData(const QMimeData *data, Qt::DropAction action, - int row, int column, const QModelIndex &parent) -{ - if ((row == -1) && (column == -1)) { - return this->sourceModel()->dropMimeData(data, action, -1, -1, mapToSource(parent)); - } - // in the regular model, when dropping between rows, the row-value passed to - // the sourceModel is inconsistent between ascending and descending ordering. - // This should fix that - if (sortOrder() == Qt::DescendingOrder) { - --row; - } - - QModelIndex proxyIndex = index(row, column, parent); - QModelIndex sourceIndex = mapToSource(proxyIndex); - return this->sourceModel()->dropMimeData(data, action, sourceIndex.row(), sourceIndex.column(), - sourceIndex.parent()); -} - +#include "pluginlistsortproxy.h" +#include "pluginlist.h" +#include +#include +#include + + +PluginListSortProxy::PluginListSortProxy(QObject *parent) + : QSortFilterProxyModel(parent), + m_SortIndex(0), m_SortOrder(Qt::AscendingOrder) +{ + m_EnabledColumns.set(PluginList::COL_NAME); + m_EnabledColumns.set(PluginList::COL_PRIORITY); + m_EnabledColumns.set(PluginList::COL_MODINDEX); + this->setDynamicSortFilter(true); +} + + +unsigned int PluginListSortProxy::getEnabledColumns() const +{ + unsigned int result = 0; + for (int i = 0; i <= PluginList::COL_LASTCOLUMN; ++i) { + if (m_EnabledColumns.test(i)) { + result |= 1 << i; + } + } + return result; +} + + +void PluginListSortProxy::setEnabledColumns(unsigned int columns) +{ + emit layoutAboutToBeChanged(); + for (int i = 0; i <= PluginList::COL_LASTCOLUMN; ++i) { + m_EnabledColumns.set(i, (columns & (1 << i)) != 0); + } + emit layoutChanged(); +} + + +Qt::ItemFlags PluginListSortProxy::flags(const QModelIndex &modelIndex) const +{ + Qt::ItemFlags flags = sourceModel()->flags(mapToSource(modelIndex)); + if (sortColumn() == PluginList::COL_NAME) { + flags &= ~Qt::ItemIsDragEnabled; + } + return flags; +} + + +void PluginListSortProxy::displayColumnSelection(const QPoint &pos) +{ + QMenu menu; + + for (int i = 0; i <= PluginList::COL_LASTCOLUMN; ++i) { + QCheckBox *checkBox = new QCheckBox(&menu); + checkBox->setText(PluginList::getColumnName(i)); + checkBox->setChecked(m_EnabledColumns.test(i) ? Qt::Checked : Qt::Unchecked); + QWidgetAction *checkableAction = new QWidgetAction(&menu); + checkableAction->setDefaultWidget(checkBox); + menu.addAction(checkableAction); + } + menu.exec(pos); + int i = 0; + + emit layoutAboutToBeChanged(); + m_EnabledColumns.reset(); + foreach (const QAction *action, menu.actions()) { + const QWidgetAction *widgetAction = qobject_cast(action); + if (widgetAction != NULL) { + const QCheckBox *checkBox = qobject_cast(widgetAction->defaultWidget()); + if (checkBox != NULL) { + m_EnabledColumns.set(i, checkBox->checkState() == Qt::Checked); + } + } + ++i; + } + emit layoutChanged(); +} + + +void PluginListSortProxy::updateFilter(const QString &filter) +{ + m_CurrentFilter = filter; + invalidateFilter(); +} + + +bool PluginListSortProxy::filterAcceptsRow(int row, const QModelIndex&) const +{ + return m_CurrentFilter.isEmpty() || + sourceModel()->data(sourceModel()->index(row, 0)).toString().contains(m_CurrentFilter, Qt::CaseInsensitive); +} + + +bool PluginListSortProxy::lessThan(const QModelIndex &left, + const QModelIndex &right) const +{ + PluginList *plugins = qobject_cast(sourceModel()); + switch (left.column()) { + case PluginList::COL_NAME: { + return QString::compare(plugins->getName(left.row()), plugins->getName(right.row()), Qt::CaseInsensitive) < 0; + } break; + case PluginList::COL_PRIORITY: + case PluginList::COL_MODINDEX: { + return plugins->getPriority(left.row()) < plugins->getPriority(right.row()); + } break; + default: { + static bool first = true; + if (first) { + qCritical("invalid sort column %d", left.column()); + first = false; + } + return plugins->getPriority(left.row()) < plugins->getPriority(right.row()); + } break; + } +} + + +bool PluginListSortProxy::dropMimeData(const QMimeData *data, Qt::DropAction action, + int row, int column, const QModelIndex &parent) +{ + if ((row == -1) && (column == -1)) { + return this->sourceModel()->dropMimeData(data, action, -1, -1, mapToSource(parent)); + } + // in the regular model, when dropping between rows, the row-value passed to + // the sourceModel is inconsistent between ascending and descending ordering. + // This should fix that + if (sortOrder() == Qt::DescendingOrder) { + --row; + } + + QModelIndex proxyIndex = index(row, column, parent); + QModelIndex sourceIndex = mapToSource(proxyIndex); + return this->sourceModel()->dropMimeData(data, action, sourceIndex.row(), sourceIndex.column(), + sourceIndex.parent()); +} + diff --git a/src/pluginlistsortproxy.h b/src/pluginlistsortproxy.h index 7397ff7c..d5c71858 100644 --- a/src/pluginlistsortproxy.h +++ b/src/pluginlistsortproxy.h @@ -17,52 +17,55 @@ You should have received a copy of the GNU General Public License along with Mod Organizer. If not, see . */ -#ifndef PLUGINLISTSORTPROXY_H -#define PLUGINLISTSORTPROXY_H - - -#include -#include -#include "pluginlist.h" - - -class PluginListSortProxy : public QSortFilterProxyModel -{ - Q_OBJECT -public: - - enum ESorting { - SORT_ASCENDING, - SORT_DESCENDING - }; - -public: - - explicit PluginListSortProxy(QObject *parent = 0); - - unsigned int getEnabledColumns() const; - - void setEnabledColumns(unsigned int columns); - - virtual Qt::ItemFlags flags(const QModelIndex &modelIndex) const; - - virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); - -public slots: - - void displayColumnSelection(const QPoint &pos); - -protected: - - virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const; - -private: - - int m_SortIndex; - Qt::SortOrder m_SortOrder; - - std::bitset m_EnabledColumns; - -}; - -#endif // PLUGINLISTSORTPROXY_H +#ifndef PLUGINLISTSORTPROXY_H +#define PLUGINLISTSORTPROXY_H + + +#include +#include +#include "pluginlist.h" + + +class PluginListSortProxy : public QSortFilterProxyModel +{ + Q_OBJECT +public: + + enum ESorting { + SORT_ASCENDING, + SORT_DESCENDING + }; + +public: + + explicit PluginListSortProxy(QObject *parent = 0); + + unsigned int getEnabledColumns() const; + + void setEnabledColumns(unsigned int columns); + + virtual Qt::ItemFlags flags(const QModelIndex &modelIndex) const; + + virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); + +public slots: + + void displayColumnSelection(const QPoint &pos); + void updateFilter(const QString &filter); + +protected: + + virtual bool filterAcceptsRow(int row, const QModelIndex &parent) const; + virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const; + +private: + + int m_SortIndex; + Qt::SortOrder m_SortOrder; + + std::bitset m_EnabledColumns; + QString m_CurrentFilter; + +}; + +#endif // PLUGINLISTSORTPROXY_H diff --git a/src/profile.cpp b/src/profile.cpp index 002c93c0..67fd1e13 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -130,8 +130,10 @@ void Profile::cancelWriteModlist() const } -void Profile::writeModlistNow() const +void Profile::writeModlistNow(bool onlyOnTimer) const { + if (onlyOnTimer && !m_SaveTimer->isActive()) return; + m_SaveTimer->stop(); #pragma message("right now, this is doing unnecessary saves. Need a flag that says that mod priority, enabled-state or name of a mod has changed") @@ -194,11 +196,6 @@ void Profile::createTweakedIniFile() void Profile::refreshModStatus() { - // don't lose changes! - if (m_SaveTimer->isActive()) { - writeModlistNow(); - } - QFile file(getModlistFileName()); if (!file.exists()) { throw MyException(QObject::tr("failed to find \"%1\"").arg(getModlistFileName())); @@ -571,11 +568,15 @@ void Profile::deactivateInvalidation() const } } + // just to be safe... + ::SetFileAttributesW(iniFileName.c_str(), FILE_ATTRIBUTE_NORMAL); + if (!::WritePrivateProfileStringW(L"Archive", GameInfo::instance().archiveListKey().c_str(), ToWString(archives.join(", ").toUtf8()).c_str(), iniFileName.c_str()) || !::WritePrivateProfileStringW(L"Archive", L"bInvalidateOlderFiles", L"0", iniFileName.c_str()) || !::WritePrivateProfileStringW(L"Archive", L"SInvalidationFile", L"ArchiveInvalidation.txt", iniFileName.c_str())) { - throw windows_error("failed to modify ini file"); + QString errorMessage = tr("failed to modify \"%1\"").arg(ToQString(iniFileName)); + throw windows_error(errorMessage.toUtf8().constData()); } } } @@ -598,11 +599,15 @@ void Profile::activateInvalidation(const QString& dataDirectory) const archives.insert(0, invalidationBSA); } + // just to be safe... + ::SetFileAttributesW(iniFileName.c_str(), FILE_ATTRIBUTE_NORMAL); + if (!::WritePrivateProfileStringW(L"Archive", GameInfo::instance().archiveListKey().c_str(), ToWString(archives.join(", ").toUtf8()).c_str(), iniFileName.c_str()) || !::WritePrivateProfileStringW(L"Archive", L"bInvalidateOlderFiles", L"1", iniFileName.c_str()) || !::WritePrivateProfileStringW(L"Archive", L"SInvalidationFile", L"", iniFileName.c_str())) { - throw windows_error("failed to modify ini file"); + QString errorMessage = tr("failed to modify \"%1\"").arg(ToQString(iniFileName)); + throw windows_error(errorMessage.toUtf8().constData()); } QString bsaFile = dataDirectory + "/" + invalidationBSA; diff --git a/src/profile.h b/src/profile.h index 0c25b8f1..32647591 100644 --- a/src/profile.h +++ b/src/profile.h @@ -17,295 +17,295 @@ 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 "modinfo.h" - -#include -#include -#include -#include -#include -#include - - -/** - * @brief represents a profile - **/ -class Profile : public QObject -{ - - Q_OBJECT - -public: - - /** - * @brief default constructor - * @todo This constructor initialised nothing, the resulting object is not usable - **/ - Profile(); - - /** - * @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, 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); - - Profile(const Profile &reference); - - ~Profile(); - - /** - * @return true if this profile (still) exists on disc - */ - bool exists() const; - - /** - * @brief copy constructor - * - * @param name of the new profile - * @param reference profile to copy from - **/ - static Profile createFrom(const QString &name, const Profile &reference); - - /** - * @brief write out the modlist.txt - **/ - void writeModlist() const; - - /** - * cancel any potential request to write modlist.txt. This is used to ensure no invalid modlist is - * saved while it's being modified - */ - void cancelWriteModlist() const; - - /** - * @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() const; - - /** - * @brief activate archive invalidation - * - * @param dataDirectory data directory of the game - * @todo passing the data directory as a parameter is useless, the function should - * be able to query it from GameInfo - **/ - void activateInvalidation(const QString &dataDirectory) const; - - /** - * @return true if this profile uses local save games - */ - bool localSavesEnabled() const; - - /** - * @brief enables or disables the use of local save games for this profile - * disabling this does not delete exising local saves but they will not be visible - * in the game - * @param enable if true, local saves are enabled, otherewise they are disabled - */ - bool enableLocalSaves(bool enable); - - /** - * @return name of the profile (this is identical to its directory name) - **/ - QString getName() const { 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 path of the archives file in this profile - */ - QString getArchivesFileName() const; - - /** - * @return the path of the delete file in this profile - * @note the deleter file lists plugins that should be hidden from the game and other tools - **/ - QString getDeleterFileName() 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; - - /** - * @return path to this profile - **/ - QString getPath() const; - - /** - * @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(); - - /** - * 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 - **/ - unsigned int numMods() const { return m_ModStatus.size(); } - - /** - * @return the number of mods that can be enabled and where the priority can be modified - */ - unsigned int numRegularMods() const { return m_NumRegularMods; } - - /** - * @brief retrieve the mod index based on the priority - * - * @param priority priority to look up - * @return the index of the mod - * @throw std::exception an exception is thrown if there is no mod with the specified priority - **/ - unsigned int modIndexByPriority(unsigned int priority) const; - - /** - * @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); - - /** - * change the priority of a mod. Of course this also changes the priority of other mods. - * The priority of the mods in the range ]old, new priority] are shifted so that no gaps - * are possible. - * - * @param index index of the mod to change - * @param newPriority the new priority value - * - * @todo what happens if the new priority is outside the range? - **/ - void 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; - -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); - -public slots: - - void writeModlistNow() const; - -private: - - class ModStatus { - friend class Profile; - public: - ModStatus() : m_Overwrite(false), m_Enabled(false), m_Priority(-1) {} - private: - bool m_Overwrite; - bool m_Enabled; - int m_Priority; - }; - -private: - Profile& operator=(const Profile &reference); // not implemented - - void initTimer(); - - void updateIndices(); - - QString getModlistFileName() const; - 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; - -private: - - QDir m_Directory; - - std::vector m_ModStatus; - std::vector m_ModIndexByPriority; - unsigned int m_NumRegularMods; - - QTimer *m_SaveTimer; - -}; - -Q_DECLARE_METATYPE(Profile) - - -#endif // PROFILE_H +#ifndef PROFILE_H +#define PROFILE_H + + +#include "modinfo.h" + +#include +#include +#include +#include +#include +#include + + +/** + * @brief represents a profile + **/ +class Profile : public QObject +{ + + Q_OBJECT + +public: + + /** + * @brief default constructor + * @todo This constructor initialised nothing, the resulting object is not usable + **/ + Profile(); + + /** + * @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, 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); + + Profile(const Profile &reference); + + ~Profile(); + + /** + * @return true if this profile (still) exists on disc + */ + bool exists() const; + + /** + * @brief copy constructor + * + * @param name of the new profile + * @param reference profile to copy from + **/ + static Profile createFrom(const QString &name, const Profile &reference); + + /** + * @brief write out the modlist.txt + **/ + void writeModlist() const; + + /** + * cancel any potential request to write modlist.txt. This is used to ensure no invalid modlist is + * saved while it's being modified + */ + void cancelWriteModlist() const; + + /** + * @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() const; + + /** + * @brief activate archive invalidation + * + * @param dataDirectory data directory of the game + * @todo passing the data directory as a parameter is useless, the function should + * be able to query it from GameInfo + **/ + void activateInvalidation(const QString &dataDirectory) const; + + /** + * @return true if this profile uses local save games + */ + bool localSavesEnabled() const; + + /** + * @brief enables or disables the use of local save games for this profile + * disabling this does not delete exising local saves but they will not be visible + * in the game + * @param enable if true, local saves are enabled, otherewise they are disabled + */ + bool enableLocalSaves(bool enable); + + /** + * @return name of the profile (this is identical to its directory name) + **/ + QString getName() const { 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 path of the archives file in this profile + */ + QString getArchivesFileName() const; + + /** + * @return the path of the delete file in this profile + * @note the deleter file lists plugins that should be hidden from the game and other tools + **/ + QString getDeleterFileName() 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; + + /** + * @return path to this profile + **/ + QString getPath() const; + + /** + * @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(); + + /** + * 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 + **/ + unsigned int numMods() const { return m_ModStatus.size(); } + + /** + * @return the number of mods that can be enabled and where the priority can be modified + */ + unsigned int numRegularMods() const { return m_NumRegularMods; } + + /** + * @brief retrieve the mod index based on the priority + * + * @param priority priority to look up + * @return the index of the mod + * @throw std::exception an exception is thrown if there is no mod with the specified priority + **/ + unsigned int modIndexByPriority(unsigned int priority) const; + + /** + * @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); + + /** + * change the priority of a mod. Of course this also changes the priority of other mods. + * The priority of the mods in the range ]old, new priority] are shifted so that no gaps + * are possible. + * + * @param index index of the mod to change + * @param newPriority the new priority value + * + * @todo what happens if the new priority is outside the range? + **/ + void 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; + +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); + +public slots: + + void writeModlistNow(bool onlyOnTimer = false) const; + +private: + + class ModStatus { + friend class Profile; + public: + ModStatus() : m_Overwrite(false), m_Enabled(false), m_Priority(-1) {} + private: + bool m_Overwrite; + bool m_Enabled; + int m_Priority; + }; + +private: + Profile& operator=(const Profile &reference); // not implemented + + void initTimer(); + + void updateIndices(); + + QString getModlistFileName() const; + 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; + +private: + + QDir m_Directory; + + std::vector m_ModStatus; + std::vector m_ModIndexByPriority; + unsigned int m_NumRegularMods; + + QTimer *m_SaveTimer; + +}; + +Q_DECLARE_METATYPE(Profile) + + +#endif // PROFILE_H diff --git a/src/profilesdialog.cpp b/src/profilesdialog.cpp index cbf50dfc..ae3d6660 100644 --- a/src/profilesdialog.cpp +++ b/src/profilesdialog.cpp @@ -261,7 +261,7 @@ void ProfilesDialog::on_profilesList_currentItemChanged(QListWidgetItem *current void ProfilesDialog::on_localSavesBox_stateChanged(int state) { - Profile ¤tProfile = m_ProfilesList->currentItem()->data(Qt::UserRole).value(); + Profile currentProfile = m_ProfilesList->currentItem()->data(Qt::UserRole).value(); if (currentProfile.enableLocalSaves(state == Qt::Checked)) { ui->transferButton->setEnabled(state == Qt::Checked); } else { diff --git a/src/shared/skyriminfo.cpp b/src/shared/skyriminfo.cpp index 6302cef3..26395e67 100644 --- a/src/shared/skyriminfo.cpp +++ b/src/shared/skyriminfo.cpp @@ -27,6 +27,7 @@ along with Mod Organizer. If not, see . #include "error_report.h" #define WIN32_LEAN_AND_MEAN #include +#include #include namespace MOShared { @@ -36,6 +37,11 @@ SkyrimInfo::SkyrimInfo(const std::wstring &omoDirectory, const std::wstring &gam : GameInfo(omoDirectory, gameDirectory) { identifyMyGamesDirectory(L"skyrim"); + + wchar_t appDataPath[MAX_PATH]; + if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appDataPath))) { + m_AppData = appDataPath; + } } bool SkyrimInfo::identifyGame(const std::wstring &searchPath) @@ -258,8 +264,12 @@ bool SkyrimInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPa } } +if (_wcsicmp(fileName, L"plugins.txt") == 0) { + log("plugins.txt expected in \"%ls\", got \"%ls\"", m_AppData.c_str(), fullPath); +} + if ((_wcsicmp(fileName, L"plugins.txt") == 0) && - (wcsstr(fullPath, L"AppData") != NULL)){ + (m_AppData.empty() || (StrStrIW(fullPath, m_AppData.c_str()) != NULL))) { return true; } diff --git a/src/shared/skyriminfo.h b/src/shared/skyriminfo.h index b12a5d58..024d0395 100644 --- a/src/shared/skyriminfo.h +++ b/src/shared/skyriminfo.h @@ -97,6 +97,10 @@ private: static bool identifyGame(const std::wstring &searchPath); +private: + + std::wstring m_AppData; + }; } // namespace MOShared diff --git a/src/shared/util.cpp b/src/shared/util.cpp index a6378a74..e61ae8a6 100644 --- a/src/shared/util.cpp +++ b/src/shared/util.cpp @@ -79,6 +79,13 @@ std::string &ToLower(std::string &text) return text; } +std::string ToLower(const std::string &text) +{ + std::string temp = text; + + std::transform(temp.begin(), temp.end(), temp.begin(), tolower); + return temp; +} std::wstring &ToLower(std::wstring &text) { diff --git a/src/shared/util.h b/src/shared/util.h index 9c59f6db..80983cb0 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -39,8 +39,9 @@ std::string ToString(const std::wstring &source, bool utf8); std::wstring ToWString(const std::string &source, bool utf8); std::string &ToLower(std::string &text); -std::wstring &ToLower(std::wstring &text); +std::string ToLower(const std::string &text); +std::wstring &ToLower(std::wstring &text); std::wstring ToLower(const std::wstring &text); VS_FIXEDFILEINFO GetFileVersion(const std::wstring &fileName); diff --git a/src/version.rc b/src/version.rc index 23f7b6e3..9f083ed4 100644 --- a/src/version.rc +++ b/src/version.rc @@ -1,7 +1,7 @@ #include "Winver.h" -#define VER_FILEVERSION 0,12,8,0 -#define VER_FILEVERSION_STR 0,12,8,0 +#define VER_FILEVERSION 0,12,9,0 +#define VER_FILEVERSION_STR 0,12,9,0 VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION -- cgit v1.3.1 From 8b31996525de06bcb0ff519be42a732c85f532c9 Mon Sep 17 00:00:00 2001 From: Tannin Date: Mon, 18 Mar 2013 20:03:46 +0100 Subject: - bugfix: invalid ini file name when creating profile for oblivion from default settings - bugfix: archives.txt file was potentially not generated if there were no bsas - bugfix: static __declspec(thread) declaration causes crashes in windows versions before vista - logger class in hook.dll now tries alternative names for the log file if it can't access the regular file - path-environment variable for mo-spawned processes now contains the path to MO, in case the hook.dll needs to find the msvc-dlls - stack-search in ini-limit hack now starts searching on local stack. This should find the right stack position for the hack more reliable --- src/mainwindow.cpp | 5 +++++ src/mainwindow.h | 1 + src/shared/inject.cpp | 1 + src/shared/oblivioninfo.cpp | 1 - src/shared/skyriminfo.cpp | 4 ---- src/spawn.cpp | 23 +++++++++++++++++++++++ 6 files changed, 30 insertions(+), 5 deletions(-) (limited to 'src/mainwindow.cpp') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 2d00580e..5bc339d3 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -528,6 +528,11 @@ bool MainWindow::saveCurrentLists() reportError(tr("failed to save load order: %1").arg(e.what())); } + // ensure the archive list exists + if (!QFile::exists(m_CurrentProfile->getArchivesFileName())) { + saveArchiveList(); + } + return true; } diff --git a/src/mainwindow.h b/src/mainwindow.h index 075c6247..89e29685 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -171,6 +171,7 @@ private: void installMod(const QString &fileName); void installMod(); bool modifyExecutablesDialog(); + void modOpenNext(); void displayModInformation(ModInfo::Ptr modInfo, unsigned int index, int tab); void displayModInformation(int row, int tab = 0); void testExtractBSA(int modIndex); diff --git a/src/shared/inject.cpp b/src/shared/inject.cpp index 9fea7fc8..5a111c4a 100644 --- a/src/shared/inject.cpp +++ b/src/shared/inject.cpp @@ -136,6 +136,7 @@ void injectDLL(HANDLE processHandle, HANDLE threadHandle, const std::string &dll (written != sizeof(stubLocal))) { throw windows_error("failed to write stub to target process"); } + // finally, make the stub the new next thing for the thread to execute threadContext.Eip = (ULONG)stubRemote; if (::SetThreadContext(threadHandle, &threadContext) == 0) { diff --git a/src/shared/oblivioninfo.cpp b/src/shared/oblivioninfo.cpp index 1c714072..73e841a7 100644 --- a/src/shared/oblivioninfo.cpp +++ b/src/shared/oblivioninfo.cpp @@ -134,7 +134,6 @@ void OblivionInfo::createProfile(const std::wstring &directory, bool useDefaults if (!FileExists(target.str())) { std::wostringstream source; - source << getMyGamesDirectory() << L"\\Oblivion\\oblivion.ini"; if (useDefaults) { source << getGameDirectory() << L"\\oblivion_default.ini"; } else { diff --git a/src/shared/skyriminfo.cpp b/src/shared/skyriminfo.cpp index 26395e67..1c13effb 100644 --- a/src/shared/skyriminfo.cpp +++ b/src/shared/skyriminfo.cpp @@ -264,10 +264,6 @@ bool SkyrimInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPa } } -if (_wcsicmp(fileName, L"plugins.txt") == 0) { - log("plugins.txt expected in \"%ls\", got \"%ls\"", m_AppData.c_str(), fullPath); -} - if ((_wcsicmp(fileName, L"plugins.txt") == 0) && (m_AppData.empty() || (StrStrIW(fullPath, m_AppData.c_str()) != NULL))) { return true; diff --git a/src/spawn.cpp b/src/spawn.cpp index 39bd2af9..e83c8e21 100644 --- a/src/spawn.cpp +++ b/src/spawn.cpp @@ -20,6 +20,7 @@ along with Mod Organizer. If not, see . #include "spawn.h" #include "report.h" #include "utility.h" +#include #include #include #include @@ -31,6 +32,8 @@ using namespace MOBase; using namespace MOShared; +static const int BUFSIZE = 4096; + bool spawn(LPCWSTR binary, LPCWSTR arguments, LPCWSTR currentDirectory, bool suspended, HANDLE& processHandle, HANDLE& threadHandle) { STARTUPINFO si; @@ -44,7 +47,25 @@ bool spawn(LPCWSTR binary, LPCWSTR arguments, LPCWSTR currentDirectory, bool sus } else { commandLine = new wchar_t[length]; _snwprintf(commandLine, length, L"\"%ls\"", binary); + } + QString moPath = QCoreApplication::applicationDirPath(); + + boost::scoped_array oldPath(new TCHAR[BUFSIZE]); + DWORD offset = ::GetEnvironmentVariable(TEXT("PATH"), oldPath.get(), BUFSIZE); + if (offset > BUFSIZE) { + oldPath.reset(new TCHAR[offset]); + ::GetEnvironmentVariable(TEXT("PATH"), oldPath.get(), offset); + } + + { + boost::scoped_array newPath(new TCHAR[offset + moPath.length() + 2]); + _tcsncpy(newPath.get(), oldPath.get(), offset - 1); + newPath.get()[offset - 1] = L'\0'; + _tcsncat(newPath.get(), TEXT(";"), 1); + _tcsncat(newPath.get(), ToWString(QDir::toNativeSeparators(moPath)).c_str(), moPath.length()); + + ::SetEnvironmentVariable(TEXT("PATH"), newPath.get()); } PROCESS_INFORMATION pi; @@ -58,6 +79,8 @@ bool spawn(LPCWSTR binary, LPCWSTR arguments, LPCWSTR currentDirectory, bool sus &si, &pi // startup and process information ); + ::SetEnvironmentVariable(TEXT("PATH"), oldPath.get()); + delete [] commandLine; if (!success) { -- cgit v1.3.1