summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/categories.cpp7
-rw-r--r--src/categories.h4
-rw-r--r--src/downloadmanager.cpp5
-rw-r--r--src/downloadmanager.h2
-rw-r--r--src/installationmanager.cpp6
-rw-r--r--src/main.cpp95
-rw-r--r--src/mainwindow.cpp90
-rw-r--r--src/mainwindow.h4
-rw-r--r--src/modinfo.cpp69
-rw-r--r--src/modinfo.h49
-rw-r--r--src/modinfodialog.cpp11
-rw-r--r--src/modlist.cpp34
-rw-r--r--src/modlistsortproxy.cpp2
-rw-r--r--src/modlistview.cpp4
-rw-r--r--src/nexusinterface.cpp10
-rw-r--r--src/nexusinterface.h1
-rw-r--r--src/nxmaccessmanager.cpp8
-rw-r--r--src/nxmaccessmanager.h2
-rw-r--r--src/organizer.pro7
-rw-r--r--src/pluginlist.cpp11
-rw-r--r--src/pluginlist.h2
-rw-r--r--src/profile.cpp3
-rw-r--r--src/selfupdater.cpp2
-rw-r--r--src/shared/directoryentry.cpp7
-rw-r--r--src/shared/gameinfo.cpp7
-rw-r--r--src/shared/gameinfo.h4
-rw-r--r--src/shared/leaktrace.cpp38
-rw-r--r--src/shared/leaktrace.h4
-rw-r--r--src/shared/shared.pro10
-rw-r--r--src/spawn.cpp4
-rw-r--r--src/spawn.h4
-rw-r--r--src/splash.pngbin103422 -> 260807 bytes
-rw-r--r--src/version.rc4
33 files changed, 362 insertions, 148 deletions
diff --git a/src/categories.cpp b/src/categories.cpp
index 62ba3ca5..c084c238 100644
--- a/src/categories.cpp
+++ b/src/categories.cpp
@@ -43,6 +43,7 @@ QString CategoryFactory::categoriesFilePath()
CategoryFactory::CategoryFactory()
{
+ atexit(&cleanup);
reset();
QFile categoryFile(categoriesFilePath());
@@ -124,6 +125,12 @@ void CategoryFactory::setParents()
}
}
+void CategoryFactory::cleanup()
+{
+ delete s_Instance;
+ s_Instance = NULL;
+}
+
void CategoryFactory::saveCategories()
{
diff --git a/src/categories.h b/src/categories.h
index 75698149..31fccd6d 100644
--- a/src/categories.h
+++ b/src/categories.h
@@ -180,6 +180,8 @@ private:
void setParents();
+ static void cleanup();
+
private:
static CategoryFactory *s_Instance;
@@ -188,6 +190,8 @@ private:
std::map<int, unsigned int> m_IDMap;
std::map<int, unsigned int> m_NexusMap;
+private:
+
};
diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp
index c8f118f6..b965d598 100644
--- a/src/downloadmanager.cpp
+++ b/src/downloadmanager.cpp
@@ -22,6 +22,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "nxmurl.h"
#include <gameinfo.h>
#include <nxmurl.h>
+#include <taskprogressmanager.h>
#include "utility.h"
#include "json.h"
#include "selectiondialog.h"
@@ -63,6 +64,7 @@ DownloadManager::DownloadInfo *DownloadManager::DownloadInfo::createNew(const Ne
info->m_CurrentUrl = 0;
info->m_Tries = AUTOMATIC_RETRIES;
info->m_State = STATE_STARTED;
+ info->m_TaskProgressId = TaskProgressManager::instance().getId();
return info;
}
@@ -105,6 +107,7 @@ DownloadManager::DownloadInfo *DownloadManager::DownloadInfo::createFromMeta(con
info->m_CurrentUrl = 0;
info->m_Urls = metaFile.value("url", "").toString().split(";");
info->m_Tries = 0;
+ info->m_TaskProgressId = TaskProgressManager::instance().getId();
info->m_NexusInfo.m_Name = metaFile.value("name", 0).toString();
info->m_NexusInfo.m_ModName = metaFile.value("modName", "").toString();
info->m_NexusInfo.m_Version = metaFile.value("version", 0).toString();
@@ -159,6 +162,7 @@ DownloadManager::~DownloadManager()
for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); iter != m_ActiveDownloads.end(); ++iter) {
delete *iter;
}
+ m_ActiveDownloads.clear();
}
@@ -805,6 +809,7 @@ void DownloadManager::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
}
int oldProgress = info->m_Progress;
info->m_Progress = ((info->m_ResumePos + bytesReceived) * 100) / (info->m_ResumePos + bytesTotal);
+ TaskProgressManager::instance().updateProgress(info->m_TaskProgressId, bytesReceived, bytesTotal);
if (oldProgress != info->m_Progress) {
emit update(index);
}
diff --git a/src/downloadmanager.h b/src/downloadmanager.h
index 92ba3143..0d49aa35 100644
--- a/src/downloadmanager.h
+++ b/src/downloadmanager.h
@@ -98,6 +98,8 @@ private:
int m_Tries;
bool m_ReQueried;
+ quint32 m_TaskProgressId;
+
NexusInfo m_NexusInfo;
static DownloadInfo *createNew(const NexusInfo &nexusInfo, int modID, int fileID, const QStringList &URLs);
diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp
index 378eb38a..87efecf1 100644
--- a/src/installationmanager.cpp
+++ b/src/installationmanager.cpp
@@ -46,6 +46,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QDateTime>
#include <QDirIterator>
#include <boost/assign.hpp>
+#include <boost/scoped_ptr.hpp>
using namespace MOBase;
@@ -678,8 +679,7 @@ bool InstallationManager::install(const QString &fileName, GuessedValue<QString>
this->m_CurrentArchive->close();
});
- DirectoryTree *filesTree = archiveOpen ? createFilesTree() : NULL;
-
+ QScopedPointer<DirectoryTree> filesTree(archiveOpen ? createFilesTree() : NULL);
IPluginInstaller::EInstallResult installResult = IPluginInstaller::RESULT_NOTATTEMPTED;
std::sort(m_Installers.begin(), m_Installers.end(), [] (IPluginInstaller *LHS, IPluginInstaller *RHS) {
@@ -704,7 +704,7 @@ bool InstallationManager::install(const QString &fileName, GuessedValue<QString>
(filesTree != NULL) && (installer->isArchiveSupported(*filesTree))) {
installResult = installerSimple->install(modName, *filesTree, version, modID);
if (installResult == IPluginInstaller::RESULT_SUCCESS) {
- mapToArchive(filesTree);
+ mapToArchive(filesTree.data());
// the simple installer only prepares the installation, the rest works the same for all installers
if (!doInstall(modName, modID, version, newestVersion, categoryID)) {
installResult = IPluginInstaller::RESULT_FAILED;
diff --git a/src/main.cpp b/src/main.cpp
index 5a694121..c4431ac4 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -18,6 +18,11 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
+#ifdef LEAK_CHECK_WITH_VLD
+#include <wchar.h>
+#include <vld.h>
+#endif // LEAK_CHECK_WITH_VLD
+
#include <QApplication>
#include <QPushButton>
#include <QListWidget>
@@ -430,61 +435,65 @@ int main(int argc, char *argv[])
application.setStyleFile(settings.value("Settings/style", "").toString());
- // set up main window and its data structures
- MainWindow mainWindow(argv[0], settings);
- QObject::connect(&mainWindow, SIGNAL(styleChanged(QString)), &application, SLOT(setStyleFile(QString)));
- QObject::connect(&instance, SIGNAL(messageSent(QString)), &mainWindow, SLOT(externalMessage(QString)));
+ int res = 1;
+ { // scope to control lifetime of mainwindow
+ // set up main window and its data structures
+ MainWindow mainWindow(argv[0], settings);
+ QObject::connect(&mainWindow, SIGNAL(styleChanged(QString)), &application, SLOT(setStyleFile(QString)));
+ QObject::connect(&instance, SIGNAL(messageSent(QString)), &mainWindow, SLOT(externalMessage(QString)));
- mainWindow.setExecutablesList(executablesList);
- mainWindow.readSettings();
+ mainWindow.setExecutablesList(executablesList);
+ mainWindow.readSettings();
- QString selectedProfileName = QString::fromUtf8(settings.value("selected_profile", "").toByteArray());
+ QString selectedProfileName = QString::fromUtf8(settings.value("selected_profile", "").toByteArray());
- { // see if there is a profile on the command line
- int profileIndex = arguments.indexOf("-p", 1);
- if ((profileIndex != -1) && (profileIndex < arguments.size() - 1)) {
- qDebug("profile overwritten on command line");
- selectedProfileName = arguments.at(profileIndex + 1);
+ { // see if there is a profile on the command line
+ int profileIndex = arguments.indexOf("-p", 1);
+ if ((profileIndex != -1) && (profileIndex < arguments.size() - 1)) {
+ qDebug("profile overwritten on command line");
+ selectedProfileName = arguments.at(profileIndex + 1);
+ }
+ arguments.removeAt(profileIndex);
+ arguments.removeAt(profileIndex);
}
- arguments.removeAt(profileIndex);
- arguments.removeAt(profileIndex);
- }
- qDebug("configured profile: %s", qPrintable(selectedProfileName));
+ qDebug("configured profile: %s", qPrintable(selectedProfileName));
- // if we have a command line parameter, it is either a nxm link or
- // a binary to start
- if ((arguments.size() > 1) && (!isNxmLink(arguments.at(1)))) {
- QString exeName = arguments.at(1);
- qDebug("starting %s from command line", qPrintable(exeName));
- arguments.removeFirst(); // remove application name (ModOrganizer.exe)
- arguments.removeFirst(); // remove binary name
- // pass the remaining parameters to the binary
- mainWindow.spawnProgram(exeName, arguments.join(" "), selectedProfileName, QDir());
- return 0;
- }
+ // if we have a command line parameter, it is either a nxm link or
+ // a binary to start
+ if ((arguments.size() > 1) && (!isNxmLink(arguments.at(1)))) {
+ QString exeName = arguments.at(1);
+ qDebug("starting %s from command line", qPrintable(exeName));
+ arguments.removeFirst(); // remove application name (ModOrganizer.exe)
+ arguments.removeFirst(); // remove binary name
+ // pass the remaining parameters to the binary
+ mainWindow.spawnProgram(exeName, arguments.join(" "), selectedProfileName, QDir());
+ return 0;
+ }
- mainWindow.createFirstProfile();
+ mainWindow.createFirstProfile();
- if (selectedProfileName.length() != 0) {
- if (!mainWindow.setCurrentProfile(selectedProfileName)) {
+ if (selectedProfileName.length() != 0) {
+ if (!mainWindow.setCurrentProfile(selectedProfileName)) {
+ mainWindow.setCurrentProfile(1);
+ qWarning("failed to set profile: %s",
+ selectedProfileName.toUtf8().constData());
+ }
+ } else {
mainWindow.setCurrentProfile(1);
- qWarning("failed to set profile: %s",
- selectedProfileName.toUtf8().constData());
}
- } else {
- mainWindow.setCurrentProfile(1);
- }
- qDebug("displaying main window");
- mainWindow.show();
+ qDebug("displaying main window");
+ mainWindow.show();
- if ((arguments.size() > 1) &&
- (isNxmLink(arguments.at(1)))) {
- qDebug("starting download from command line: %s", qPrintable(arguments.at(1)));
- mainWindow.externalMessage(arguments.at(1));
+ if ((arguments.size() > 1) &&
+ (isNxmLink(arguments.at(1)))) {
+ qDebug("starting download from command line: %s", qPrintable(arguments.at(1)));
+ mainWindow.externalMessage(arguments.at(1));
+ }
+ splash.finish(&mainWindow);
+ res = application.exec();
}
- splash.finish(&mainWindow);
- return application.exec();
+ return res;
} catch (const std::exception &e) {
reportError(e.what());
return 1;
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index b6ee866f..9516f818 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -139,8 +139,8 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget
: QMainWindow(parent), ui(new Ui::MainWindow), m_Tutorial(this, "MainWindow"),
m_ExeName(exeName), m_OldProfileIndex(-1),
m_DirectoryStructure(new DirectoryEntry(L"data", NULL, 0)),
- m_ModList(NexusInterface::instance()), m_ModListGroupingProxy(NULL), m_ModListSortProxy(NULL),
- m_OldExecutableIndex(-1), m_GamePath(ToQString(GameInfo::instance().getGameDirectory())),
+ m_ModList(this), m_ModListGroupingProxy(NULL), m_ModListSortProxy(NULL),
+ m_PluginList(this), m_OldExecutableIndex(-1), m_GamePath(ToQString(GameInfo::instance().getGameDirectory())),
m_DownloadManager(NexusInterface::instance(), this),
m_InstallationManager(this), m_Translator(NULL), m_TranslatorQt(NULL),
m_Updater(NexusInterface::instance(), this), m_CategoryFactory(CategoryFactory::instance()),
@@ -149,8 +149,7 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget
m_GameInfo(new GameInfoImpl())
{
ui->setupUi(this);
-
- this->setWindowTitle(ToQString(GameInfo::instance().getGameName()).append(" Mod Organizer v").append(m_Updater.getVersion().canonicalString()));
+ this->setWindowTitle(ToQString(GameInfo::instance().getGameName()) + " Mod Organizer v" + m_Updater.getVersion().displayString());
m_RefreshProgress = new QProgressBar(statusBar());
m_RefreshProgress->setTextVisible(true);
@@ -256,7 +255,7 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget
connect(&m_Updater, SIGNAL(updateAvailable()), this, SLOT(updateAvailable()));
connect(&m_Updater, SIGNAL(motdAvailable(QString)), this, SLOT(motdReceived(QString)));
- connect(ExitProxy::instance(), SIGNAL(exit()), this, SLOT(close()));
+// connect(ExitProxy::instance(), SIGNAL(exit()), this, SLOT(close()));
connect(NexusInterface::instance()->getAccessManager(), SIGNAL(loginSuccessful(bool)), this, SLOT(loginSuccessful(bool)));
connect(NexusInterface::instance()->getAccessManager(), SIGNAL(loginFailed(QString)), this, SLOT(loginFailed(QString)));
@@ -413,7 +412,7 @@ void MainWindow::actionToToolButton(QAction *&sourceAction)
button->setToolButtonStyle(ui->toolBar->toolButtonStyle());
button->setToolTip(sourceAction->toolTip());
button->setShortcut(sourceAction->shortcut());
- QMenu *buttonMenu = new QMenu(sourceAction->text());
+ QMenu *buttonMenu = new QMenu(sourceAction->text(), button);
button->setMenu(buttonMenu);
QAction *newAction = ui->toolBar->insertWidget(sourceAction, button);
newAction->setObjectName(sourceAction->objectName());
@@ -1330,6 +1329,7 @@ void MainWindow::spawnBinary(const QFileInfo &binary, const QString &arguments,
QFile::remove(m_CurrentProfile->getLoadOrderFileName());
}
dialog->hide();
+ dialog->deleteLater();
}
}
}
@@ -1499,6 +1499,8 @@ void MainWindow::updateTo(QTreeWidgetItem *subTree, const std::wstring &director
updateTo(directoryChild, temp.str(), **current, conflictsOnly);
if (directoryChild->childCount() != 0) {
subTree->addChild(directoryChild);
+ } else {
+ delete directoryChild;
}
}
}
@@ -3070,7 +3072,6 @@ void MainWindow::openExplorer_clicked()
::ShellExecuteW(NULL, L"explore", ToWString(modInfo->absolutePath()).c_str(), NULL, NULL, SW_SHOWNORMAL);
}
-
void MainWindow::information_clicked()
{
try {
@@ -3080,7 +3081,6 @@ void MainWindow::information_clicked()
}
}
-
void MainWindow::syncOverwrite()
{
ModInfo::Ptr modInfo = ModInfo::getByIndex(m_ContextRow);
@@ -3092,7 +3092,6 @@ void MainWindow::syncOverwrite()
}
}
-
void MainWindow::createModFromOverwrite()
{
GuessedValue<QString> name;
@@ -3126,14 +3125,12 @@ void MainWindow::createModFromOverwrite()
refreshModList();
}
-
void MainWindow::cancelModListEditor()
{
ui->modList->setEnabled(false);
ui->modList->setEnabled(true);
}
-
void MainWindow::on_modList_doubleClicked(const QModelIndex &index)
{
if (!index.isValid()) {
@@ -3156,7 +3153,6 @@ void MainWindow::on_modList_doubleClicked(const QModelIndex &index)
}
}
-
bool MainWindow::addCategories(QMenu *menu, int targetID)
{
ModInfo::Ptr modInfo = ModInfo::getByIndex(m_ContextRow);
@@ -3195,7 +3191,6 @@ bool MainWindow::addCategories(QMenu *menu, int targetID)
return childEnabled;
}
-
void MainWindow::saveCategoriesFromMenu(QMenu *menu, int modRow)
{
ModInfo::Ptr modInfo = ModInfo::getByIndex(modRow);
@@ -3212,7 +3207,6 @@ void MainWindow::saveCategoriesFromMenu(QMenu *menu, int modRow)
}
}
-
void MainWindow::saveCategories()
{
QMenu *menu = qobject_cast<QMenu*>(sender());
@@ -3256,8 +3250,6 @@ void MainWindow::saveCategories()
refreshFilters();
}
-
-
void MainWindow::savePrimaryCategory()
{
QMenu *menu = qobject_cast<QMenu*>(sender());
@@ -3282,7 +3274,6 @@ void MainWindow::savePrimaryCategory()
}
}
-
void MainWindow::checkModsForUpdates()
{
statusBar()->show();
@@ -3300,6 +3291,45 @@ void MainWindow::checkModsForUpdates()
}
}
+void MainWindow::changeVersioningScheme() {
+ if (QMessageBox::question(this, tr("Continue?"),
+ tr("This will try to change the versioning scheme so that the newest version is interpreted as an update to "
+ "the installed version."),
+ QMessageBox::Yes | QMessageBox::Cancel) == QMessageBox::Yes) {
+
+ ModInfo::Ptr info = ModInfo::getByIndex(m_ContextRow);
+
+ bool success = false;
+
+ static VersionInfo::VersionScheme schemes[] = { VersionInfo::SCHEME_REGULAR, VersionInfo::SCHEME_DECIMALMARK, VersionInfo::SCHEME_NUMBERSANDLETTERS };
+
+ for (int i = 0; i < sizeof(schemes) / sizeof(VersionInfo::VersionScheme) && !success; ++i) {
+ VersionInfo verOld(info->getVersion().canonicalString(), schemes[i]);
+ VersionInfo verNew(info->getNewestVersion().canonicalString(), schemes[i]);
+ if (verOld < verNew) {
+ info->setVersion(verOld);
+ info->setNewestVersion(verNew);
+ success = true;
+ }
+ }
+ if (!success) {
+ QMessageBox::information(this, tr("Sorry"),
+ tr("I don't know a versioning scheme where %1 is newer than %2.").arg(info->getNewestVersion().canonicalString()).arg(info->getVersion().canonicalString()),
+ QMessageBox::Ok);
+ }
+ }
+}
+
+void MainWindow::ignoreUpdate() {
+ ModInfo::Ptr info = ModInfo::getByIndex(m_ContextRow);
+ info->ignoreUpdate(true);
+}
+
+void MainWindow::unignoreUpdate()
+{
+ ModInfo::Ptr info = ModInfo::getByIndex(m_ContextRow);
+ info->ignoreUpdate(false);
+}
void MainWindow::addPrimaryCategoryCandidates(QMenu *primaryCategoryMenu, ModInfo::Ptr info)
{
@@ -3321,7 +3351,6 @@ void MainWindow::addPrimaryCategoryCandidates(QMenu *primaryCategoryMenu, ModInf
}
}
-
void MainWindow::addPrimaryCategoryCandidates()
{
QMenu *menu = qobject_cast<QMenu*>(sender());
@@ -3335,7 +3364,6 @@ void MainWindow::addPrimaryCategoryCandidates()
addPrimaryCategoryCandidates(menu, modInfo);
}
-
void MainWindow::enableVisibleMods()
{
if (QMessageBox::question(NULL, tr("Confirm"), tr("Really enable all visible mods?"),
@@ -3344,7 +3372,6 @@ void MainWindow::enableVisibleMods()
}
}
-
void MainWindow::disableVisibleMods()
{
if (QMessageBox::question(NULL, tr("Confirm"), tr("Really disable all visible mods?"),
@@ -3353,7 +3380,6 @@ void MainWindow::disableVisibleMods()
}
}
-
void MainWindow::exportModListCSV()
{
SelectionDialog selection(tr("Choose what to export"));
@@ -3408,7 +3434,6 @@ void MainWindow::exportModListCSV()
}
}
-
void addMenuAsPushButton(QMenu *menu, QMenu *subMenu)
{
QPushButton *pushBtn = new QPushButton(subMenu->title());
@@ -3418,13 +3443,13 @@ void addMenuAsPushButton(QMenu *menu, QMenu *subMenu)
menu->addAction(action);
}
-
void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos)
{
try {
QTreeView *modList = findChild<QTreeView*>("modList");
- m_ContextRow = mapToModel(&m_ModList, modList->indexAt(pos)).row();
+ QModelIndex index = mapToModel(&m_ModList, modList->indexAt(pos));
+ m_ContextRow = index.row();
QMenu menu;
@@ -3463,6 +3488,17 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos)
connect(primaryCategoryMenu, SIGNAL(aboutToHide()), this, SLOT(savePrimaryCategory()));
addMenuAsPushButton(&menu, primaryCategoryMenu);
+ menu.addSeparator();
+ if (info->downgradeAvailable()) {
+ menu.addAction(tr("Change versioning scheme"), this, SLOT(changeVersioningScheme()));
+ }
+ if (info->updateIgnored()) {
+ menu.addAction(tr("Un-ignore update"), this, SLOT(unignoreUpdate()));
+ } else {
+ menu.addAction(tr("Ignore update"), this, SLOT(ignoreUpdate()));
+ }
+ menu.addSeparator();
+
menu.addAction(tr("Rename Mod..."), this, SLOT(renameMod_clicked()));
menu.addAction(tr("Remove Mod..."), this, SLOT(removeMod_clicked()));
menu.addAction(tr("Reinstall Mod"), this, SLOT(reinstallMod_clicked()));
@@ -4209,9 +4245,9 @@ void MainWindow::on_actionEndorseMO_triggered()
void MainWindow::updateDownloadListDelegate()
{
if (ui->compactBox->isChecked()) {
- ui->downloadView->setItemDelegate(new DownloadListWidgetCompactDelegate(&m_DownloadManager, ui->downloadView));
+ ui->downloadView->setItemDelegate(new DownloadListWidgetCompactDelegate(&m_DownloadManager, ui->downloadView, ui->downloadView));
} else {
- ui->downloadView->setItemDelegate(new DownloadListWidgetDelegate(&m_DownloadManager, ui->downloadView));
+ ui->downloadView->setItemDelegate(new DownloadListWidgetDelegate(&m_DownloadManager, ui->downloadView, ui->downloadView));
}
DownloadListSortProxy *sortProxy = new DownloadListSortProxy(&m_DownloadManager, ui->downloadView);
@@ -4269,7 +4305,7 @@ void MainWindow::nxmUpdatesAvailable(const std::vector<int> &modIDs, QVariant us
} else {
std::vector<ModInfo::Ptr> info = ModInfo::getByModID(result["id"].toInt());
for (auto iter = info.begin(); iter != info.end(); ++iter) {
- (*iter)->setNewestVersion(VersionInfo(result["version"].toString()));
+ (*iter)->setNewestVersion(result["version"].toString());
(*iter)->setNexusDescription(result["description"].toString());
if (NexusInterface::instance()->getAccessManager()->loggedIn() &&
result.contains("voted_by_user")) {
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 80dca172..dfec5f49 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -466,6 +466,10 @@ private slots:
void removeFromToolbar();
void overwriteClosed(int);
+ void changeVersioningScheme();
+ void ignoreUpdate();
+ void unignoreUpdate();
+
private slots: // ui slots
// actions
void on_actionAdd_Profile_triggered();
diff --git a/src/modinfo.cpp b/src/modinfo.cpp
index 166c815b..1479f7b4 100644
--- a/src/modinfo.cpp
+++ b/src/modinfo.cpp
@@ -303,10 +303,11 @@ ModInfoRegular::ModInfoRegular(const QDir &path, DirectoryEntry **directoryStruc
QString metaFileName = path.absoluteFilePath("meta.ini");
QSettings metaFile(metaFileName, QSettings::IniFormat);
- m_Notes = metaFile.value("notes", "").toString();
- m_NexusID = metaFile.value("modid", -1).toInt();
+ m_Notes = metaFile.value("notes", "").toString();
+ m_NexusID = metaFile.value("modid", -1).toInt();
m_Version.parse(metaFile.value("version", "").toString());
- m_NewestVersion = metaFile.value("newestVersion", "").toString();
+ m_NewestVersion = metaFile.value("newestVersion", "").toString();
+ m_IgnoredVersion = metaFile.value("ignoredVersion", "").toString();
m_InstallationFile = metaFile.value("installationFile", "").toString();
m_NexusDescription = metaFile.value("nexusDescription", "").toString();
m_LastNexusQuery = QDateTime::fromString(metaFile.value("lastNexusQuery", "").toString(), Qt::ISODate);
@@ -350,8 +351,6 @@ ModInfoRegular::ModInfoRegular(const QDir &path, DirectoryEntry **directoryStruc
ModInfoRegular::~ModInfoRegular()
{
try {
- //TODO this may cause the meta-file and the directory to be
- // re-created after a remove
saveMeta();
} catch (const std::exception &e) {
qCritical("failed to save meta information for \"%s\": %s",
@@ -371,28 +370,26 @@ bool ModInfoRegular::isEmpty() const
void ModInfoRegular::saveMeta()
{
- if (m_MetaInfoChanged) {
- if (QFile::exists(absolutePath().append("/meta.ini"))) {
- QSettings metaFile(absolutePath().append("/meta.ini"), QSettings::IniFormat);
- if (metaFile.status() == QSettings::NoError) {
- std::set<int> temp = m_Categories;
- temp.erase(m_PrimaryCategory);
- metaFile.setValue("category", QString("%1").arg(m_PrimaryCategory) + "," + SetJoin(temp, ","));
- metaFile.setValue("newestVersion", m_NewestVersion.canonicalString());
- metaFile.setValue("version", m_Version.canonicalString());
- metaFile.setValue("modid", m_NexusID);
- metaFile.setValue("notes", m_Notes);
- metaFile.setValue("nexusDescription", m_NexusDescription);
- metaFile.setValue("lastNexusQuery", m_LastNexusQuery.toString(Qt::ISODate));
- if (m_EndorsedState != ENDORSED_UNKNOWN) {
- metaFile.setValue("endorsed", m_EndorsedState);
- }
-
- } else {
- reportError(tr("failed to write %1/meta.ini: %2").arg(absolutePath()).arg(metaFile.status()));
+ // only write meta data if the mod directory exists
+ if (m_MetaInfoChanged && QFile::exists(absolutePath())) {
+ QSettings metaFile(absolutePath().append("/meta.ini"), QSettings::IniFormat);
+ if (metaFile.status() == QSettings::NoError) {
+ std::set<int> temp = m_Categories;
+ temp.erase(m_PrimaryCategory);
+ metaFile.setValue("category", QString("%1").arg(m_PrimaryCategory) + "," + SetJoin(temp, ","));
+ metaFile.setValue("newestVersion", m_NewestVersion.canonicalString());
+ metaFile.setValue("ignoredVersion", m_IgnoredVersion.canonicalString());
+ metaFile.setValue("version", m_Version.canonicalString());
+ metaFile.setValue("modid", m_NexusID);
+ metaFile.setValue("notes", m_Notes);
+ metaFile.setValue("nexusDescription", m_NexusDescription);
+ metaFile.setValue("lastNexusQuery", m_LastNexusQuery.toString(Qt::ISODate));
+ if (m_EndorsedState != ENDORSED_UNKNOWN) {
+ metaFile.setValue("endorsed", m_EndorsedState);
}
+ metaFile.sync(); // sync needs to be called to ensure the file is created
} else {
- qWarning("mod %s has no meta.ini at %s/meta.ini", m_Name.toUtf8().constData(), absolutePath().toUtf8().constData());
+ reportError(tr("failed to write %1/meta.ini: %2").arg(absolutePath()).arg(metaFile.status()));
}
m_MetaInfoChanged = false;
}
@@ -401,10 +398,22 @@ void ModInfoRegular::saveMeta()
bool ModInfoRegular::updateAvailable() const
{
+ if (m_IgnoredVersion.isValid() && (m_IgnoredVersion == m_NewestVersion)) {
+ return false;
+ }
return m_NewestVersion.isValid() && (m_Version < m_NewestVersion);
}
+bool ModInfoRegular::downgradeAvailable() const
+{
+ if (m_IgnoredVersion.isValid() && (m_IgnoredVersion == m_NewestVersion)) {
+ return false;
+ }
+ return m_NewestVersion.isValid() && (m_NewestVersion < m_Version);
+}
+
+
void ModInfoRegular::nxmDescriptionAvailable(int, QVariant, QVariant resultData)
{
QVariantMap result = resultData.toMap();
@@ -581,6 +590,16 @@ QString ModInfoRegular::absolutePath() const
return m_Path;
}
+void ModInfoRegular::ignoreUpdate(bool ignore)
+{
+ if (ignore) {
+ m_IgnoredVersion = m_NewestVersion;
+ } else {
+ m_IgnoredVersion.clear();
+ }
+ m_MetaInfoChanged = true;
+}
+
std::vector<ModInfo::EFlag> ModInfoRegular::getFlags() const
{
diff --git a/src/modinfo.h b/src/modinfo.h
index 7e217de7..3b83d207 100644
--- a/src/modinfo.h
+++ b/src/modinfo.h
@@ -193,6 +193,22 @@ public:
virtual bool updateAvailable() const = 0;
/**
+ * @return true if the update currently available is ignored
+ */
+ virtual bool updateIgnored() const = 0;
+
+ /**
+ * @brief test if the "newest" version of the mod is older than the installed version
+ *
+ * test if there is a newer version of the mod. This does NOT cause
+ * information to be retrieved from the nexus, it will only test version information already
+ * available locally. Use checkAllForUpdate() to update this version information
+ *
+ * @return true if the newest version is older than the installed one
+ **/
+ virtual bool downgradeAvailable() const = 0;
+
+ /**
* @brief request an update of nexus description for this mod.
*
* This requests mod information from the nexus. This is an asynchronous request,
@@ -310,6 +326,11 @@ public:
virtual MOBase::VersionInfo getNewestVersion() const = 0;
/**
+ * @brief ignore the newest version for updates
+ */
+ virtual void ignoreUpdate(bool ignore) = 0;
+
+ /**
* @brief getter for the nexus mod id
*
* @return the nexus mod id. may be 0 if the mod id isn't known or doesn't exist
@@ -495,6 +516,22 @@ public:
bool updateAvailable() const;
/**
+ * @return true if the current update is being ignored
+ */
+ virtual bool updateIgnored() const { return m_IgnoredVersion == m_NewestVersion; }
+
+ /**
+ * @brief test if there is a newer version of the mod
+ *
+ * test if there is a newer version of the mod. This does NOT cause
+ * information to be retrieved from the nexus, it will only test version information already
+ * available locally. Use checkAllForUpdate() to update this version information
+ *
+ * @return true if there is a newer version
+ **/
+ bool downgradeAvailable() const;
+
+ /**
* @brief request an update of nexus description for this mod.
*
* This requests mod information from the nexus. This is an asynchronous request,
@@ -621,6 +658,11 @@ public:
MOBase::VersionInfo getNewestVersion() const { return m_NewestVersion; }
/**
+ * @brief ignore the newest version for updates
+ */
+ void ignoreUpdate(bool ignore);
+
+ /**
* @brief getter for the installation file
*
* @return file used to install this mod from
@@ -746,6 +788,7 @@ private:
bool m_MetaInfoChanged;
MOBase::VersionInfo m_NewestVersion;
+ MOBase::VersionInfo m_IgnoredVersion;
EEndorsedState m_EndorsedState;
@@ -767,10 +810,13 @@ class ModInfoBackup : public ModInfoRegular
public:
virtual bool updateAvailable() const { return false; }
+ virtual bool updateIgnored() const { return false; }
+ virtual bool downgradeAvailable() const { return false; }
virtual bool updateNXMInfo() { return false; }
virtual void setNexusID(int) {}
virtual void endorse(bool) {}
virtual int getFixedPriority() const { return -1; }
+ virtual void ignoreUpdate(bool) {}
virtual bool canBeUpdated() const { return false; }
virtual bool canBeEnabled() const { return false; }
virtual std::vector<QString> getIniTweaks() const { return std::vector<QString>(); }
@@ -798,12 +844,15 @@ class ModInfoOverwrite : public ModInfo
public:
virtual bool updateAvailable() const { return false; }
+ virtual bool updateIgnored() const { return false; }
+ virtual bool downgradeAvailable() const { return false; }
virtual bool updateNXMInfo() { return false; }
virtual void setCategory(int, bool) {}
virtual bool setName(const QString&) { return false; }
virtual void setNotes(const QString&) {}
virtual void setNexusID(int) {}
virtual void setNewestVersion(const MOBase::VersionInfo&) {}
+ virtual void ignoreUpdate(bool) {}
virtual void setNexusDescription(const QString&) {}
virtual void setIsEndorsed(bool) {}
virtual void setNeverEndorse() {}
diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp
index 75e7e499..b4ae57ea 100644
--- a/src/modinfodialog.cpp
+++ b/src/modinfodialog.cpp
@@ -76,7 +76,6 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo
m_UTF8Codec = QTextCodec::codecForName("utf-8");
QListWidget *textFileList = findChild<QListWidget*>("textFileList");
- QListWidget *iniFileList = findChild<QListWidget*>("iniFileList");
QListWidget *iniTweaksList = findChild<QListWidget*>("iniTweaksList");
QListWidget *activeESPList = findChild<QListWidget*>("activeESPList");
QListWidget *inactiveESPList = findChild<QListWidget*>("inactiveESPList");
@@ -707,7 +706,7 @@ QString ModInfoDialog::getFileCategory(int categoryID)
void ModInfoDialog::updateVersionColor()
{
// QPalette versionColor;
- if (m_ModInfo->getVersion() < m_ModInfo->getNewestVersion()) {
+ if (m_ModInfo->getVersion() != m_ModInfo->getNewestVersion()) {
ui->versionEdit->setStyleSheet("color: red");
// versionColor.setColor(QPalette::Text, Qt::red);
ui->versionEdit->setToolTip(tr("Current Version: %1").arg(m_ModInfo->getNewestVersion().canonicalString()));
@@ -758,13 +757,7 @@ void ModInfoDialog::modDetailsUpdated(bool success)
ui->descriptionView->setHtml(tr("(description incomplete, please visit nexus)"));
}
- QString version = m_ModInfo->getNewestVersion().canonicalString();
-
- if (!version.isEmpty()) {
- m_ModInfo->setNewestVersion(version);
-
- updateVersionColor();
- }
+ updateVersionColor();
}
}
diff --git a/src/modlist.cpp b/src/modlist.cpp
index b5a7182e..7367b2ae 100644
--- a/src/modlist.cpp
+++ b/src/modlist.cpp
@@ -143,13 +143,16 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
} else if (column == COL_NAME) {
return modInfo->name();
} else if (column == COL_VERSION) {
- QString version = modInfo->getVersion().canonicalString();
- if (version.isEmpty() && modInfo->canBeUpdated()) {
- version = "?";
- } else if (version[0] == 'd') {
- version.remove(0, 1);
+ VersionInfo verInfo = modInfo->getVersion();
+ if (role == Qt::EditRole) {
+ return verInfo.canonicalString();
+ } else {
+ QString version = verInfo.displayString();
+ if (version.isEmpty() && modInfo->canBeUpdated()) {
+ version = "?";
+ }
+ return version;
}
- return version;
} else if (column == COL_PRIORITY) {
int priority = modInfo->getFixedPriority();
if (priority != INT_MIN) {
@@ -241,17 +244,18 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
result.setItalic(true);
}
} else if (column == COL_VERSION) {
- if (modInfo->updateAvailable()) {
+ if (modInfo->updateAvailable() || modInfo->downgradeAvailable()) {
result.setWeight(QFont::Bold);
}
}
return result;
} else if (role == Qt::DecorationRole) {
if (column == COL_VERSION) {
- if (modInfo->updateAvailable() &&
- modInfo->getNewestVersion().isValid()) {
+ if (modInfo->updateAvailable()) {
return QIcon(":/MO/gui/update_available");
- } else if (modInfo->getVersion().isVersionDate()) {
+ } else if (modInfo->downgradeAvailable()) {
+ return QIcon(":/MO/gui/warning");
+ } else if (modInfo->getVersion().scheme() == VersionInfo::SCHEME_DATE) {
return QIcon(":/MO/gui/version_date");
}
}
@@ -264,7 +268,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
} else if (column == COL_VERSION) {
if (!modInfo->getNewestVersion().isValid()) {
return QVariant();
- } else if (modInfo->updateAvailable()) {
+ } else if (modInfo->updateAvailable() || modInfo->downgradeAvailable()) {
return QBrush(Qt::red);
} else {
return QBrush(Qt::darkGreen);
@@ -291,7 +295,13 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
return QString();
}
} else if (column == COL_VERSION) {
- return tr("installed version: %1, newest version: %2").arg(modInfo->getVersion().canonicalString()).arg(modInfo->getNewestVersion().canonicalString());
+ QString text = tr("installed version: %1, newest version: %2").arg(modInfo->getVersion().displayString()).arg(modInfo->getNewestVersion().displayString());
+ if (modInfo->downgradeAvailable()) {
+ text += "<br>" + tr("The newest version on Nexus seems to be older than the one you have installed. This could either mean the version you have has been withdrawn "
+ "(i.e. due to a bug) or the author uses a non-standard versioning scheme and that newest version is actually newer. "
+ "Either way you may want to \"upgrade\".");
+ }
+ return text;
} else if (column == COL_CATEGORY) {
const std::set<int> &categories = modInfo->getCategories();
std::wostringstream categoryString;
diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp
index 53c03c6a..c7c3ab28 100644
--- a/src/modlistsortproxy.cpp
+++ b/src/modlistsortproxy.cpp
@@ -211,7 +211,7 @@ bool ModListSortProxy::filterMatches(ModInfo::Ptr info, bool enabled) const
if (enabled) return false;
} break;
case CategoryFactory::CATEGORY_SPECIAL_UPDATEAVAILABLE: {
- if (!info->updateAvailable()) return false;
+ if (!info->updateAvailable() && !info->downgradeAvailable()) return false;
} break;
case CategoryFactory::CATEGORY_SPECIAL_NOCATEGORY: {
if (info->getCategories().size() > 0) return false;
diff --git a/src/modlistview.cpp b/src/modlistview.cpp
index 44228d5b..1a4f6266 100644
--- a/src/modlistview.cpp
+++ b/src/modlistview.cpp
@@ -4,7 +4,7 @@
#include <QProxyStyle>
-class ModListViewStyle: public QProxyStyle{
+class ModListViewStyle: public QProxyStyle {
public:
ModListViewStyle(QStyle *style, int indentation);
@@ -37,7 +37,7 @@ void ModListViewStyle::drawPrimitive(PrimitiveElement element, const QStyleOptio
ModListView::ModListView(QWidget *parent)
: QTreeView(parent)
{
- setStyle(new ModListViewStyle(style(), indentation()));
+// setStyle(new ModListViewStyle(style(), indentation()));
}
void ModListView::dragEnterEvent(QDragEnterEvent *event)
diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp
index cd78ca4c..bee0bb44 100644
--- a/src/nexusinterface.cpp
+++ b/src/nexusinterface.cpp
@@ -68,6 +68,7 @@ void NexusBridge::nxmDescriptionAvailable(int modID, QVariant userData, QVariant
std::set<int>::iterator iter = m_RequestIDs.find(requestID);
if (iter != m_RequestIDs.end()) {
m_RequestIDs.erase(iter);
+
emit descriptionAvailable(modID, userData, resultData);
}
}
@@ -142,6 +143,7 @@ QAtomicInt NexusInterface::NXMRequestInfo::s_NextID(0);
NexusInterface::NexusInterface()
: m_NMMVersion()
{
+ atexit(&cleanup);
m_AccessManager = new NXMAccessManager(this);
m_DiskCache = new QNetworkDiskCache(this);
@@ -149,6 +151,13 @@ NexusInterface::NexusInterface()
}
+void NexusInterface::cleanup()
+{
+ delete NexusInterface::s_Instance;
+ NexusInterface::s_Instance = NULL;
+}
+
+
NXMAccessManager *NexusInterface::getAccessManager()
{
return m_AccessManager;
@@ -405,6 +414,7 @@ void NexusInterface::downloadRequestedNXM(const QString &url)
emit requestNXMDownload(url);
}
+#include <QDebug>
void NexusInterface::requestFinished(std::list<NXMRequestInfo>::iterator iter)
{
diff --git a/src/nexusinterface.h b/src/nexusinterface.h
index 0c304a71..0b53f9d0 100644
--- a/src/nexusinterface.h
+++ b/src/nexusinterface.h
@@ -294,6 +294,7 @@ private:
NexusInterface();
void nextRequest();
void requestFinished(std::list<NXMRequestInfo>::iterator iter);
+ static void cleanup();
private:
diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp
index d83ffa61..a05b8a6c 100644
--- a/src/nxmaccessmanager.cpp
+++ b/src/nxmaccessmanager.cpp
@@ -44,6 +44,14 @@ NXMAccessManager::NXMAccessManager(QObject *parent)
{
}
+NXMAccessManager::~NXMAccessManager()
+{
+ if (m_LoginReply != NULL) {
+ m_LoginReply->deleteLater();
+ m_LoginReply = NULL;
+ }
+}
+
QNetworkReply *NXMAccessManager::createRequest(
QNetworkAccessManager::Operation operation, const QNetworkRequest &request,
diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h
index b0c43978..1d8d36ab 100644
--- a/src/nxmaccessmanager.h
+++ b/src/nxmaccessmanager.h
@@ -37,6 +37,8 @@ public:
explicit NXMAccessManager(QObject *parent);
+ ~NXMAccessManager();
+
bool loggedIn() const;
void login(const QString &username, const QString &password);
diff --git a/src/organizer.pro b/src/organizer.pro
index e89b6e99..a9353361 100644
--- a/src/organizer.pro
+++ b/src/organizer.pro
@@ -183,7 +183,6 @@ INCLUDEPATH += ../shared ../archive ../uibase ../bsatk ../esptk "$(BOOSTPATH)"
LIBS += -L"$(BOOSTPATH)/stage/lib"
-
CONFIG(debug, debug|release) {
OUTDIR = $$OUT_PWD/debug
DSTDIR = $$PWD/../../outputd
@@ -294,6 +293,12 @@ OTHER_FILES += \
INCLUDEPATH += "$(ZLIBPATH)" "$(ZLIBPATH)/build" "$(BOOSTPATH)"
LIBS += -L"$(ZLIBPATH)/build" -lzlibstatic
+
+# leak detection with vld
+#INCLUDEPATH += "E:/Visual Leak Detector/include"
+#LIBS += -L"E:/Visual Leak Detector/lib/Win32"
+#DEFINES += LEAK_CHECK_WITH_VLD
+
#SOURCES += modeltest.cpp
#HEADERS += modeltest.h
#DEFINES += TEST_MODELS
diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp
index 0ed0d7f9..e730d3f4 100644
--- a/src/pluginlist.cpp
+++ b/src/pluginlist.cpp
@@ -90,6 +90,10 @@ PluginList::PluginList(QObject *parent)
}
+PluginList::~PluginList()
+{
+}
+
QString PluginList::getColumnName(int column)
{
@@ -675,8 +679,13 @@ QVariant PluginList::data(const QModelIndex &modelIndex, int role) const
} else {
QString text = tr("Origin: %1").arg(m_ESPs[index].m_OriginName);
if (m_ESPs[index].m_MasterUnset.size() > 0) {
- text += "\n" + tr("Missing Masters") + ": " + SetJoin(m_ESPs[index].m_MasterUnset, ", ");
+ text += "<br>" + tr("Missing Masters") + ": <b>" + SetJoin(m_ESPs[index].m_MasterUnset, ", ") + "</b>";
}
+ std::set<QString> enabledMasters;
+ std::set_difference(m_ESPs[index].m_Masters.begin(), m_ESPs[index].m_Masters.end(),
+ m_ESPs[index].m_MasterUnset.begin(), m_ESPs[index].m_MasterUnset.end(),
+ std::inserter(enabledMasters, enabledMasters.end()));
+ text += "<br>" + tr("Enabled Masters") + ": " + SetJoin(enabledMasters, ", ");
return text;
}
} else {
diff --git a/src/pluginlist.h b/src/pluginlist.h
index 3442a9f7..60c9be95 100644
--- a/src/pluginlist.h
+++ b/src/pluginlist.h
@@ -53,6 +53,8 @@ public:
**/
PluginList(QObject *parent = NULL);
+ ~PluginList();
+
/**
* @brief does a complete refresh of the list
*
diff --git a/src/profile.cpp b/src/profile.cpp
index 07f7010e..3da12d7d 100644
--- a/src/profile.cpp
+++ b/src/profile.cpp
@@ -185,7 +185,7 @@ void Profile::writeModlistNow(bool onlyOnTimer) const
QString fileName = getModlistFileName();
if (QFile::exists(fileName)) {
- shellDelete(QStringList(fileName));
+ shellDelete(QStringList(fileName), false, QApplication::activeModalWidget());
}
if (!file.copy(fileName)) {
@@ -238,6 +238,7 @@ void Profile::createTweakedIniFile()
if (error) {
reportError(tr("failed to create tweaked ini: %1").arg(getCurrentErrorStringA().c_str()));
}
+ qDebug("%s saved", qPrintable(QDir::toNativeSeparators(tweakedIni)));
}
diff --git a/src/selfupdater.cpp b/src/selfupdater.cpp
index 421fbeab..bdace814 100644
--- a/src/selfupdater.cpp
+++ b/src/selfupdater.cpp
@@ -126,7 +126,6 @@ void SelfUpdater::startUpdate()
void SelfUpdater::download(const QString &downloadLink, const QString &fileName)
{
- qDebug("download: %s", downloadLink.toUtf8().constData());
QNetworkAccessManager *accessManager = m_Interface->getAccessManager();
QUrl dlUrl(downloadLink);
QNetworkRequest request(dlUrl);
@@ -324,7 +323,6 @@ void SelfUpdater::nxmDescriptionAvailable(int, QVariant, QVariant resultData, in
if (m_NewestVersion.isEmpty()) {
QTimer::singleShot(5000, this, SLOT(testForUpdate()));
}
-
VersionInfo currentVersion(m_MOVersion);
VersionInfo newestVersion(m_NewestVersion);
diff --git a/src/shared/directoryentry.cpp b/src/shared/directoryentry.cpp
index bd33fef6..8380181f 100644
--- a/src/shared/directoryentry.cpp
+++ b/src/shared/directoryentry.cpp
@@ -568,8 +568,9 @@ void DirectoryEntry::removeDirRecursive()
for (auto iter = m_SubDirectories.begin(); iter != m_SubDirectories.end(); ++iter) {
(*iter)->removeDirRecursive();
+ delete *iter;
}
- m_SubDirectories.clear();
+ m_SubDirectories.clear();
}
void DirectoryEntry::removeDir(const std::wstring &path)
@@ -578,8 +579,10 @@ void DirectoryEntry::removeDir(const std::wstring &path)
if (pos == std::string::npos) {
for (auto iter = m_SubDirectories.begin(); iter != m_SubDirectories.end(); ++iter) {
if (_wcsicmp((*iter)->getName().c_str(), path.c_str()) == 0) {
- (*iter)->removeDirRecursive();
+ DirectoryEntry *entry = *iter;
+ entry->removeDirRecursive();
m_SubDirectories.erase(iter);
+ delete entry;
break;
}
}
diff --git a/src/shared/gameinfo.cpp b/src/shared/gameinfo.cpp
index 6b53450d..f74e52b4 100644
--- a/src/shared/gameinfo.cpp
+++ b/src/shared/gameinfo.cpp
@@ -40,6 +40,13 @@ GameInfo* GameInfo::s_Instance = NULL;
GameInfo::GameInfo(const std::wstring &omoDirectory, const std::wstring &gameDirectory)
: m_GameDirectory(gameDirectory), m_OrganizerDirectory(omoDirectory)
{
+ atexit(&cleanup);
+}
+
+
+void GameInfo::cleanup() {
+ delete GameInfo::s_Instance;
+ GameInfo::s_Instance = NULL;
}
diff --git a/src/shared/gameinfo.h b/src/shared/gameinfo.h
index 3e022ef4..14f52f05 100644
--- a/src/shared/gameinfo.h
+++ b/src/shared/gameinfo.h
@@ -176,9 +176,11 @@ private:
static bool identifyGame(const std::wstring &omoDirectory, const std::wstring &searchPath);
std::wstring getSpecialPath(LPCWSTR name) const;
+ static void cleanup();
+
private:
- static GameInfo* s_Instance;
+ static GameInfo *s_Instance;
std::wstring m_MyGamesDirectory;
diff --git a/src/shared/leaktrace.cpp b/src/shared/leaktrace.cpp
index 0c618b68..c3721557 100644
--- a/src/shared/leaktrace.cpp
+++ b/src/shared/leaktrace.cpp
@@ -3,6 +3,7 @@
#include <DbgHelp.h>
#include <set>
#include <map>
+#include <vector>
#include <sstream>
@@ -32,8 +33,18 @@ class StackData {
friend bool operator==(const StackData &LHS, const StackData &RHS);
friend bool operator<(const StackData &LHS, const StackData &RHS);
public:
- StackData() {
+
+ StackData()
+ : m_FunctionName("Dummy"), m_CodeLine(0)
+ {}
+ StackData(const char *functionName, int line) {
m_Count = ::CaptureStackBackTrace(FRAMES_TO_SKIP, FRAMES_TO_CAPTURE, m_Stack, &m_Hash);
+ m_FunctionName = functionName;
+ m_CodeLine = line;
+ if (m_Count == 0) {
+ // TODO in this case the hash doesn't seem to be set. This is of course not a good solution
+ m_Hash = reinterpret_cast<unsigned long>(m_FunctionName) + m_CodeLine;
+ }
}
std::string toString() const {
initDbgIfNecessary();
@@ -45,6 +56,8 @@ public:
std::ostringstream stackStream;
+ stackStream << m_FunctionName << " [" << m_CodeLine << "]\n";
+
for(unsigned int i = 0; i < m_Count; ++i) {
DWORD64 displacement = 0;
if (!::SymFromAddr(::GetCurrentProcess(), (DWORD64)m_Stack[i], &displacement, symbol)) {
@@ -59,6 +72,8 @@ private:
LPVOID m_Stack[FRAMES_TO_CAPTURE];
USHORT m_Count;
ULONG m_Hash;
+ const char *m_FunctionName;
+ int m_CodeLine;
};
bool operator==(const StackData &LHS, const StackData &RHS) {
@@ -70,10 +85,9 @@ bool operator<(const StackData &LHS, const StackData &RHS) {
}
-
static struct __TraceData {
- void regTrace(void *pointer) {
- m_Traces[reinterpret_cast<unsigned long>(pointer)] = StackData();
+ void regTrace(void *pointer, const char *functionName, int line) {
+ m_Traces[reinterpret_cast<unsigned long>(pointer)] = StackData(functionName, line);
}
void deregTrace(void *pointer) {
auto iter = m_Traces.find(reinterpret_cast<unsigned long>(pointer));
@@ -83,24 +97,30 @@ static struct __TraceData {
}
~__TraceData() {
- std::map<StackData, int> result;
+ std::map<StackData, std::vector<unsigned long> > result;
for (auto iter = m_Traces.begin(); iter != m_Traces.end(); ++iter) {
- result[iter->second] += 1;
+ result[iter->second].push_back(iter->first);
}
for (auto iter = result.begin(); iter != result.end(); ++iter) {
printf("-----------------------------------\n"
"%d objects not freed, allocated at:\n%s",
- iter->second, iter->first.toString().c_str());
+ iter->second.size(), iter->first.toString().c_str());
+ printf("Addresses: ");
+ for (int i = 0; i < (std::min<int>)(5, iter->second.size()); ++i) {
+ printf("%p, ", iter->second[i]);
+ }
+ printf("\n");
}
}
std::map<unsigned long, StackData> m_Traces;
+
} __trace;
-void LeakTrace::TraceAlloc(void *ptr)
+void LeakTrace::TraceAlloc(void *ptr, const char *functionName, int line)
{
- __trace.regTrace(ptr);
+ __trace.regTrace(ptr, functionName, line);
}
void LeakTrace::TraceDealloc(void *ptr)
diff --git a/src/shared/leaktrace.h b/src/shared/leaktrace.h
index 78764260..4985925e 100644
--- a/src/shared/leaktrace.h
+++ b/src/shared/leaktrace.h
@@ -4,14 +4,14 @@
namespace LeakTrace {
-void TraceAlloc(void *ptr);
+void TraceAlloc(void *ptr, const char *functionName, int line);
void TraceDealloc(void *ptr);
};
#ifdef TRACE_LEAKS
-#define LEAK_TRACE LeakTrace::TraceAlloc(this)
+#define LEAK_TRACE LeakTrace::TraceAlloc(this, __FUNCTION__, __LINE__)
#define LEAK_UNTRACE LeakTrace::TraceDealloc(this)
#else // TRACE_LEAKS
diff --git a/src/shared/shared.pro b/src/shared/shared.pro
index ab0bd8a0..992fd7f2 100644
--- a/src/shared/shared.pro
+++ b/src/shared/shared.pro
@@ -13,9 +13,17 @@ CONFIG += staticlib
INCLUDEPATH += ../bsatk "$(BOOSTPATH)"
+
+# only for custom leak detection
+#DEFINES += TRACE_LEAKS
+#LIBS += -lDbgHelp
+
+
CONFIG(debug, debug|release) {
- LIBS += -L$$OUT_PWD/../bsatk/debug
+ LIBS += -L$$OUT_PWD/../bsatk/debug
LIBS += -lDbgHelp
+ QMAKE_CXXFLAGS_DEBUG -= -Zi
+ QMAKE_CXXFLAGS += -Z7
} else {
LIBS += -L$$OUT_PWD/../bsatk/release
}
diff --git a/src/spawn.cpp b/src/spawn.cpp
index ab43b687..5639a78c 100644
--- a/src/spawn.cpp
+++ b/src/spawn.cpp
@@ -156,7 +156,7 @@ HANDLE startBinary(const QFileInfo &binary, const QString &arguments, const QStr
return processHandle;
}
-
+/*
ExitProxy *ExitProxy::s_Instance = NULL;
ExitProxy *ExitProxy::instance()
@@ -170,4 +170,4 @@ ExitProxy *ExitProxy::instance()
void ExitProxy::emitExit()
{
emit exit();
-}
+}*/
diff --git a/src/spawn.h b/src/spawn.h
index e0d1f958..48320fea 100644
--- a/src/spawn.h
+++ b/src/spawn.h
@@ -31,7 +31,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
* @brief a dirty little trick so we can issue a clean restart from startBinary
* @note unused
*/
-class ExitProxy : public QObject {
+/*class ExitProxy : public QObject {
Q_OBJECT
public:
static ExitProxy *instance();
@@ -42,7 +42,7 @@ private:
ExitProxy() {}
private:
static ExitProxy *s_Instance;
-};
+};*/
/**
diff --git a/src/splash.png b/src/splash.png
index 45ace8f8..0137bf72 100644
--- a/src/splash.png
+++ b/src/splash.png
Binary files differ
diff --git a/src/version.rc b/src/version.rc
index 16e006cf..16669011 100644
--- a/src/version.rc
+++ b/src/version.rc
@@ -1,7 +1,7 @@
#include "Winver.h"
-#define VER_FILEVERSION 1,0,2,0
-#define VER_FILEVERSION_STR "1,0,2,0\0"
+#define VER_FILEVERSION 1,0,4,0
+#define VER_FILEVERSION_STR "1,0,4,0\0"
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION