Compare commits

...
Author SHA1 Message Date
Tannin f3cb50057b - bugfixes to last merge
- fnis-check plugin can now be disabled
2013-10-12 13:21:37 +02:00
Tannin 5518309300 Merge 2013-10-12 12:32:37 +02:00
Tannin f22bb9d6a6 Merge 2013-10-11 23:04:44 +02:00
Tannin 382226bb46 - added new plugin to test if fnis needs to be run
- some functionality to the plugin interface to enable them to search for files&directories in the virtual FS (rudimentary atm)
- functionality for plugins to react to application being started from MO
- broken ESPs are no longer reported as popup windows but only in the log file
- bugfix: plugins couldn't store persistent data if they had no user-editable settings
2013-10-11 23:03:49 +02:00
Tannin bdf04f516c - MO now warns if a nxm-link for a wrong game was attempted instead of downloading the wrong file
- bugfix: in nxmhandler adding a new line with different game but same executable didn't work (the change was silently dropped)
2013-10-10 21:23:25 +02:00
Tannin 54c7131a5e - new toggle to display hidden downloads
- hidden downloads can be un-hidden
- the installation manager now more thoroughly cleans up the temporary directory after installation
- added SkyrimLauncher.exe to the list of auto-detected executables
- bugfix: shutting down MO while downloads where active in some occasions didn't work
- bugfix: when canceling the only active download the taskbar icon didn't return to normal
2013-10-10 19:32:01 +02:00
Tannin 15e256ef44 Added tag release v1.0.4 for changeset 7732c5d2e41d 2013-10-10 19:09:29 +02:00
Tannin b23a4885e0 - bugfix: When updating MO, if login is required, the process didn't continue automatically after login 2013-10-06 14:12:25 +02:00
Tannin 823dfd410b - option to ignore/unignore updates is now only shown if there IS an update
- window now shouldn't lose focus on win 8 2 seconds after mod information gets invalidated
- small bugfix related to new version scheme parsing
2013-10-06 13:34:34 +02:00
Tannin ba09054e6b Merge 2013-10-06 12:20:07 +02:00
Tannin 694e3ed279 bugfix: statusbar may have stayed enabled if an error occured on handling the refreshed-event 2013-10-06 12:19:46 +02:00
Tannin cffd9eb4e2 - hook.dll now doesn't inject to certain applications (currently steam, chrome and firefox)
- versioning system improved. Will now report "downgrades" for mods and support a different versioning system (requires manual switch)
- updates can now be ignored until a new version is uploaded
- new splash screen
- bugfix: a few memory leaks (shouldn't account for much)
- bugfix: result of GetModuleHandle wasn't zero-terminated in some cases
2013-10-05 14:20:48 +02:00
Tannin 640b14ef25 diagnosis plugin now warns when nitpick is installed 2013-09-30 18:33:45 +02:00
Tannin 47293827bb - download progress is now visible in task bar
- esp-tooltip now lists all masters, highlighting the missing ones
- python plugin will now report a problem if the path contains a semicolon
- leak detection now (somewaht) works around the fact that we don't always get a stack trace
- bugfix: mod meta-file is now reliably created if it was missing
- bugfix: parser for nxm-links didn't handle numbers in the mod name
- bugfix: small memory leak
2013-09-28 21:13:57 +02:00
Tannin 0a3169b808 - plugin tooltip now only lists the masters that aren't enabled (if any) 2013-09-26 19:10:44 +02:00
Tannin f4528c7aaa - bugfix: esp parsing could crash for broken/unrecognized esps
- bugfix: esp parser didn't handle oblivion esps correctly
2013-09-23 22:39:58 +02:00
Tannin 4f0a6e8b88 Added tag release v1.0.2 for changeset 0aaed2f8f48d 2013-09-22 13:24:53 +02:00
44 changed files with 713 additions and 281 deletions
+7
View File
@@ -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()
{
+4
View File
@@ -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:
};
+16 -4
View File
@@ -208,6 +208,11 @@ void DownloadListWidgetDelegate::issueRemoveFromView()
emit removeDownload(m_ContextRow, false);
}
void DownloadListWidgetDelegate::issueRestoreToView()
{
emit restoreDownload(m_ContextRow);
}
void DownloadListWidgetDelegate::issueCancel()
{
emit cancelDownload(m_ContextRow);
@@ -277,13 +282,18 @@ bool DownloadListWidgetDelegate::editorEvent(QEvent *event, QAbstractItemModel *
QMenu menu(m_View);
m_ContextRow = qobject_cast<QSortFilterProxyModel*>(model)->mapToSource(index).row();
DownloadManager::DownloadState state = m_Manager->getState(m_ContextRow);
bool hidden = m_Manager->isHidden(m_ContextRow);
if (state >= DownloadManager::STATE_READY) {
menu.addAction(tr("Install"), this, SLOT(issueInstall()));
if (m_Manager->isInfoIncomplete(m_ContextRow)) {
menu.addAction(tr("Query Info"), this, SLOT(issueQueryInfo()));
}
menu.addAction(tr("Delete"), this, SLOT(issueDelete()));
menu.addAction(tr("Remove from View"), this, SLOT(issueRemoveFromView()));
if (hidden) {
menu.addAction(tr("Un-Hide"), this, SLOT(issueRestoreToView()));
} else {
menu.addAction(tr("Remove from View"), this, SLOT(issueRemoveFromView()));
}
} else if (state == DownloadManager::STATE_DOWNLOADING){
menu.addAction(tr("Cancel"), this, SLOT(issueCancel()));
menu.addAction(tr("Pause"), this, SLOT(issuePause()));
@@ -295,9 +305,11 @@ bool DownloadListWidgetDelegate::editorEvent(QEvent *event, QAbstractItemModel *
menu.addSeparator();
menu.addAction(tr("Delete Installed..."), this, SLOT(issueDeleteCompleted()));
menu.addAction(tr("Delete All..."), this, SLOT(issueDeleteAll()));
menu.addSeparator();
menu.addAction(tr("Remove Installed..."), this, SLOT(issueRemoveFromViewCompleted()));
menu.addAction(tr("Remove All..."), this, SLOT(issueRemoveFromViewAll()));
if (!hidden) {
menu.addSeparator();
menu.addAction(tr("Remove Installed..."), this, SLOT(issueRemoveFromViewCompleted()));
menu.addAction(tr("Remove All..."), this, SLOT(issueRemoveFromViewAll()));
}
menu.exec(mouseEvent->globalPos());
event->accept();
+2
View File
@@ -65,6 +65,7 @@ signals:
void installDownload(int index);
void queryInfo(int index);
void removeDownload(int index, bool deleteFile);
void restoreDownload(int index);
void cancelDownload(int index);
void pauseDownload(int index);
void resumeDownload(int index);
@@ -83,6 +84,7 @@ private slots:
void issueInstall();
void issueDelete();
void issueRemoveFromView();
void issueRestoreToView();
void issueCancel();
void issuePause();
void issueResume();
+16 -4
View File
@@ -195,6 +195,11 @@ void DownloadListWidgetCompactDelegate::issueRemoveFromView()
emit removeDownload(m_ContextIndex.row(), false);
}
void DownloadListWidgetCompactDelegate::issueRestoreToView()
{
emit restoreDownload(m_ContextIndex.row());
}
void DownloadListWidgetCompactDelegate::issueCancel()
{
emit cancelDownload(m_ContextIndex.row());
@@ -265,13 +270,18 @@ bool DownloadListWidgetCompactDelegate::editorEvent(QEvent *event, QAbstractItem
QMenu menu;
m_ContextIndex = qobject_cast<QSortFilterProxyModel*>(model)->mapToSource(index);
DownloadManager::DownloadState state = m_Manager->getState(m_ContextIndex.row());
bool hidden = m_Manager->isHidden(m_ContextIndex.row());
if (state >= DownloadManager::STATE_READY) {
menu.addAction(tr("Install"), this, SLOT(issueInstall()));
if (m_Manager->isInfoIncomplete(m_ContextIndex.row())) {
menu.addAction(tr("Query Info"), this, SLOT(issueQueryInfo()));
}
menu.addAction(tr("Delete"), this, SLOT(issueDelete()));
menu.addAction(tr("Remove from View"), this, SLOT(issueRemoveFromView()));
if (hidden) {
menu.addAction(tr("Un-Hide"), this, SLOT(issueRestoreToView()));
} else {
menu.addAction(tr("Remove from View"), this, SLOT(issueRemoveFromView()));
}
} else if (state == DownloadManager::STATE_DOWNLOADING){
menu.addAction(tr("Cancel"), this, SLOT(issueCancel()));
menu.addAction(tr("Pause"), this, SLOT(issuePause()));
@@ -283,9 +293,11 @@ bool DownloadListWidgetCompactDelegate::editorEvent(QEvent *event, QAbstractItem
menu.addSeparator();
menu.addAction(tr("Delete Installed..."), this, SLOT(issueDeleteCompleted()));
menu.addAction(tr("Delete All..."), this, SLOT(issueDeleteAll()));
menu.addSeparator();
menu.addAction(tr("Remove Installed..."), this, SLOT(issueRemoveFromViewCompleted()));
menu.addAction(tr("Remove All..."), this, SLOT(issueRemoveFromViewAll()));
if (!hidden) {
menu.addSeparator();
menu.addAction(tr("Remove Installed..."), this, SLOT(issueRemoveFromViewCompleted()));
menu.addAction(tr("Remove All..."), this, SLOT(issueRemoveFromViewAll()));
}
menu.exec(mouseEvent->globalPos());
event->accept();
+2
View File
@@ -65,6 +65,7 @@ signals:
void installDownload(int index);
void queryInfo(int index);
void removeDownload(int index, bool deleteFile);
void restoreDownload(int index);
void cancelDownload(int index);
void pauseDownload(int index);
void resumeDownload(int index);
@@ -83,6 +84,7 @@ private slots:
void issueInstall();
void issueDelete();
void issueRemoveFromView();
void issueRestoreToView();
void issueCancel();
void issuePause();
void issueResume();
+69 -11
View File
@@ -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,18 +64,21 @@ 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;
}
DownloadManager::DownloadInfo *DownloadManager::DownloadInfo::createFromMeta(const QString &filePath)
DownloadManager::DownloadInfo *DownloadManager::DownloadInfo::createFromMeta(const QString &filePath, bool showHidden)
{
DownloadInfo *info = new DownloadInfo;
QString metaFileName = filePath + ".meta";
QSettings metaFile(metaFileName, QSettings::IniFormat);
if (metaFile.value("removed", false).toBool()) {
if (!showHidden && metaFile.value("removed", false).toBool()) {
return NULL;
} else {
info->m_Hidden = metaFile.value("removed", false).toBool();
}
QString fileName = QFileInfo(filePath).fileName();
@@ -105,6 +109,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();
@@ -148,7 +153,7 @@ QString DownloadManager::DownloadInfo::currentURL()
DownloadManager::DownloadManager(NexusInterface *nexusInterface, QObject *parent)
: IDownloadManager(parent), m_NexusInterface(nexusInterface), m_DirWatcher()
: IDownloadManager(parent), m_NexusInterface(nexusInterface), m_DirWatcher(), m_ShowHidden(false)
{
connect(&m_DirWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(directoryChanged(QString)));
}
@@ -159,6 +164,7 @@ DownloadManager::~DownloadManager()
for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); iter != m_ActiveDownloads.end(); ++iter) {
delete *iter;
}
m_ActiveDownloads.clear();
}
@@ -184,13 +190,15 @@ void DownloadManager::pauseAll()
::Sleep(100);
bool done = false;
QTime startTime = QTime::currentTime();
// further loops: busy waiting for all downloads to complete. This could be neater...
while (!done) {
while (!done && (startTime.secsTo(QTime::currentTime()) < 5)) {
QCoreApplication::processEvents();
done = true;
foreach (DownloadInfo *info, m_ActiveDownloads) {
if ((info->m_State < STATE_CANCELED) ||
(info->m_State != STATE_FETCHINGFILEINFO) || (info->m_State != STATE_FETCHINGMODINFO)) {
(info->m_State == STATE_FETCHINGFILEINFO) ||
(info->m_State == STATE_FETCHINGMODINFO)) {
done = false;
break;
}
@@ -226,6 +234,12 @@ void DownloadManager::setSupportedExtensions(const QStringList &extensions)
refreshList();
}
void DownloadManager::setShowHidden(bool showHidden)
{
m_ShowHidden = showHidden;
refreshList();
}
void DownloadManager::refreshList()
{
// remove finished downloads
@@ -263,7 +277,7 @@ void DownloadManager::refreshList()
QString fileName = QDir::fromNativeSeparators(m_OutputDirectory) + "/" + file;
DownloadInfo *info = DownloadInfo::createFromMeta(fileName);
DownloadInfo *info = DownloadInfo::createFromMeta(fileName, m_ShowHidden);
if (info != NULL) {
m_ActiveDownloads.push_front(info);
}
@@ -362,6 +376,15 @@ void DownloadManager::startDownload(QNetworkReply *reply, DownloadInfo *newDownl
void DownloadManager::addNXMDownload(const QString &url)
{
NXMUrl nxmInfo(url);
QString managedGame = ToQString(MOShared::GameInfo::instance().getGameShortName());
if (nxmInfo.game().compare(managedGame, Qt::CaseInsensitive) != 0) {
QMessageBox::information(NULL, tr("Wrong Game"), tr("The download link is for a mod for \"%1\" but this instance of MO "
"has been set up for \"%2\".").arg(nxmInfo.game()).arg(managedGame), QMessageBox::Ok);
return;
}
m_RequestIDs.insert(m_NexusInterface->requestFileInfo(nxmInfo.getModId(), nxmInfo.getFileId(), this, QVariant()));
}
@@ -433,6 +456,22 @@ void DownloadManager::refreshAlphabeticalTranslation()
}
void DownloadManager::restoreDownload(int index)
{
if ((index < 0) || (index >= m_ActiveDownloads.size())) {
throw MyException(tr("invalid index"));
}
DownloadInfo *download = m_ActiveDownloads.at(index);
download->m_Hidden = false;
QString filePath = m_OutputDirectory + "/" + download->m_FileName;
QSettings metaSettings(filePath.append(".meta"), QSettings::IniFormat);
metaSettings.setValue("removed", false);
}
void DownloadManager::removeDownload(int index, bool deleteFile)
{
try {
@@ -488,9 +527,13 @@ void DownloadManager::pauseDownload(int index)
return;
}
if (m_ActiveDownloads.at(index)->m_State == STATE_DOWNLOADING) {
setState(m_ActiveDownloads.at(index), STATE_PAUSING);
qDebug("pausing %d - %s", index, m_ActiveDownloads[index]->m_FileName.toUtf8().constData());
DownloadInfo *info = m_ActiveDownloads.at(index);
if (info->m_State == STATE_DOWNLOADING) {
setState(info, STATE_PAUSING);
qDebug("pausing %d - %s", index, info->m_FileName.toUtf8().constData());
} else if ((info->m_State == STATE_FETCHINGMODINFO) || (info->m_State == STATE_FETCHINGFILEINFO)) {
setState(info, STATE_READY);
}
}
@@ -667,6 +710,14 @@ int DownloadManager::getModID(int index) const
return m_ActiveDownloads.at(index)->m_ModID;
}
bool DownloadManager::isHidden(int index) const
{
if ((index < 0) || (index >= m_ActiveDownloads.size())) {
throw MyException(tr("invalid index"));
}
return m_ActiveDownloads.at(index)->m_Hidden;
}
NexusInfo DownloadManager::getNexusInfo(int index) const
{
@@ -805,6 +856,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);
}
@@ -838,6 +890,7 @@ void DownloadManager::createMetaFile(DownloadInfo *info)
metaFile.setValue("uninstalled", info->m_State == DownloadManager::STATE_UNINSTALLED);
metaFile.setValue("paused", (info->m_State == DownloadManager::STATE_PAUSED) ||
(info->m_State == DownloadManager::STATE_ERROR));
metaFile.setValue("removed", info->m_Hidden);
// slightly hackish...
for (int i = 0; i < m_ActiveDownloads.size(); ++i) {
@@ -946,7 +999,7 @@ void DownloadManager::nxmFilesAvailable(int, QVariant userData, QVariant resultD
}
void DownloadManager::nxmFileInfoAvailable(int modID, int fileID, QVariant, QVariant resultData, int requestID)
void DownloadManager::nxmFileInfoAvailable(int modID, int fileID, QVariant userData, QVariant resultData, int requestID)
{
std::set<int>::iterator idIter = m_RequestIDs.find(requestID);
if (idIter == m_RequestIDs.end()) {
@@ -963,7 +1016,11 @@ void DownloadManager::nxmFileInfoAvailable(int modID, int fileID, QVariant, QVar
info.m_Version = result["version"].toString();
info.m_FileName = result["uri"].toString();
m_RequestIDs.insert(m_NexusInterface->requestDownloadURL(modID, fileID, this, qVariantFromValue(info)));
if (userData.isValid()) {
m_RequestIDs.insert(m_NexusInterface->requestDownloadURL(modID, fileID, this, qVariantFromValue(info), userData.toString()));
} else {
m_RequestIDs.insert(m_NexusInterface->requestDownloadURL(modID, fileID, this, qVariantFromValue(info)));
}
}
@@ -1105,6 +1162,7 @@ void DownloadManager::downloadFinished()
QByteArray data = info->m_Reply->readAll();
info->m_Output.write(data);
info->m_Output.close();
TaskProgressManager::instance().forgetMe(info->m_TaskProgressId);
bool error = false;
+26 -2
View File
@@ -98,10 +98,14 @@ private:
int m_Tries;
bool m_ReQueried;
quint32 m_TaskProgressId;
NexusInfo m_NexusInfo;
bool m_Hidden;
static DownloadInfo *createNew(const NexusInfo &nexusInfo, int modID, int fileID, const QStringList &URLs);
static DownloadInfo *createFromMeta(const QString &filePath);
static DownloadInfo *createFromMeta(const QString &filePath, bool showHidden);
/**
* @brief rename the file
@@ -121,7 +125,7 @@ private:
private:
static unsigned int s_NextDownloadID;
private:
DownloadInfo() : m_TotalSize(0), m_ReQueried(false) {}
DownloadInfo() : m_TotalSize(0), m_ReQueried(false), m_Hidden(false) {}
};
public:
@@ -166,6 +170,11 @@ public:
*/
void setSupportedExtensions(const QStringList &extensions);
/**
* @brief sets whether hidden files are to be shown after all
*/
void setShowHidden(bool showHidden);
/**
* @brief download from an already open network connection
*
@@ -261,6 +270,13 @@ public:
**/
int getModID(int index) const;
/**
* @brief determine if the specified file is supposed to be hidden
* @param index index of the file to look up
* @return true if the specified file is supposed to be hidden
*/
bool isHidden(int index) const;
/**
* @brief retrieve all nexus info of the download specified by index
*
@@ -350,6 +366,12 @@ public slots:
**/
void removeDownload(int index, bool deleteFile);
/**
* @brief restores the specified download to view (which was previously hidden
* @param index index of the download to restore
*/
void restoreDownload(int index);
/**
* @brief cancel the specified download. This will lead to the corresponding file to be deleted
*
@@ -434,6 +456,8 @@ private:
std::map<QString, int> m_DownloadFails;
bool m_ShowHidden;
};
#endif // DOWNLOADMANAGER_H
+32 -58
View File
@@ -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;
@@ -183,11 +184,7 @@ bool InstallationManager::unpackSingleFile(const QString &fileName)
QString InstallationManager::extractFile(const QString &fileName)
{
if (unpackSingleFile(fileName)) {
QString tempFileName = QDir::tempPath().append("/").append(QFileInfo(fileName).fileName());
m_FilesToDelete.insert(tempFileName);
return tempFileName;
return QDir::tempPath().append("/").append(QFileInfo(fileName).fileName());
} else {
return QString();
}
@@ -570,52 +567,39 @@ bool InstallationManager::doInstall(GuessedValue<QString> &modName, int modID,
}
void InstallationManager::openFile(const QString &fileName)
{
unpackSingleFile(fileName);
QString tempFileName = QDir::tempPath().append("/").append(QFileInfo(fileName).fileName());
SHELLEXECUTEINFOW execInfo;
memset(&execInfo, 0, sizeof(SHELLEXECUTEINFOW));
execInfo.cbSize = sizeof(SHELLEXECUTEINFOW);
execInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
execInfo.lpVerb = L"open";
std::wstring fileNameW = ToWString(tempFileName);
execInfo.lpFile = fileNameW.c_str();
execInfo.nShow = SW_SHOWNORMAL;
if (!::ShellExecuteExW(&execInfo)) {
qCritical("failed to spawn %s: %d", tempFileName.toUtf8().constData(), ::GetLastError());
}
m_FilesToDelete.insert(tempFileName);
}
// copy and pasted from mo_dll
bool EndsWith(LPCWSTR string, LPCWSTR subString)
{
size_t slen = wcslen(string);
size_t len = wcslen(subString);
if (slen < len) {
return false;
}
for (size_t i = 0; i < len; ++i) {
if (towlower(string[slen - len + i]) != towlower(subString[i])) {
return false;
}
}
return true;
}
bool InstallationManager::wasCancelled()
{
return m_CurrentArchive->getLastError() == Archive::ERROR_EXTRACT_CANCELLED;
}
void InstallationManager::postInstallCleanup() const
{
m_CurrentArchive->close();
// directories we may want to remove. sorted from longest to shortest to ensure we remove subdirectories first.
auto longestFirst = [](const QString &LHS, const QString &RHS) -> bool {
if (LHS.size() != RHS.size()) return LHS.size() > RHS.size();
else return LHS < RHS;
};
std::set<QString, std::function<bool(const QString&, const QString&)>> directoriesToRemove(longestFirst);
// clean up temp files
// TODO: this doesn't yet remove directories. Also, the files may be left there if this point isn't reached
foreach (const QString &tempFile, m_TempFilesToDelete) {
QFileInfo fileInfo(QDir::tempPath() + "/" + tempFile);
QFile::remove(fileInfo.absoluteFilePath());
directoriesToRemove.insert(fileInfo.absolutePath());
}
// try to delete each directory we had temporary files in. the call fails for non-empty directories which is ok
foreach (const QString &dir, directoriesToRemove) {
QDir().rmdir(dir);
}
}
bool InstallationManager::install(const QString &fileName, GuessedValue<QString> &modName, bool &hasIniTweaks)
{
QFileInfo fileInfo(fileName);
@@ -674,12 +658,9 @@ bool InstallationManager::install(const QString &fileName, GuessedValue<QString>
bool archiveOpen = m_CurrentArchive->open(ToWString(QDir::toNativeSeparators(fileName)).c_str(),
new MethodCallback<InstallationManager, void, LPSTR>(this, &InstallationManager::queryPassword));
ON_BLOCK_EXIT([this] {
this->m_CurrentArchive->close();
});
DirectoryTree *filesTree = archiveOpen ? createFilesTree() : NULL;
ON_BLOCK_EXIT(std::bind(&InstallationManager::postInstallCleanup, this));
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 +685,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;
@@ -729,13 +710,6 @@ bool InstallationManager::install(const QString &fileName, GuessedValue<QString>
qPrintable(installer->name()), e.what());
}
// clean up temp files
// TODO: this doesn't yet remove directories. Also, the files may be left there if this point isn't reached
foreach (const QString &tempFile, m_TempFilesToDelete) {
QFile::remove(QDir::tempPath() + "/" + tempFile);
}
// act upon the installation result. at this point the files have already been
// extracted to the correct location
switch (installResult) {
+1 -4
View File
@@ -168,9 +168,7 @@ private:
bool ensureValidModName(MOBase::GuessedValue<QString> &name) const;
private slots:
void openFile(const QString &fileName);
void postInstallCleanup() const;
private:
@@ -202,7 +200,6 @@ private:
QProgressDialog m_InstallationProgress;
std::set<QString> m_FilesToDelete;
std::set<QString> m_TempFilesToDelete;
};
+56 -44
View File
@@ -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>
@@ -428,63 +433,70 @@ int main(int argc, char *argv[])
qDebug("initializing tutorials");
TutorialManager::init(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getTutorialDir())).append("/"));
application.setStyleFile(settings.value("Settings/style", "").toString());
if (!application.setStyleFile(settings.value("Settings/style", "").toString())) {
// disable invalid stylesheet
settings.setValue("Settings/style", "");
}
// 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.startApplication(exeName, arguments, QString(), selectedProfileName);
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;
+164 -33
View File
@@ -111,6 +111,8 @@ using namespace MOBase;
using namespace MOShared;
static bool isOnline()
{
QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
@@ -139,18 +141,17 @@ 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()),
m_CurrentProfile(NULL), m_AskForNexusPW(false), m_LoginAttempted(false),
m_ArchivesInit(false), m_ContextItem(NULL), m_ContextAction(NULL), m_CurrentSaveView(NULL),
m_GameInfo(new GameInfoImpl())
m_GameInfo(new GameInfoImpl()), m_AboutToRun()
{
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 +257,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 +414,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());
@@ -1277,10 +1278,15 @@ HANDLE MainWindow::spawnBinaryDirect(const QFileInfo &binary, const QString &arg
QCoreApplication::processEvents();
}
return startBinary(binary, arguments, profileName, m_Settings.logLevel(), currentDirectory, true);
if (m_AboutToRun(binary.absoluteFilePath())) {
return startBinary(binary, arguments, profileName, m_Settings.logLevel(), currentDirectory, true);
} else {
qDebug("start of \"%s\" canceled by plugin", qPrintable(binary.absoluteFilePath()));
return INVALID_HANDLE_VALUE;
}
}
/*
void MainWindow::spawnProgram(const QString &fileName, const QString &argumentsArg,
const QString &profileName, const QDir &currentDirectory)
{
@@ -1300,7 +1306,7 @@ void MainWindow::spawnProgram(const QString &fileName, const QString &argumentsA
}
spawnBinaryDirect(binary, arguments, profileName, currentDirectory, steamAppID);
}
*/
void MainWindow::spawnBinary(const QFileInfo &binary, const QString &arguments, const QDir &currentDirectory, bool closeAfterStart, const QString &steamAppID)
{
@@ -1330,6 +1336,7 @@ void MainWindow::spawnBinary(const QFileInfo &binary, const QString &arguments,
QFile::remove(m_CurrentProfile->getLoadOrderFileName());
}
dialog->hide();
dialog->deleteLater();
}
}
}
@@ -1499,6 +1506,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;
}
}
}
@@ -1893,7 +1902,6 @@ void MainWindow::activateProxy(bool activate)
busyDialog.hide();
}
void MainWindow::readSettings()
{
QSettings settings(ToQString(GameInfo::instance().getIniFilename()), QSettings::IniFormat);
@@ -2004,6 +2012,10 @@ void MainWindow::on_tabWidget_currentChanged(int index)
void MainWindow::installMod(const QString &fileName)
{
if (m_CurrentProfile == NULL) {
return;
}
bool hasIniTweaks = false;
GuessedValue<QString> modName;
m_CurrentProfile->writeModlistNow();
@@ -2047,11 +2059,86 @@ QString MainWindow::resolvePath(const QString &fileName) const
}
}
QStringList MainWindow::listDirectories(const QString &directoryName) const
{
QStringList result;
DirectoryEntry *dir = m_DirectoryStructure->findSubDirectoryRecursive(ToWString(directoryName));
if (dir != NULL) {
std::vector<DirectoryEntry*>::iterator current, end;
dir->getSubDirectories(current, end);
for (; current != end; ++current) {
result.append(ToQString((*current)->getName()));
}
}
return result;
}
QStringList MainWindow::findFiles(const QString &path, const std::function<bool(const QString&)> &filter) const
{
QStringList result;
DirectoryEntry *dir = m_DirectoryStructure->findSubDirectoryRecursive(ToWString(path));
if (dir != NULL) {
std::vector<FileEntry::Ptr> files = dir->getFiles();
foreach (FileEntry::Ptr file, files) {
if (filter(ToQString(file->getName()))) {
result.append(ToQString(file->getFullPath()));
}
}
} else {
qWarning("directory %s not found", qPrintable(path));
}
return result;
}
IDownloadManager *MainWindow::downloadManager()
{
return &m_DownloadManager;
}
HANDLE MainWindow::startApplication(const QString &executable, const QStringList &args, const QString &cwd, const QString &profile)
{
QFileInfo binary;
QString arguments = args.join(" ");
QString currentDirectory = cwd;
QString profileName = (profile.length() > 0) ? profile : m_CurrentProfile->getName();
QString steamAppID;
if (executable.contains('\\') || executable.contains('/')) {
// file path
binary = QFileInfo(executable);
if (binary.isRelative()) {
// relative path, should be relative to game directory
binary = QFileInfo(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory())) + "/" + executable);
}
if (cwd.length() == 0) {
currentDirectory = binary.absolutePath();
}
} else {
// only a file name, search executables list
try {
const Executable &exe = m_ExecutablesList.find(executable);
steamAppID = exe.m_SteamAppID;
if (arguments == "") {
arguments = exe.m_Arguments;
}
binary = exe.m_BinaryInfo;
if (cwd.length() == 0) {
currentDirectory = exe.m_WorkingDirectory;
}
} catch (const std::runtime_error&) {
qWarning("\"%s\" not set up as executable", executable.toUtf8().constData());
return INVALID_HANDLE_VALUE;
}
}
return spawnBinaryDirect(binary, arguments, profileName, currentDirectory, steamAppID);
}
bool MainWindow::onAboutToRun(const std::function<bool (const QString &)> &func)
{
auto conn = m_AboutToRun.connect(func);
return conn.connected();
}
std::vector<unsigned int> MainWindow::activeProblems() const
{
std::vector<unsigned int> problems;
@@ -2383,6 +2470,8 @@ void MainWindow::refresher_progress(int percent)
void MainWindow::directory_refreshed()
{
statusBar()->hide();
DirectoryEntry *newStructure = m_DirectoryRefresher.getDirectoryStructure();
if (newStructure != NULL) {
DirectoryEntry *oldStructure = m_DirectoryStructure;
@@ -2400,7 +2489,6 @@ void MainWindow::directory_refreshed()
refreshLists();
}
// m_RefreshProgress->setVisible(false);
statusBar()->hide();
// some problem-reports may rely on the virtual directory tree so they need to be updated
// now
@@ -3065,7 +3153,6 @@ void MainWindow::openExplorer_clicked()
::ShellExecuteW(NULL, L"explore", ToWString(modInfo->absolutePath()).c_str(), NULL, NULL, SW_SHOWNORMAL);
}
void MainWindow::information_clicked()
{
try {
@@ -3075,7 +3162,6 @@ void MainWindow::information_clicked()
}
}
void MainWindow::syncOverwrite()
{
ModInfo::Ptr modInfo = ModInfo::getByIndex(m_ContextRow);
@@ -3087,7 +3173,6 @@ void MainWindow::syncOverwrite()
}
}
void MainWindow::createModFromOverwrite()
{
GuessedValue<QString> name;
@@ -3121,14 +3206,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()) {
@@ -3151,7 +3234,6 @@ void MainWindow::on_modList_doubleClicked(const QModelIndex &index)
}
}
bool MainWindow::addCategories(QMenu *menu, int targetID)
{
ModInfo::Ptr modInfo = ModInfo::getByIndex(m_ContextRow);
@@ -3190,7 +3272,6 @@ bool MainWindow::addCategories(QMenu *menu, int targetID)
return childEnabled;
}
void MainWindow::saveCategoriesFromMenu(QMenu *menu, int modRow)
{
ModInfo::Ptr modInfo = ModInfo::getByIndex(modRow);
@@ -3207,7 +3288,6 @@ void MainWindow::saveCategoriesFromMenu(QMenu *menu, int modRow)
}
}
void MainWindow::saveCategories()
{
QMenu *menu = qobject_cast<QMenu*>(sender());
@@ -3251,8 +3331,6 @@ void MainWindow::saveCategories()
refreshFilters();
}
void MainWindow::savePrimaryCategory()
{
QMenu *menu = qobject_cast<QMenu*>(sender());
@@ -3277,7 +3355,6 @@ void MainWindow::savePrimaryCategory()
}
}
void MainWindow::checkModsForUpdates()
{
statusBar()->show();
@@ -3295,6 +3372,45 @@ void MainWindow::checkModsForUpdates()
}
}
void MainWindow::changeVersioningScheme() {
if (QMessageBox::question(this, tr("Continue?"),
tr("The versioning scheme decides which version is considered newer than another.\n"
"This function will guess the versioning scheme under the assumption that the installed version is outdated."),
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)
{
@@ -3316,7 +3432,6 @@ void MainWindow::addPrimaryCategoryCandidates(QMenu *primaryCategoryMenu, ModInf
}
}
void MainWindow::addPrimaryCategoryCandidates()
{
QMenu *menu = qobject_cast<QMenu*>(sender());
@@ -3330,7 +3445,6 @@ void MainWindow::addPrimaryCategoryCandidates()
addPrimaryCategoryCandidates(menu, modInfo);
}
void MainWindow::enableVisibleMods()
{
if (QMessageBox::question(NULL, tr("Confirm"), tr("Really enable all visible mods?"),
@@ -3339,7 +3453,6 @@ void MainWindow::enableVisibleMods()
}
}
void MainWindow::disableVisibleMods()
{
if (QMessageBox::question(NULL, tr("Confirm"), tr("Really disable all visible mods?"),
@@ -3348,7 +3461,6 @@ void MainWindow::disableVisibleMods()
}
}
void MainWindow::exportModListCSV()
{
SelectionDialog selection(tr("Choose what to export"));
@@ -3403,7 +3515,6 @@ void MainWindow::exportModListCSV()
}
}
void addMenuAsPushButton(QMenu *menu, QMenu *subMenu)
{
QPushButton *pushBtn = new QPushButton(subMenu->title());
@@ -3413,13 +3524,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;
@@ -3458,6 +3569,19 @@ 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->updateAvailable() || info->downgradeAvailable()) {
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()));
@@ -4185,6 +4309,7 @@ void MainWindow::on_actionUpdate_triggered()
(m_AskForNexusPW && queryLogin(username, password)))) {
NexusInterface::instance()->getAccessManager()->login(username, password);
m_LoginAttempted = true;
m_PostLoginTasks.push_back([&](MainWindow*) { m_Updater.startUpdate(); });
} else {
m_Updater.startUpdate();
}
@@ -4204,9 +4329,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);
@@ -4221,6 +4346,7 @@ void MainWindow::updateDownloadListDelegate()
connect(ui->downloadView->itemDelegate(), SIGNAL(installDownload(int)), this, SLOT(installDownload(int)));
connect(ui->downloadView->itemDelegate(), SIGNAL(queryInfo(int)), &m_DownloadManager, SLOT(queryInfo(int)));
connect(ui->downloadView->itemDelegate(), SIGNAL(removeDownload(int, bool)), &m_DownloadManager, SLOT(removeDownload(int, bool)));
connect(ui->downloadView->itemDelegate(), SIGNAL(restoreDownload(int)), &m_DownloadManager, SLOT(restoreDownload(int)));
connect(ui->downloadView->itemDelegate(), SIGNAL(cancelDownload(int)), &m_DownloadManager, SLOT(cancelDownload(int)));
connect(ui->downloadView->itemDelegate(), SIGNAL(pauseDownload(int)), &m_DownloadManager, SLOT(pauseDownload(int)));
connect(ui->downloadView->itemDelegate(), SIGNAL(resumeDownload(int)), &m_DownloadManager, SLOT(resumeDownload(int)));
@@ -4264,7 +4390,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")) {
@@ -4691,3 +4817,8 @@ void MainWindow::on_linkButton_pressed()
ui->linkButton->menu()->actions().at(1)->setIcon(linkDesktopFile.exists() ? removeIcon : addIcon);
ui->linkButton->menu()->actions().at(2)->setIcon(linkMenuFile.exists() ? removeIcon : addIcon);
}
void MainWindow::on_showHiddenBox_toggled(bool checked)
{
m_DownloadManager.setShowHidden(checked);
}
+36 -2
View File
@@ -50,6 +50,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "savegameinfowidgetgamebryo.h"
#include <guessedvalue.h>
#include <directoryentry.h>
#include <boost/signals2.hpp>
namespace Ui {
class MainWindow;
@@ -64,6 +65,28 @@ class MainWindow : public QMainWindow, public MOBase::IOrganizer, public MOBase:
Q_OBJECT
Q_INTERFACES(MOBase::IPluginDiagnose)
private:
struct SignalCombinerAnd
{
typedef bool result_type;
template<typename InputIterator>
bool operator()(InputIterator first, InputIterator last) const
{
while (first != last) {
if (!(*first)) {
return false;
}
++first;
}
return true;
}
};
public:
typedef boost::signals2::signal<bool (const QString&), SignalCombinerAnd> SignalAboutToRunApplication;
public:
explicit MainWindow(const QString &exeName, QSettings &initSettings, QWidget *parent = 0);
~MainWindow();
@@ -89,8 +112,8 @@ public:
void createFirstProfile();
void spawnProgram(const QString &fileName, const QString &argumentsArg,
const QString &profileName, const QDir &currentDirectory);
/* void spawnProgram(const QString &fileName, const QString &argumentsArg,
const QString &profileName, const QDir &currentDirectory);*/
void loadPlugins();
@@ -111,7 +134,11 @@ public:
virtual QString pluginDataPath() const;
virtual void installMod(const QString &fileName);
virtual QString resolvePath(const QString &fileName) const;
virtual QStringList listDirectories(const QString &directoryName) const;
virtual QStringList findFiles(const QString &path, const std::function<bool(const QString &)> &filter) const;
virtual MOBase::IDownloadManager *downloadManager();
virtual HANDLE startApplication(const QString &executable, const QStringList &args = QStringList(), const QString &cwd = "", const QString &profile = "");
virtual bool onAboutToRun(const std::function<bool(const QString&)> &func);
virtual std::vector<unsigned int> activeProblems() const;
virtual QString shortDescription(unsigned int key) const;
@@ -320,6 +347,8 @@ private:
QFile m_PluginsCheck;
SignalAboutToRunApplication m_AboutToRun;
private slots:
void showMessage(const QString &message);
@@ -466,6 +495,10 @@ private slots:
void removeFromToolbar();
void overwriteClosed(int);
void changeVersioningScheme();
void ignoreUpdate();
void unignoreUpdate();
private slots: // ui slots
// actions
void on_actionAdd_Profile_triggered();
@@ -498,6 +531,7 @@ private slots: // ui slots
void on_groupCombo_currentIndexChanged(int index);
void on_categoriesList_itemSelectionChanged();
void on_linkButton_pressed();
void on_showHiddenBox_toggled(bool checked);
};
#endif // MAINWINDOW_H
+8 -1
View File
@@ -968,7 +968,7 @@ p, li { white-space: pre-wrap; }
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,2">
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0,2">
<item>
<widget class="QCheckBox" name="compactBox">
<property name="text">
@@ -976,6 +976,13 @@ p, li { white-space: pre-wrap; }
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="showHiddenBox">
<property name="text">
<string>Show Hidden</string>
</property>
</widget>
</item>
<item>
<widget class="MOBase::LineEditClear" name="downloadFilterEdit">
<property name="placeholderText">
+5 -1
View File
@@ -32,7 +32,7 @@ MOApplication::MOApplication(int argc, char **argv)
}
void MOApplication::setStyleFile(const QString &styleName)
bool MOApplication::setStyleFile(const QString &styleName)
{
// remove all files from watch
QStringList currentWatch = m_StyleWatcher.files();
@@ -42,11 +42,15 @@ void MOApplication::setStyleFile(const QString &styleName)
// set new stylesheet or clear it
if (styleName.length() != 0) {
QString styleSheetName = applicationDirPath() + "/" + MOBase::ToQString(AppConfig::stylesheetsPath()) + "/" + styleName;
if (!QFile::exists(styleSheetName)) {
return false;
}
m_StyleWatcher.addPath(styleSheetName);
updateStyle(styleSheetName);
} else {
setStyleSheet("");
}
return true;
}
+30 -30
View File
@@ -17,33 +17,33 @@ 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 MOAPPLICATION_H
#define MOAPPLICATION_H
#include <QApplication>
#include <QFileSystemWatcher>
class MOApplication : public QApplication {
Q_OBJECT
public:
MOApplication(int argc, char **argv);
virtual bool notify (QObject *receiver, QEvent *event);
public slots:
void setStyleFile(const QString &style);
private slots:
void updateStyle(const QString &fileName);
private:
QFileSystemWatcher m_StyleWatcher;
};
#endif // MOAPPLICATION_H
#ifndef MOAPPLICATION_H
#define MOAPPLICATION_H
#include <QApplication>
#include <QFileSystemWatcher>
class MOApplication : public QApplication {
Q_OBJECT
public:
MOApplication(int argc, char **argv);
virtual bool notify (QObject *receiver, QEvent *event);
public slots:
bool setStyleFile(const QString &style);
private slots:
void updateStyle(const QString &fileName);
private:
QFileSystemWatcher m_StyleWatcher;
};
#endif // MOAPPLICATION_H
+44 -25
View File
@@ -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
{
+49
View File
@@ -192,6 +192,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.
*
@@ -309,6 +325,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
*
@@ -494,6 +515,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.
*
@@ -620,6 +657,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
*
@@ -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() {}
+2 -9
View File
@@ -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();
}
}
+21 -12
View File
@@ -143,11 +143,12 @@ 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();
QString version = verInfo.displayString();
if (role != Qt::EditRole) {
if (version.isEmpty() && modInfo->canBeUpdated()) {
version = "?";
}
}
return version;
} else if (column == COL_PRIORITY) {
@@ -241,17 +242,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 +266,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 +293,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;
@@ -395,7 +403,8 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role)
} break;
case COL_VERSION: {
ModInfo::Ptr info = ModInfo::getByIndex(modID);
VersionInfo version(value.toString());
VersionInfo::VersionScheme scheme = info->getVersion().scheme();
VersionInfo version(value.toString(), scheme);
if (version.isValid()) {
info->setVersion(version);
return true;

Some files were not shown because too many files have changed in this diff Show More