summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTannin <devnull@localhost>2013-03-22 18:57:45 +0100
committerTannin <devnull@localhost>2013-03-22 18:57:45 +0100
commitec0ea9df8dabe686d3256665c7ed638660309915 (patch)
tree39ff86ad325494c3531c159990ee695e84bee469
parent24cc3861912cc33235af587d4f4feb538c1054dc (diff)
parent74c75e60d67b66a63225239c1f6b1403662857aa (diff)
Merge with default
-rw-r--r--README.txt68
-rw-r--r--src/categoriesdialog.cpp3
-rw-r--r--src/editexecutablesdialog.cpp40
-rw-r--r--src/loadmechanism.cpp3
-rw-r--r--src/mainwindow.cpp75
-rw-r--r--src/mainwindow.h6
-rw-r--r--src/mainwindow.ui21
-rw-r--r--src/modinfo.cpp3
-rw-r--r--src/modlist.cpp2
-rw-r--r--src/nexusdialog.cpp5
-rw-r--r--src/organizer.pro7
-rw-r--r--src/pluginlist.cpp2
-rw-r--r--src/pluginlistsortproxy.cpp262
-rw-r--r--src/pluginlistsortproxy.h101
-rw-r--r--src/profile.cpp21
-rw-r--r--src/profile.h2
-rw-r--r--src/shared/inject.cpp1
-rw-r--r--src/shared/oblivioninfo.cpp1
-rw-r--r--src/shared/skyriminfo.cpp8
-rw-r--r--src/shared/skyriminfo.h4
-rw-r--r--src/shared/util.cpp7
-rw-r--r--src/shared/util.h3
-rw-r--r--src/spawn.cpp23
-rw-r--r--src/version.rc4
24 files changed, 445 insertions, 227 deletions
diff --git a/README.txt b/README.txt
new file mode 100644
index 00000000..119cf55f
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,68 @@
+HOW TO BUILD
+============
+
+Requirements:
+-------------
+
+Visual C++ compiler 2010 (VC 10.0) or up
+- Included in visual c++ express 2010 or windows sdk 7.0
+
+QtSDK 4.8.x (http://qt-project.org/downloads)
+- Qt5 is not yet supported but WIP
+- Install according to instruction
+
+boost libraries (http://www.boost.org/)
+- Compile according to their instructions (using vc++)
+- As of time of writing boost_thread is the only compiled boost library used, you can
+ disable the others to safe yourself the compile time
+
+zlib (http://www.zlib.net/)
+- Compile static library according to their instructions
+- You should have a "zlibstatic.lib" under "build" afterwards
+
+7z.dll (http://www.7-zip.org/download.html)
+- Part of the 7-zip program
+- Has to be the 32-bit dll! (approx. 893kb)
+
+Recommended:
+------------
+
+Qt Creator
+- Included in QtSDK but there might be a newer version as a separate download
+
+Set up (using Qt Creator):
+--------------------------
+
+1. Using Qt Creator open source/ModOrganizer.pro from your working copy
+2. Open the "Projects" tab, open the "Details" for "Build Environment"
+3. Click "Add" to add a variable called "BOOSTPATH" with the path of your boost installation as the value (i.e. C:\code\boost_1_52_0)
+4. Click "Add" to add a variable called "ZLIBPATH" with the path of your zlib installation as the value (i.e. C:\code\zlib-1.2.7)
+5. Switch the build configuration at the very top of the same page from "debug" to "release" (or vice versa) and repeat steps 3 and 4
+6. Compile the configuration(s) you want to use (debug and/or release) (Build All). This should compile correctly.
+7. return to the "projects" tab and switch to "Run Settings"
+For Release build:
+8r. Add a "Run configuration" that points to <your working copy>\output\ModOrganizer.exe
+9r. Copy "7z.dll" to <your working copy>\output\dlls
+10r. From QtSDK\Desktop\Qt\4.8.0\msvc2010\bin copy the following files to <your working copy>\output\dlls: QtCore4.dll, QtDeclarative4.dll, QtGui4.dll, QtNetwork4.dll, QtScript4.dll, QtSql4.dll, QtWebkit4.dll, QtXml4.dll, QtXmlPatterns4.dll
+For Debug build:
+8d. Add a "Run configuration" that points to <your working copy>\outputd\ModOrganizer.exe
+9d. Copy "7z.dll" to <your working copy>\outputd\dlls
+10d. From QtSDK\Desktop\Qt\4.8.0\msvc2010\bin copy the following files to <your working copy>\outputd\dlls: QtCored4.dll, QtDeclaratived4.dll, QtGuid4.dll, QtNetworkd4.dll, QtScriptd4.dll, QtSqld4.dll, QtWebkitd4.dll, QtXmld4.dll, QtXmlPatternsd4.dll
+
+Now you should be able to compile and run Mod Organizer.
+Please note that when you change anything apart from the "organizer" subproject, qt creator may not pick up on the changes
+and not recompile the modified subproject. the "organizer" project on the other hand is always re-linked. If anyone knowledgeable enough with qmake
+can fix that that would be awesome.
+
+Set up (without Qt Creator):
+----------------------------
+
+1. open a command line shell and navigate to <your working copy>\source
+2. run "qmake -tp vc" to create a visual c++ solution
+3. Open that solution
+4. - 98. A miracle happens
+99. You can now compile MO using VC
+
+I'm not using this workflow so I can't give more detailed instructions.
+Please note that the primary project format of MO remains qmake, if you work with visual studio and make changes to the project (like adding
+source files) you have to manually transfer those changes to the .pro file. \ No newline at end of file
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<QLineEdit*>(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/editexecutablesdialog.cpp b/src/editexecutablesdialog.cpp
index 42f29d83..e0d1994d 100644
--- a/src/editexecutablesdialog.cpp
+++ b/src/editexecutablesdialog.cpp
@@ -21,6 +21,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "ui_editexecutablesdialog.h"
#include "filedialogmemory.h"
#include <QMessageBox>
+#include <Shellapi.h>
+#include <utility.h>
using namespace MOBase;
@@ -87,6 +89,7 @@ void EditExecutablesDialog::resetInput()
{
ui->binaryEdit->setText("");
ui->titleEdit->setText("");
+ ui->workingDirEdit->clear();
ui->argumentsEdit->setText("");
ui->closeCheckBox->setChecked(false);
}
@@ -113,11 +116,42 @@ void EditExecutablesDialog::on_addButton_clicked()
void EditExecutablesDialog::on_browseButton_clicked()
{
QString binaryName = FileDialogMemory::getOpenFileName("editExecutableBinary", this,
- tr("Select a binary"), QString(), tr("Executable (%1)").arg("*.exe *.bat"));
+ tr("Select a binary"), QString(), tr("Executable (%1)").arg("*.exe *.bat *.jar"));
- QLineEdit *binaryEdit = findChild<QLineEdit*>("binaryEdit");
+ if (binaryName.endsWith(".jar", Qt::CaseInsensitive)) {
+ QString binaryPath;
+ { // try to find java automatically
+ std::wstring binaryNameW = ToWString(binaryName);
+ WCHAR buffer[MAX_PATH];
+ if (::FindExecutableW(binaryNameW.c_str(), NULL, buffer) > (HINSTANCE)32) {
+ DWORD binaryType = 0UL;
+ if (!::GetBinaryTypeW(binaryNameW.c_str(), &binaryType)) {
+ qDebug("failed to determine binary type: %lu", ::GetLastError());
+ } else if (binaryType == SCS_32BIT_BINARY) {
+ binaryPath = ToQString(buffer);
+ }
+ }
+ }
+ if (binaryPath.isEmpty()) {
+ QSettings javaReg("HKEY_LOCAL_MACHINE\\Software\\JavaSoft\\Java Runtime Environment", QSettings::NativeFormat);
+ if (javaReg.contains("CurrentVersion")) {
+ QString currentVersion = javaReg.value("CurrentVersion").toString();
+ binaryPath = javaReg.value(QString("%1/JavaHome").arg(currentVersion)).toString().append("\\bin\\javaw.exe");
+ }
+ }
+ if (binaryPath.isEmpty()) {
+ QMessageBox::information(this, tr("Java (32-bit) required"),
+ tr("MO requires 32-bit java to run this application. If you already have it installed, select javaw.exe "
+ "from that installation as the binary."));
+ } else {
+ ui->binaryEdit->setText(binaryPath);
+ }
- binaryEdit->setText(QDir::toNativeSeparators(binaryName));
+ ui->workingDirEdit->setText(QDir::toNativeSeparators(QFileInfo(binaryName).absolutePath()));
+ ui->argumentsEdit->setText("-jar \"" + QDir::toNativeSeparators(binaryName) + "\"");
+ } else {
+ ui->binaryEdit->setText(QDir::toNativeSeparators(binaryName));
+ }
}
void EditExecutablesDialog::on_browseDirButton_clicked()
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 6c8871ce..67a0de49 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -209,6 +209,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()));
@@ -228,6 +229,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();
@@ -448,10 +452,12 @@ void MainWindow::createHelpWidget()
typedef std::vector<std::pair<int, QAction*> > 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;
@@ -483,6 +489,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) {
@@ -508,23 +535,11 @@ 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");
+ // ensure the archive list exists
+ if (!QFile::exists(m_CurrentProfile->getArchivesFileName())) {
+ saveArchiveList();
}
+
return true;
}
@@ -554,7 +569,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();
@@ -1064,6 +1079,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();
@@ -1107,7 +1125,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;
@@ -1655,12 +1673,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;
@@ -2680,9 +2692,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;
@@ -3310,7 +3322,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());
@@ -3694,8 +3706,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();
}
@@ -3837,7 +3853,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 1484a1bf..25071127 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -46,6 +46,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "installationmanager.h"
#include "selfupdater.h"
#include "savegamegamebyro.h"
+#include "modlistsortproxy.h"
#include "pluginlistsortproxy.h"
#include "tutorialcontrol.h"
#include "savegameinfowidgetgamebryo.h"
@@ -104,6 +105,7 @@ public:
void addPrimaryCategoryCandidates(QMenu *primaryCategoryMenu, ModInfo::Ptr info);
+ void saveArchiveList();
public slots:
void displayColumnSelection(const QPoint &pos);
@@ -171,6 +173,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);
@@ -280,6 +283,7 @@ private:
QStringList m_ActiveArchives;
bool m_DirectoryUpdate;
bool m_ArchivesInit;
+ QTimer m_CheckBSATimer;
QTime m_StartTime;
SaveGameInfoWidget *m_CurrentSaveView;
@@ -397,6 +401,8 @@ private slots:
void startExeAction();
+ void checkBSAList();
+
private slots: // ui slots
// actions
void on_actionAdd_Profile_triggered();
diff --git a/src/mainwindow.ui b/src/mainwindow.ui
index 370265da..bcb0f156 100644
--- a/src/mainwindow.ui
+++ b/src/mainwindow.ui
@@ -621,9 +621,18 @@ p, li { white-space: pre-wrap; }
<string notr="true">ESPs</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
- <property name="margin">
+ <property name="leftMargin">
+ <number>6</number>
+ </property>
+ <property name="topMargin">
<number>6</number>
</property>
+ <property name="rightMargin">
+ <number>6</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
@@ -748,6 +757,16 @@ p, li { white-space: pre-wrap; }
</attribute>
</widget>
</item>
+ <item>
+ <widget class="MOBase::LineEditClear" name="espFilterEdit">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="placeholderText">
+ <string>Namefilter</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
<widget class="QWidget" name="bsaTab">
diff --git a/src/modinfo.cpp b/src/modinfo.cpp
index 28bdf789..31f0278c 100644
--- a/src/modinfo.cpp
+++ b/src/modinfo.cpp
@@ -726,6 +726,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 dad77d68..bc838a98 100644
--- a/src/modlist.cpp
+++ b/src/modlist.cpp
@@ -146,7 +146,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<int>(m_Profile->numRegularMods()) - 1) &&
(role == Qt::DisplayRole)) {
return tr("max");
} else {
diff --git a/src/nexusdialog.cpp b/src/nexusdialog.cpp
index 91c0caf8..6d8e850b 100644
--- a/src/nexusdialog.cpp
+++ b/src/nexusdialog.cpp
@@ -142,8 +142,8 @@ void NexusDialog::login(const QString &username, const QString &password)
{
m_AccessManager->login(username, password);
- connect(m_AccessManager, SIGNAL(loginSuccessful(bool)), this, SLOT(loginFinished(bool)));
- connect(m_AccessManager, SIGNAL(loginFailed(QString)), this, SLOT(loginFailed(QString)));
+ connect(m_AccessManager, SIGNAL(loginSuccessful(bool)), this, SLOT(loginFinished(bool)), Qt::UniqueConnection);
+ connect(m_AccessManager, SIGNAL(loginFailed(QString)), this, SLOT(loginFailed(QString)), Qt::UniqueConnection);
}
@@ -160,6 +160,7 @@ void NexusDialog::loginFinished(bool necessary)
if (necessary && this->isVisible()) {
MessageDialog::showMessage(tr("login successful"), this);
}
+
loadNexus();
emit loginSuccessful(necessary);
}
diff --git a/src/organizer.pro b/src/organizer.pro
index 633b2a21..0dbd2427 100644
--- a/src/organizer.pro
+++ b/src/organizer.pro
@@ -195,6 +195,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
@@ -227,7 +232,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 da31d11c..aa7bf4a3 100644
--- a/src/pluginlist.cpp
+++ b/src/pluginlist.cpp
@@ -606,7 +606,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<int>(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 <http://www.gnu.org/licenses/>.
*/
-#include "pluginlistsortproxy.h"
-#include "pluginlist.h"
-#include <QMenu>
-#include <QCheckBox>
-#include <QWidgetAction>
-
-
-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<const QWidgetAction*>(action);
- if (widgetAction != NULL) {
- const QCheckBox *checkBox = qobject_cast<const QCheckBox*>(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<PluginList*>(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 <QMenu>
+#include <QCheckBox>
+#include <QWidgetAction>
+
+
+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<const QWidgetAction*>(action);
+ if (widgetAction != NULL) {
+ const QCheckBox *checkBox = qobject_cast<const QCheckBox*>(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<PluginList*>(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 <http://www.gnu.org/licenses/>.
*/
-#ifndef PLUGINLISTSORTPROXY_H
-#define PLUGINLISTSORTPROXY_H
-
-
-#include <bitset>
-#include <QSortFilterProxyModel>
-#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<PluginList::COL_LASTCOLUMN + 1> m_EnabledColumns;
-
-};
-
-#endif // PLUGINLISTSORTPROXY_H
+#ifndef PLUGINLISTSORTPROXY_H
+#define PLUGINLISTSORTPROXY_H
+
+
+#include <bitset>
+#include <QSortFilterProxyModel>
+#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<PluginList::COL_LASTCOLUMN + 1> m_EnabledColumns;
+ QString m_CurrentFilter;
+
+};
+
+#endif // PLUGINLISTSORTPROXY_H
diff --git a/src/profile.cpp b/src/profile.cpp
index 62ac943e..97bd06b9 100644
--- a/src/profile.cpp
+++ b/src/profile.cpp
@@ -136,8 +136,10 @@ void Profile::cancelWriteModlist() const
}
-void Profile::writeModlistNow() const
+void Profile::writeModlistNow(bool onlyOnTimer) const
{
+ if (onlyOnTimer && !m_SaveTimer->isActive()) return;
+
m_SaveTimer->stop();
if (!m_Directory.exists()) return;
#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")
@@ -225,11 +227,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()));
@@ -600,11 +597,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());
}
}
}
@@ -627,11 +628,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 52b6a5eb..9c678a23 100644
--- a/src/profile.h
+++ b/src/profile.h
@@ -275,7 +275,7 @@ signals:
public slots:
- void writeModlistNow() const;
+ void writeModlistNow(bool onlyOnTimer = false) const;
private:
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 6302cef3..1c13effb 100644
--- a/src/shared/skyriminfo.cpp
+++ b/src/shared/skyriminfo.cpp
@@ -27,6 +27,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "error_report.h"
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
+#include <Shlwapi.h>
#include <boost/assign.hpp>
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)
@@ -259,7 +265,7 @@ bool SkyrimInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPa
}
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/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 <http://www.gnu.org/licenses/>.
#include "spawn.h"
#include "report.h"
#include "utility.h"
+#include <boost/scoped_array.hpp>
#include <gameinfo.h>
#include <inject.h>
#include <appconfig.h>
@@ -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<TCHAR> 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<TCHAR> 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) {
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