Compare commits

...
Author SHA1 Message Date
Tannin bc7c42dbe8 - directories in data-view are now sorted
- questionbox with selection memory is now exposed to plugins
- the choice to run fnis from the checker can now be memorized
2013-10-20 16:51:40 +02:00
Tannin 9a03783f49 - tooltip on download list now contains the file name
- bugfix: when refreshing the directory tree conflict information wasn't immediately refreshed (including on start)
- bugfix: dataChanged events wasn't emitted when user changed the modlist
- bugfix: file patterns in checkfnis plugin weren't completely correct
2013-10-18 23:35:38 +02:00
Tannin d73b1e38c8 - mod sorting now always uses priority as secondary sorting
- added missing ipluginlist.h
2013-10-17 19:21:22 +02:00
Tannin b47c89661e - plugin (esp/esm) list is now exposed to plugins (read-only functionality right now)
- integrated fomod installer now supports file dependencies
- bugfix: integrated fomod installer crashed if the installer had no optiosn´´ns
2013-10-16 23:04:03 +02:00
Tannin 0b84cc3d45 Merge 2013-10-16 19:34:56 +02:00
Tannin 1bf3cc585e - nmm importer now also transfers category, endorsement state and lastest version information
- nmm importer should now always determine the correct nexus id
- nmm importer will now correctly restore overwritten files for imported mods
2013-10-16 19:32:59 +02:00
Tannin eae275cc84 Added tag release v1.0.5 for changeset c6a9d2ab2d6c 2013-10-15 23:34:16 +02:00
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
48 changed files with 877 additions and 605 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:
};
+4 -2
View File
@@ -75,12 +75,14 @@ QVariant DownloadList::data(const QModelIndex &index, int role) const
if (role == Qt::DisplayRole) {
return index.row();
} else if (role == Qt::ToolTipRole) {
QString text = m_Manager->getFileName(index.row()) + "\n";
if (m_Manager->isInfoIncomplete(index.row())) {
return tr("Information missing, please select \"Query Info\" from the context menu to re-retrieve.");
text += tr("Information missing, please select \"Query Info\" from the context menu to re-retrieve.");
} else {
NexusInfo info = m_Manager->getNexusInfo(index.row());
return QString("%1 (ID %2) %3").arg(info.m_ModName).arg(m_Manager->getModID(index.row())).arg(info.m_Version);
text += QString("%1 (ID %2) %3").arg(info.m_ModName).arg(m_Manager->getModID(index.row())).arg(info.m_Version);
}
return text;
} else {
return QVariant();
}
+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;
+181 -37
View File
@@ -59,14 +59,15 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <appconfig.h>
#include <utility.h>
#include <ipluginproxy.h>
#include <questionboxmemory.h>
#include <map>
#include <ctime>
#include <QTime>
#include <util.h>
#include <wchar.h>
#include <QTime>
#include <QInputDialog>
#include <QSettings>
#include <QWhatsThis>
#include <wchar.h>
#include <sstream>
#include <QProcess>
#include <QMenu>
@@ -111,6 +112,8 @@ using namespace MOBase;
using namespace MOShared;
static bool isOnline()
{
QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
@@ -139,18 +142,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);
@@ -161,6 +163,8 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget
ui->actionEndorseMO->setVisible(false);
MOBase::QuestionBoxMemory::init(initSettings.fileName());
updateProblemsButton();
updateToolBar();
@@ -256,7 +260,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 +417,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());
@@ -1263,7 +1267,7 @@ HANDLE MainWindow::spawnBinaryDirect(const QFileInfo &binary, const QString &arg
(m_Settings.getLoadMechanism() == LoadMechanism::LOAD_MODORGANIZER)) {
if (!testForSteam()) {
if (QuestionBoxMemory::query(this->isVisible() ? this : NULL,
m_Settings.directInterface(), "steamQuery", tr("Start Steam?"),
"steamQuery", tr("Start Steam?"),
tr("Steam is required to be running already to correctly start the game. "
"Should MO try to start steam now?"),
QDialogButtonBox::Yes | QDialogButtonBox::No) == QDialogButtonBox::Yes) {
@@ -1277,10 +1281,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 +1309,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 +1339,7 @@ void MainWindow::spawnBinary(const QFileInfo &binary, const QString &arguments,
QFile::remove(m_CurrentProfile->getLoadOrderFileName());
}
dialog->hide();
dialog->deleteLater();
}
}
}
@@ -1499,6 +1509,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 +1905,6 @@ void MainWindow::activateProxy(bool activate)
busyDialog.hide();
}
void MainWindow::readSettings()
{
QSettings settings(ToQString(GameInfo::instance().getIniFilename()), QSettings::IniFormat);
@@ -2004,6 +2015,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 +2062,91 @@ 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->getFullPath()))) {
result.append(ToQString(file->getFullPath()));
}
}
} else {
qWarning("directory %s not found", qPrintable(path));
}
return result;
}
IDownloadManager *MainWindow::downloadManager()
{
return &m_DownloadManager;
}
IPluginList *MainWindow::pluginList()
{
return &m_PluginList;
}
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 +2478,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,11 +2497,15 @@ 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
updateProblemsButton();
for (int i = 0; i < m_ModList.rowCount(); ++i) {
ModInfo::Ptr modInfo = ModInfo::getByIndex(i);
modInfo->clearCaches();
}
}
@@ -2996,7 +3097,7 @@ void MainWindow::testExtractBSA(int modIndex)
QFileInfoList archives = dir.entryInfoList(QStringList("*.bsa"));
if (archives.length() != 0 &&
(QuestionBoxMemory::query(this, m_Settings.directInterface(), "unpackBSA", tr("Extract BSA"),
(QuestionBoxMemory::query(this, "unpackBSA", tr("Extract BSA"),
tr("This mod contains at least one BSA. Do you want to unpack it?\n"
"(This removes the BSA after completion. If you don't know about BSAs, just select no)"),
QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::No) == QMessageBox::Yes)) {
@@ -3065,7 +3166,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 +3175,6 @@ void MainWindow::information_clicked()
}
}
void MainWindow::syncOverwrite()
{
ModInfo::Ptr modInfo = ModInfo::getByIndex(m_ContextRow);
@@ -3087,7 +3186,6 @@ void MainWindow::syncOverwrite()
}
}
void MainWindow::createModFromOverwrite()
{
GuessedValue<QString> name;
@@ -3121,14 +3219,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 +3247,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 +3285,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 +3301,6 @@ void MainWindow::saveCategoriesFromMenu(QMenu *menu, int modRow)
}
}
void MainWindow::saveCategories()
{
QMenu *menu = qobject_cast<QMenu*>(sender());
@@ -3251,8 +3344,6 @@ void MainWindow::saveCategories()
refreshFilters();
}
void MainWindow::savePrimaryCategory()
{
QMenu *menu = qobject_cast<QMenu*>(sender());
@@ -3277,7 +3368,6 @@ void MainWindow::savePrimaryCategory()
}
}
void MainWindow::checkModsForUpdates()
{
statusBar()->show();
@@ -3295,6 +3385,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 +3445,6 @@ void MainWindow::addPrimaryCategoryCandidates(QMenu *primaryCategoryMenu, ModInf
}
}
void MainWindow::addPrimaryCategoryCandidates()
{
QMenu *menu = qobject_cast<QMenu*>(sender());
@@ -3330,7 +3458,6 @@ void MainWindow::addPrimaryCategoryCandidates()
addPrimaryCategoryCandidates(menu, modInfo);
}
void MainWindow::enableVisibleMods()
{
if (QMessageBox::question(NULL, tr("Confirm"), tr("Really enable all visible mods?"),
@@ -3339,7 +3466,6 @@ void MainWindow::enableVisibleMods()
}
}
void MainWindow::disableVisibleMods()
{
if (QMessageBox::question(NULL, tr("Confirm"), tr("Really disable all visible mods?"),
@@ -3348,7 +3474,6 @@ void MainWindow::disableVisibleMods()
}
}
void MainWindow::exportModListCSV()
{
SelectionDialog selection(tr("Choose what to export"));
@@ -3403,7 +3528,6 @@ void MainWindow::exportModListCSV()
}
}
void addMenuAsPushButton(QMenu *menu, QMenu *subMenu)
{
QPushButton *pushBtn = new QPushButton(subMenu->title());
@@ -3413,13 +3537,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 +3582,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 +4322,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 +4342,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 +4359,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 +4403,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 +4830,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 -3
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;
@@ -59,11 +60,32 @@ class QToolButton;
class ModListSortProxy;
class ModListGroupCategoriesProxy;
class MainWindow : public QMainWindow, public MOBase::IOrganizer, public MOBase::IPluginDiagnose
{
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;
}
};
typedef boost::signals2::signal<bool (const QString&), SignalCombinerAnd> SignalAboutToRunApplication;
public:
explicit MainWindow(const QString &exeName, QSettings &initSettings, QWidget *parent = 0);
~MainWindow();
@@ -89,8 +111,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 +133,12 @@ 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 MOBase::IPluginList *pluginList();
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;
@@ -153,7 +180,6 @@ signals:
void styleChanged(const QString &styleFile);
void modListDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
protected:
@@ -320,6 +346,8 @@ private:
QFile m_PluginsCheck;
SignalAboutToRunApplication m_AboutToRun;
private slots:
void showMessage(const QString &message);
@@ -466,6 +494,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 +530,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
+56 -26
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);
@@ -323,6 +324,7 @@ ModInfoRegular::ModInfoRegular(const QDir &path, DirectoryEntry **directoryStruc
}
}
QString categoriesString = metaFile.value("category", "").toString();
QStringList categories = categoriesString.split(',', QString::SkipEmptyParts);
@@ -350,8 +352,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 +371,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 +399,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();
@@ -545,6 +555,11 @@ void ModInfoRegular::setNexusDescription(const QString &description)
m_MetaInfoChanged = true;
}
void ModInfoRegular::addNexusCategory(int categoryID)
{
m_Categories.insert(CategoryFactory::instance().resolveNexusID(categoryID));
}
void ModInfoRegular::setIsEndorsed(bool endorsed)
{
@@ -575,12 +590,27 @@ void ModInfoRegular::endorse(bool doEndorse)
}
}
void ModInfoRegular::clearCaches()
{
m_LastConflictCheck = QTime();
}
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
{
@@ -666,7 +696,7 @@ ModInfoRegular::EConflictType ModInfoRegular::isConflicted() const
{
// this is costy so cache the result
QTime now = QTime::currentTime();
if (abs(m_LastConflictCheck.secsTo(now)) > 10) {
if (m_LastConflictCheck.isNull() || (m_LastConflictCheck.secsTo(now) > 10)) {
bool overwrite = false;
bool overwritten = false;
bool regular = false;
+74 -17
View File
@@ -80,23 +80,6 @@ public:
ENDORSED_UNKNOWN,
ENDORSED_NEVER
};
/*
struct NexusFileInfo {
NexusFileInfo(const QString &data);
NexusFileInfo(int id, const QString &name, const QString &url, const QString &version,
const QString &description, int category, int size)
: id(id), name(name), url(url), version(version), description(description),
category(category), size(size) {}
int id;
QString name;
QString url;
QString version;
QString description;
int category;
int size;
QString toString() const;
};*/
public:
@@ -192,6 +175,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.
*
@@ -251,6 +250,13 @@ public:
*/
virtual void setNexusDescription(const QString &description) = 0;
/**
* @brief sets the category id from a nexus category id. Conversion to MO id happens internally
* @param categoryID the nexus category id
* @note if a mapping is not possible, the category is set to the default value
*/
virtual void addNexusCategory(int categoryID) = 0;
/**
* update the endorsement state for the mod. This only changes the
* buffered state, it does not sync with Nexus
@@ -276,6 +282,11 @@ public:
*/
virtual void endorse(bool doEndorse) = 0;
/**
* @brief clear all caches held for this mod
*/
virtual void clearCaches() {}
/**
* @brief getter for the mod name
*
@@ -309,6 +320,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 +510,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.
*
@@ -568,6 +600,13 @@ public:
*/
virtual void setNexusDescription(const QString &description);
/**
* @brief sets the category id from a nexus category id. Conversion to MO id happens internally
* @param categoryID the nexus category id
* @note if a mapping is not possible, the category is set to the default value
*/
virtual void addNexusCategory(int categoryID);
/**
* @brief sets the new primary category of the mod
* @param categoryID the category to set
@@ -599,6 +638,11 @@ public:
*/
virtual void endorse(bool doEndorse);
/**
* @brief clear all caches held for this mod
*/
virtual void clearCaches();
/**
* @brief getter for the mod name
*
@@ -620,6 +664,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 +795,7 @@ private:
bool m_MetaInfoChanged;
MOBase::VersionInfo m_NewestVersion;
MOBase::VersionInfo m_IgnoredVersion;
EEndorsedState m_EndorsedState;
@@ -767,10 +817,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,13 +851,17 @@ 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 addNexusCategory(int) {}
virtual void setIsEndorsed(bool) {}
virtual void setNeverEndorse() {}
virtual bool remove() { return false; }
+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();
}
}

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