summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTannin <devnull@localhost>2014-05-25 15:39:45 +0200
committerTannin <devnull@localhost>2014-05-25 15:39:45 +0200
commitcf0a1bc2be22c8784fd098e00e05e46373afe602 (patch)
tree3f2140aae72dbebb1ef5c475eb019bb246f469d2 /src
parent48c8cca578c415152e64b3c3a6e1523dbc76b4d8 (diff)
- files in bsas are now only displayed in the data tab if they are managed by mo
- number of problems detected by MO is now displayed as a badge on the icon - rephrased the explanation text on the Archives tab. unchecked plugin-loaded bsas no longer prompt a warning - bsa extraction is now handled in a plugin - added a way for plugins to react to mod installation - re-enabled the automatic fix for asset order problems - bugfix: In some cases when a download wasn't started successfully the download urls weren't stored in the meta file so no resume was possible - bugfix: MO tried to resume downloads when it didn't have and download urls - bugfix: downloads couldn't be paused if the download was already broken on the network layer - bugfix: download managear did not recognize a file as downloaded if the download completed before signals were hooked up - bugfix: in-place file replacement was re-broken
Diffstat (limited to 'src')
-rw-r--r--src/directoryrefresher.cpp10
-rw-r--r--src/directoryrefresher.h10
-rw-r--r--src/downloadmanager.cpp183
-rw-r--r--src/downloadmanager.h1
-rw-r--r--src/mainwindow.cpp154
-rw-r--r--src/mainwindow.h7
-rw-r--r--src/mainwindow.ui23
-rw-r--r--src/organizerproxy.cpp6
-rw-r--r--src/organizerproxy.h4
-rw-r--r--src/resources.qrc10
-rw-r--r--src/resources/badge_1.pngbin0 -> 1119 bytes
-rw-r--r--src/resources/badge_2.pngbin0 -> 1223 bytes
-rw-r--r--src/resources/badge_3.pngbin0 -> 1346 bytes
-rw-r--r--src/resources/badge_4.pngbin0 -> 1200 bytes
-rw-r--r--src/resources/badge_5.pngbin0 -> 1269 bytes
-rw-r--r--src/resources/badge_6.pngbin0 -> 1244 bytes
-rw-r--r--src/resources/badge_7.pngbin0 -> 1190 bytes
-rw-r--r--src/resources/badge_8.pngbin0 -> 1252 bytes
-rw-r--r--src/resources/badge_9.pngbin0 -> 1259 bytes
-rw-r--r--src/resources/badge_more.pngbin0 -> 1629 bytes
-rw-r--r--src/version.rc4
21 files changed, 237 insertions, 175 deletions
diff --git a/src/directoryrefresher.cpp b/src/directoryrefresher.cpp
index 70bcf5b6..a2a3ef77 100644
--- a/src/directoryrefresher.cpp
+++ b/src/directoryrefresher.cpp
@@ -46,10 +46,12 @@ DirectoryEntry *DirectoryRefresher::getDirectoryStructure()
return result;
}
-void DirectoryRefresher::setMods(const std::vector<std::tuple<QString, QString, int> > &mods)
+void DirectoryRefresher::setMods(const std::vector<std::tuple<QString, QString, int> > &mods
+ , const std::set<QString> &managedArchives)
{
QMutexLocker locker(&m_RefreshLock);
m_Mods = mods;
+ m_ManagedArchives = managedArchives;
}
@@ -74,8 +76,10 @@ void DirectoryRefresher::addModToStructure(DirectoryEntry *directoryStructure, c
QDir dir(directory);
QFileInfoList bsaFiles = dir.entryInfoList(QStringList("*.bsa"), QDir::Files);
foreach (QFileInfo file, bsaFiles) {
- directoryStructure->addFromBSA(ToWString(modName), directoryW,
- ToWString(QDir::toNativeSeparators(file.absoluteFilePath())), priority);
+ if (m_ManagedArchives.find(file.fileName()) != m_ManagedArchives.end()) {
+ directoryStructure->addFromBSA(ToWString(modName), directoryW,
+ ToWString(QDir::toNativeSeparators(file.absoluteFilePath())), priority);
+ }
}
}
diff --git a/src/directoryrefresher.h b/src/directoryrefresher.h
index a6c8f00b..691448fa 100644
--- a/src/directoryrefresher.h
+++ b/src/directoryrefresher.h
@@ -20,11 +20,12 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#ifndef DIRECTORYREFRESHER_H
#define DIRECTORYREFRESHER_H
+#include <directoryentry.h>
#include <QObject>
-#include <vector>
#include <QMutex>
+#include <vector>
+#include <set>
#include <tuple>
-#include <directoryentry.h>
/**
@@ -60,7 +61,7 @@ public:
*
* @param mods list of the mods to include
**/
- void setMods(const std::vector<std::tuple<QString, QString, int> > &mods);
+ void setMods(const std::vector<std::tuple<QString, QString, int> > &mods, const std::set<QString> &managedArchives);
/**
* @brief sets up the directory where mods are stored
@@ -82,7 +83,7 @@ public:
* @param directory
* @param priorityDir
*/
- static void addModToStructure(MOShared::DirectoryEntry *directoryStructure, const QString &modName, int priority, const QString &directory);
+ void addModToStructure(MOShared::DirectoryEntry *directoryStructure, const QString &modName, int priority, const QString &directory);
public slots:
@@ -100,6 +101,7 @@ signals:
private:
std::vector<std::tuple<QString, QString, int> > m_Mods;
+ std::set<QString> m_ManagedArchives;
MOShared::DirectoryEntry *m_DirectoryStructure;
QMutex m_RefreshLock;
diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp
index ae53a819..5200bb4f 100644
--- a/src/downloadmanager.cpp
+++ b/src/downloadmanager.cpp
@@ -148,7 +148,10 @@ void DownloadManager::DownloadInfo::setName(QString newName, bool renameFile)
metaFile.rename(newName.mid(0).append(".meta"));
}
}
- m_Output.setFileName(newName);
+ if (!m_Output.isOpen()) {
+ // can't set file name if it's open
+ m_Output.setFileName(newName);
+ }
}
bool DownloadManager::DownloadInfo::isPausedState()
@@ -253,67 +256,70 @@ void DownloadManager::setShowHidden(bool showHidden)
void DownloadManager::refreshList()
{
- int downloadsBefore = m_ActiveDownloads.size();
+ try {
+ int downloadsBefore = m_ActiveDownloads.size();
- // remove finished downloads
- for (QVector<DownloadInfo*>::iterator Iter = m_ActiveDownloads.begin(); Iter != m_ActiveDownloads.end();) {
- if (((*Iter)->m_State == STATE_READY) || ((*Iter)->m_State == STATE_INSTALLED) || ((*Iter)->m_State == STATE_UNINSTALLED)) {
- delete *Iter;
- Iter = m_ActiveDownloads.erase(Iter);
- } else {
- ++Iter;
+ // remove finished downloads
+ for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); iter != m_ActiveDownloads.end();) {
+ if (((*iter)->m_State == STATE_READY) || ((*iter)->m_State == STATE_INSTALLED) || ((*iter)->m_State == STATE_UNINSTALLED)) {
+ delete *iter;
+ iter = m_ActiveDownloads.erase(iter);
+ } else {
+ ++iter;
+ }
}
- }
-
- QStringList nameFilters(m_SupportedExtensions);
- foreach (const QString &extension, m_SupportedExtensions) {
- nameFilters.append("*." + extension);
- }
- nameFilters.append(QString("*").append(UNFINISHED));
- QDir dir(QDir::fromNativeSeparators(m_OutputDirectory));
-
- // find orphaned meta files and delete them (sounds cruel but it's better for everyone)
- QStringList orphans;
- QStringList metaFiles = dir.entryList(QStringList() << "*.meta");
- foreach (const QString &metaFile, metaFiles) {
- QString baseFile = metaFile.left(metaFile.length() - 5);
- if (!QFile::exists(dir.absoluteFilePath(baseFile))) {
- orphans.append(dir.absoluteFilePath(metaFile));
+ QStringList nameFilters(m_SupportedExtensions);
+ foreach (const QString &extension, m_SupportedExtensions) {
+ nameFilters.append("*." + extension);
}
- }
- if (orphans.size() > 0) {
- qDebug("%d orphaned meta files will be deleted", orphans.size());
- shellDelete(orphans, true);
- }
- // add existing downloads to list
- foreach (QString file, dir.entryList(nameFilters, QDir::Files, QDir::Time)) {
- bool Exists = false;
- for (QVector<DownloadInfo*>::const_iterator Iter = m_ActiveDownloads.begin(); Iter != m_ActiveDownloads.end() && !Exists; ++Iter) {
- if (QString::compare((*Iter)->m_FileName, file, Qt::CaseInsensitive) == 0) {
- Exists = true;
- } else if (QString::compare(QFileInfo((*Iter)->m_Output.fileName()).fileName(), file, Qt::CaseInsensitive) == 0) {
- Exists = true;
+ nameFilters.append(QString("*").append(UNFINISHED));
+ QDir dir(QDir::fromNativeSeparators(m_OutputDirectory));
+
+ // find orphaned meta files and delete them (sounds cruel but it's better for everyone)
+ QStringList orphans;
+ QStringList metaFiles = dir.entryList(QStringList() << "*.meta");
+ foreach (const QString &metaFile, metaFiles) {
+ QString baseFile = metaFile.left(metaFile.length() - 5);
+ if (!QFile::exists(dir.absoluteFilePath(baseFile))) {
+ orphans.append(dir.absoluteFilePath(metaFile));
}
}
- if (Exists) {
- qDebug("%s exists", qPrintable(file));
- continue;
+ if (orphans.size() > 0) {
+ qDebug("%d orphaned meta files will be deleted", orphans.size());
+ shellDelete(orphans, true);
}
- QString fileName = QDir::fromNativeSeparators(m_OutputDirectory) + "/" + file;
+ // add existing downloads to list
+ foreach (QString file, dir.entryList(nameFilters, QDir::Files, QDir::Time)) {
+ bool Exists = false;
+ for (QVector<DownloadInfo*>::const_iterator Iter = m_ActiveDownloads.begin(); Iter != m_ActiveDownloads.end() && !Exists; ++Iter) {
+ if (QString::compare((*Iter)->m_FileName, file, Qt::CaseInsensitive) == 0) {
+ Exists = true;
+ } else if (QString::compare(QFileInfo((*Iter)->m_Output.fileName()).fileName(), file, Qt::CaseInsensitive) == 0) {
+ Exists = true;
+ }
+ }
+ if (Exists) {
+ continue;
+ }
- DownloadInfo *info = DownloadInfo::createFromMeta(fileName, m_ShowHidden);
- if (info != NULL) {
- m_ActiveDownloads.push_front(info);
+ QString fileName = QDir::fromNativeSeparators(m_OutputDirectory) + "/" + file;
+
+ DownloadInfo *info = DownloadInfo::createFromMeta(fileName, m_ShowHidden);
+ if (info != NULL) {
+ m_ActiveDownloads.push_front(info);
+ }
}
- }
- if (m_ActiveDownloads.size() != downloadsBefore) {
- qDebug("downloads after refresh: %d", m_ActiveDownloads.size());
+ if (m_ActiveDownloads.size() != downloadsBefore) {
+ qDebug("downloads after refresh: %d", m_ActiveDownloads.size());
+ }
+ emit update(-1);
+ } catch (const std::bad_alloc&) {
+ reportError(tr("Memory allocation error (in refreshing directory)."));
}
- emit update(-1);
}
@@ -344,6 +350,9 @@ bool DownloadManager::addDownload(QNetworkReply *reply, const ModRepositoryFileI
bool DownloadManager::addDownload(QNetworkReply *reply, const QStringList &URLs, const QString &fileName,
int modID, int fileID, const ModRepositoryFileInfo *fileInfo)
{
+ if (!reply->isRunning()) {
+ qDebug("this is not a running download! %d", reply->isFinished());
+ }
// download invoked from an already open network reply (i.e. download link in the browser)
DownloadInfo *newDownload = DownloadInfo::createNew(fileInfo, URLs);
@@ -404,6 +413,7 @@ void DownloadManager::startDownload(QNetworkReply *reply, DownloadInfo *newDownl
}
newDownload->m_StartTime.start();
+ createMetaFile(newDownload);
if (!newDownload->m_Output.open(mode)) {
reportError(tr("failed to download %1: could not open output file: %2")
@@ -413,6 +423,7 @@ void DownloadManager::startDownload(QNetworkReply *reply, DownloadInfo *newDownl
connect(newDownload->m_Reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(downloadProgress(qint64, qint64)));
connect(newDownload->m_Reply, SIGNAL(finished()), this, SLOT(downloadFinished()));
+ connect(newDownload->m_Reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(downloadError(QNetworkReply::NetworkError)));
connect(newDownload->m_Reply, SIGNAL(readyRead()), this, SLOT(downloadReadyRead()));
connect(newDownload->m_Reply, SIGNAL(metaDataChanged()), this, SLOT(metaDataChanged()));
@@ -421,11 +432,15 @@ void DownloadManager::startDownload(QNetworkReply *reply, DownloadInfo *newDownl
removePending(newDownload->m_FileInfo->modID, newDownload->m_FileInfo->fileID);
emit aboutToUpdate();
-
m_ActiveDownloads.append(newDownload);
emit update(-1);
emit downloadAdded();
+
+ if (reply->isFinished()) {
+ // it's possible the download has already finished before this function ran
+ downloadFinished();
+ }
}
}
@@ -593,8 +608,11 @@ void DownloadManager::pauseDownload(int index)
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());
+ if (info->m_Reply->isRunning()) {
+ setState(info, STATE_PAUSING);
+ } else {
+ setState(info, STATE_PAUSED);
+ }
} else if ((info->m_State == STATE_FETCHINGMODINFO) || (info->m_State == STATE_FETCHINGFILEINFO)) {
setState(info, STATE_READY);
}
@@ -619,6 +637,11 @@ void DownloadManager::resumeDownloadInt(int index)
}
DownloadInfo *info = m_ActiveDownloads[index];
if (info->isPausedState()) {
+ if ((info->m_Urls.size() == 0)
+ || ((info->m_Urls.size() == 1) && (info->m_Urls[0].size() == 0))) {
+ emit showMessage(tr("No known download urls. Sorry, this download can't be resumed."));
+ return;
+ }
if (info->m_State == STATE_ERROR) {
info->m_CurrentUrl = (info->m_CurrentUrl + 1) % info->m_Urls.count();
}
@@ -955,32 +978,40 @@ void DownloadManager::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
return;
}
int index = 0;
- DownloadInfo *info = findDownload(this->sender(), &index);
- if (info != NULL) {
- if (info->m_State == STATE_CANCELING) {
- setState(info, STATE_CANCELED);
- } else if (info->m_State == STATE_PAUSING) {
- setState(info, STATE_PAUSED);
- } else {
- if (bytesTotal > info->m_TotalSize) {
- info->m_TotalSize = 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);
+ try {
+ DownloadInfo *info = findDownload(this->sender(), &index);
+ if (info != NULL) {
+ if (info->m_State == STATE_CANCELING) {
+ setState(info, STATE_CANCELED);
+ } else if (info->m_State == STATE_PAUSING) {
+ setState(info, STATE_PAUSED);
+ } else {
+ if (bytesTotal > info->m_TotalSize) {
+ info->m_TotalSize = 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);
+ }
}
}
+ } catch (const std::bad_alloc&) {
+ reportError(tr("Memory allocation error (in processing progress event)."));
}
}
void DownloadManager::downloadReadyRead()
{
- DownloadInfo *info = findDownload(this->sender());
- if (info != NULL) {
- info->m_Output.write(info->m_Reply->readAll());
+ try {
+ DownloadInfo *info = findDownload(this->sender());
+ if (info != NULL) {
+ info->m_Output.write(info->m_Reply->readAll());
+ }
+ } catch (const std::bad_alloc&) {
+ reportError(tr("Memory allocation error (in processing downloaded data)."));
}
}
@@ -1267,7 +1298,6 @@ void DownloadManager::nxmDownloadURLsAvailable(int modID, int fileID, QVariant u
foreach (const QVariant &server, resultList) {
URLs.append(server.toMap()["URI"].toString());
}
-
addDownload(URLs, modID, fileID, info);
}
@@ -1356,7 +1386,6 @@ void DownloadManager::downloadFinished()
createMetaFile(info);
emit update(index);
} else {
-
QString url = info->m_Urls[info->m_CurrentUrl];
if (info->m_FileInfo->userData.contains("downloadMap")) {
foreach (const QVariant &server, info->m_FileInfo->userData["downloadMap"].toList()) {
@@ -1406,6 +1435,14 @@ void DownloadManager::downloadFinished()
}
+void DownloadManager::downloadError(QNetworkReply::NetworkError error)
+{
+ if (error != QNetworkReply::OperationCanceledError) {
+ qWarning("Download error occured: %d", error);
+ }
+}
+
+
void DownloadManager::metaDataChanged()
{
int index = 0;
@@ -1416,7 +1453,7 @@ void DownloadManager::metaDataChanged()
if (!newName.isEmpty() && (newName != info->m_FileName)) {
info->setName(getDownloadFileName(newName), true);
refreshAlphabeticalTranslation();
- if (!info->m_Output.open(QIODevice::WriteOnly | QIODevice::Append)) {
+ if (!info->m_Output.isOpen() && !info->m_Output.open(QIODevice::WriteOnly | QIODevice::Append)) {
reportError(tr("failed to re-open %1").arg(info->m_FileName));
setState(info, STATE_CANCELING);
}
diff --git a/src/downloadmanager.h b/src/downloadmanager.h
index 9ea95e6a..0d8d314a 100644
--- a/src/downloadmanager.h
+++ b/src/downloadmanager.h
@@ -417,6 +417,7 @@ private slots:
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
void downloadReadyRead();
void downloadFinished();
+ void downloadError(QNetworkReply::NetworkError error);
void metaDataChanged();
void directoryChanged(const QString &dirctory);
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index a524be61..1e8d512a 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -164,7 +164,7 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget
m_Updater(NexusInterface::instance(), this), m_CategoryFactory(CategoryFactory::instance()),
m_CurrentProfile(NULL), m_AskForNexusPW(false),
m_ArchivesInit(false), m_ContextItem(NULL), m_ContextAction(NULL), m_CurrentSaveView(NULL),
- m_GameInfo(new GameInfoImpl()), m_AboutToRun()
+ m_GameInfo(new GameInfoImpl()), m_AboutToRun(), m_ModInstalled()
{
ui->setupUi(this);
this->setWindowTitle(ToQString(GameInfo::instance().getGameName()) + " Mod Organizer v" + m_Updater.getVersion().displayString());
@@ -285,7 +285,6 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget
connect(&m_PluginList, SIGNAL(saveTimer()), this, SLOT(savePluginList()));
connect(ui->bsaList, SIGNAL(itemsMoved()), this, SLOT(bsaList_itemMoved()));
- connect(ui->bsaWarning, SIGNAL(linkActivated(QString)), this, SLOT(linkClicked(QString)));
connect(ui->dataTree, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(expandDataTreeItem(QTreeWidgetItem*)));
@@ -533,14 +532,26 @@ void MainWindow::updateToolBar()
void MainWindow::updateProblemsButton()
{
- if (checkForProblems()) {
+ int numProblems = checkForProblems();
+ if (numProblems > 0) {
ui->actionProblems->setEnabled(true);
ui->actionProblems->setIconText(tr("Problems"));
ui->actionProblems->setToolTip(tr("There are potential problems with your setup"));
+
+// QPixmap mergedIcon(64, 64);
+ QPixmap mergedIcon = QPixmap(":/MO/gui/warning").scaled(64, 64);
+ {
+ QPainter painter(&mergedIcon);
+// painter.setBrush(QBrush(Qt::transparent));
+ std::string badgeName = std::string(":/MO/gui/badge_") + (numProblems < 10 ? std::to_string(static_cast<long long>(numProblems)) : "more");
+ painter.drawPixmap(32, 32, 32, 32, QPixmap(badgeName.c_str()));
+ }
+ ui->actionProblems->setIcon(QIcon(mergedIcon));
} else {
ui->actionProblems->setEnabled(false);
ui->actionProblems->setIconText(tr("No Problems"));
ui->actionProblems->setToolTip(tr("Everything seems to be in order"));
+ ui->actionProblems->setIcon(QIcon(":/MO/gui/warning"));
}
}
@@ -575,15 +586,13 @@ bool MainWindow::errorReported(QString &logFile)
}
-bool MainWindow::checkForProblems()
+int MainWindow::checkForProblems()
{
foreach (IPluginDiagnose *diagnose, m_DiagnosisPlugins) {
std::vector<unsigned int> activeProblems = diagnose->activeProblems();
- if (activeProblems.size() > 0) {
- return true;
- }
+ return activeProblems.size();
}
- return false;
+ return 0;
}
void MainWindow::about()
@@ -1616,11 +1625,27 @@ bool MainWindow::refreshProfiles(bool selectProfile)
}
+std::set<QString> MainWindow::managedArchives()
+{
+ std::set<QString> result;
+
+ QFile archiveFile(m_CurrentProfile->getArchivesFileName());
+ if (archiveFile.open(QIODevice::ReadOnly)) {
+ while (!archiveFile.atEnd()) {
+ result.insert(QString::fromUtf8(archiveFile.readLine()).trimmed());
+ }
+ archiveFile.close();
+ }
+ return result;
+}
+
+
void MainWindow::refreshDirectoryStructure()
{
m_DirectoryUpdate = true;
std::vector<std::tuple<QString, QString, int> > activeModList = m_CurrentProfile->getActiveMods();
- m_DirectoryRefresher.setMods(activeModList);
+
+ m_DirectoryRefresher.setMods(activeModList, managedArchives());
statusBar()->show();
m_RefreshProgress->setRange(0, 100);
@@ -1776,6 +1801,17 @@ static bool BySortValue(const std::pair<UINT32, QTreeWidgetItem*> &LHS, const st
}
+template <typename InputIterator>
+QStringList toStringList(InputIterator current, InputIterator end)
+{
+ QStringList result;
+ for (; current != end; ++current) {
+ result.append(*current);
+ }
+ return result;
+}
+
+
void MainWindow::refreshBSAList()
{
m_ArchivesInit = false;
@@ -1811,17 +1847,9 @@ void MainWindow::refreshBSAList()
m_ActiveArchives.clear();
- QFile archiveFile(m_CurrentProfile->getArchivesFileName());
- if (archiveFile.open(QIODevice::ReadOnly)) {
- while (!archiveFile.atEnd()) {
- m_ActiveArchives.append(QString::fromUtf8(archiveFile.readLine()));
- }
- archiveFile.close();
-
- for (int i = 0; i < m_ActiveArchives.count(); ++i) {
- m_ActiveArchives[i] = m_ActiveArchives[i].trimmed();
- }
- } else {
+ auto iter = managedArchives();
+ m_ActiveArchives = toStringList(iter.begin(), iter.end());
+ if (m_ActiveArchives.isEmpty()) {
m_ActiveArchives = m_DefaultArchives;
}
@@ -1908,7 +1936,7 @@ void MainWindow::checkBSAList()
item->setIcon(0, QIcon(":/MO/gui/warning"));
item->setToolTip(0, tr("This bsa is enabled in the ini file so it may be required!"));
modWarning = true;
- } else {
+/* } else {
QString espName = filename.mid(0, filename.length() - 3).append("esp").toLower();
QString esmName = filename.mid(0, filename.length() - 3).append("esm").toLower();
if (m_PluginList.isEnabled(espName) || m_PluginList.isEnabled(esmName)) {
@@ -1916,7 +1944,7 @@ void MainWindow::checkBSAList()
item->setToolTip(0, tr("This archive will still be loaded since there is a plugin of the same name but "
"its files will not follow installation order!"));
modWarning = true;
- }
+ }*/
}
}
}
@@ -2224,7 +2252,7 @@ IModInterface *MainWindow::installMod(const QString &fileName)
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)) {
displayModInformation(modInfo, modIndex, ModInfoDialog::TAB_INIFILES);
}
- testExtractBSA(modIndex);
+ m_ModInstalled(modName);
return modInfo.data();
} else {
reportError(tr("mod \"%1\" not found").arg(modName));
@@ -2599,7 +2627,10 @@ void MainWindow::modStatusChanged(unsigned int index)
try {
ModInfo::Ptr modInfo = ModInfo::getByIndex(index);
if (m_CurrentProfile->modEnabled(index)) {
- DirectoryRefresher::addModToStructure(m_DirectoryStructure, modInfo->name(), m_CurrentProfile->getModPriority(index), modInfo->absolutePath());
+ m_DirectoryRefresher.addModToStructure(m_DirectoryStructure
+ , modInfo->name()
+ , m_CurrentProfile->getModPriority(index)
+ , modInfo->absolutePath());
DirectoryRefresher::cleanStructure(m_DirectoryStructure);
} else {
if (m_DirectoryStructure->originExists(ToWString(modInfo->name()))) {
@@ -3128,9 +3159,9 @@ void MainWindow::displayModInformation(ModInfo::Ptr modInfo, unsigned int index,
FilesOrigin& origin = m_DirectoryStructure->getOriginByName(ToWString(modInfo->name()));
origin.enable(false);
- DirectoryRefresher::addModToStructure(m_DirectoryStructure,
- modInfo->name(), m_CurrentProfile->getModPriority(index),
- modInfo->absolutePath());
+ m_DirectoryRefresher.addModToStructure(m_DirectoryStructure,
+ modInfo->name(), m_CurrentProfile->getModPriority(index),
+ modInfo->absolutePath());
DirectoryRefresher::cleanStructure(m_DirectoryStructure);
refreshLists();
}
@@ -3195,54 +3226,6 @@ void MainWindow::displayModInformation(int row, int tab)
}
-void MainWindow::testExtractBSA(int modIndex)
-{
- ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex);
- QDir dir(modInfo->absolutePath());
-
- QFileInfoList archives = dir.entryInfoList(QStringList("*.bsa"));
- if (archives.length() != 0 &&
- (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)) {
-
-
- foreach (QFileInfo archiveInfo, archives) {
- BSA::Archive archive;
- BSA::EErrorCode result = archive.read(archiveInfo.absoluteFilePath().toLocal8Bit().constData());
- if ((result != BSA::ERROR_NONE) && (result != BSA::ERROR_INVALIDHASHES)) {
- reportError(tr("failed to read %1: %2").arg(archiveInfo.fileName()).arg(result));
- return;
- }
-
- QProgressDialog progress(this);
- progress.setMaximum(100);
- progress.setValue(0);
- progress.show();
-
- archive.extractAll(modInfo->absolutePath().toLocal8Bit().constData(),
- boost::bind(&MainWindow::extractProgress, this, boost::ref(progress), _1, _2),
- false);
-
- if (result == BSA::ERROR_INVALIDHASHES) {
- reportError(tr("This archive contains invalid hashes. Some files may be broken."));
- }
-
- archive.close();
-
- if (!QFile::remove(archiveInfo.absoluteFilePath())) {
- qCritical("failed to remove archive %s", archiveInfo.absoluteFilePath().toUtf8().constData());
- } else {
- m_DirectoryStructure->removeFile(ToWString(archiveInfo.fileName()));
- }
- }
-
- refreshBSAList();
- }
-}
-
-
void MainWindow::ignoreMissingData_clicked()
{
ModInfo::Ptr info = ModInfo::getByIndex(m_ContextRow);
@@ -4233,7 +4216,8 @@ void MainWindow::installDownload(int index)
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)) {
displayModInformation(modInfo, modIndex, ModInfoDialog::TAB_INIFILES);
}
- testExtractBSA(modIndex);
+
+ m_ModInstalled(modName);
} else {
reportError(tr("mod \"%1\" not found").arg(modName));
}
@@ -5001,11 +4985,13 @@ void MainWindow::removeFromToolbar()
void MainWindow::toolBar_customContextMenuRequested(const QPoint &point)
{
QAction *action = ui->toolBar->actionAt(point);
- if (action->objectName().startsWith("custom_")) {
- m_ContextAction = action;
- QMenu menu;
- menu.addAction(tr("Remove"), this, SLOT(removeFromToolbar()));
- menu.exec(ui->toolBar->mapToGlobal(point));
+ if (action != NULL) {
+ if (action->objectName().startsWith("custom_")) {
+ m_ContextAction = action;
+ QMenu menu;
+ menu.addAction(tr("Remove"), this, SLOT(removeFromToolbar()));
+ menu.exec(ui->toolBar->mapToGlobal(point));
+ }
}
}
@@ -5418,3 +5404,9 @@ void MainWindow::on_categoriesOrBtn_toggled(bool checked)
m_ModListSortProxy->setFilterMode(ModListSortProxy::FILTER_OR);
}
}
+
+void MainWindow::on_managedArchiveLabel_linkHovered(const QString&)
+{
+ QToolTip::showText(QCursor::pos(),
+ ui->managedArchiveLabel->toolTip());
+}
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 910e243a..bbbbea2f 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -90,6 +90,7 @@ private:
};
typedef boost::signals2::signal<bool (const QString&), SignalCombinerAnd> SignalAboutToRunApplication;
+ typedef boost::signals2::signal<void (const QString&)> SignalModInstalled;
public:
explicit MainWindow(const QString &exeName, QSettings &initSettings, QWidget *parent = 0);
@@ -251,7 +252,7 @@ private:
bool extractProgress(QProgressDialog &extractProgress, int percentage, std::string fileName);
- bool checkForProblems();
+ int checkForProblems();
int getBinaryExecuteInfo(const QFileInfo &targetInfo, QFileInfo &binaryInfo, QString &arguments);
QTreeWidgetItem *addFilterItem(QTreeWidgetItem *root, const QString &name, int categoryID);
@@ -284,6 +285,8 @@ private:
QMenu *modListContextMenu();
+ std::set<QString> managedArchives();
+
private:
static const unsigned int PROBLEM_PLUGINSNOTLOADED = 1;
@@ -366,6 +369,7 @@ private:
QFile m_PluginsCheck;
SignalAboutToRunApplication m_AboutToRun;
+ SignalModInstalled m_ModInstalled;
QString m_CurrentLanguage;
std::vector<QTranslator*> m_Translators;
@@ -588,6 +592,7 @@ private slots: // ui slots
void on_actionCopy_Log_to_Clipboard_triggered();
void on_categoriesAndBtn_toggled(bool checked);
void on_categoriesOrBtn_toggled(bool checked);
+ void on_managedArchiveLabel_linkHovered(const QString &link);
};
diff --git a/src/mainwindow.ui b/src/mainwindow.ui
index c607a8e6..1bb70d64 100644
--- a/src/mainwindow.ui
+++ b/src/mainwindow.ui
@@ -899,6 +899,19 @@ p, li { white-space: pre-wrap; }
<number>6</number>
</property>
<item>
+ <widget class="QLabel" name="managedArchiveLabel">
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Managed&lt;/span&gt; Archives are always loaded and the priority of their mod (left pane) applies to them. MO will also provide conflict information for managed archives.&lt;br/&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Unmanaged&lt;/span&gt; Archives are only loaded if there is a plugin of the same name (&amp;quot;Plugins&amp;quot; tab) with the same priority as that plugin!&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;If you don't understand this it's safest to leave all archives unchecked except the grayed out ones.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Check an archive to have MO manage it. (&lt;a href=&quot;#&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;read more&lt;/span&gt;&lt;/a&gt;)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="MOBase::SortableTreeWidget" name="bsaList">
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
@@ -958,16 +971,6 @@ BSAs checked here are loaded in such a way that your installation order is obeye
</column>
</widget>
</item>
- <item>
- <widget class="QLabel" name="bsaWarning">
- <property name="text">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Marked Archives (&lt;img src=&quot;:/MO/gui/warning_16&quot;/&gt;) are still loaded on Skyrim but the &lt;a href=&quot;http://forums.bethsoft.com/topic/1354395-update-bsas-and-you/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;regular file override&lt;/span&gt;&lt;/a&gt; mechanism will apply: Loose files override BSAs, no matter the mod/plugin priority.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
- </property>
- <property name="wordWrap">
- <bool>true</bool>
- </property>
- </widget>
- </item>
</layout>
</widget>
<widget class="QWidget" name="dataTab">
diff --git a/src/organizerproxy.cpp b/src/organizerproxy.cpp
index f17d7cd9..c48bc765 100644
--- a/src/organizerproxy.cpp
+++ b/src/organizerproxy.cpp
@@ -110,6 +110,12 @@ bool OrganizerProxy::onAboutToRun(const std::function<bool (const QString &)> &f
return conn.connected();
}
+bool OrganizerProxy::onModInstalled(const std::function<void (const QString &)> &func)
+{
+ auto conn = m_Proxied->m_ModInstalled.connect(func);
+ return conn.connected();
+}
+
void OrganizerProxy::refreshModList(bool saveChanges)
{
m_Proxied->refreshModList(saveChanges);
diff --git a/src/organizerproxy.h b/src/organizerproxy.h
index fd9dd56a..017908e5 100644
--- a/src/organizerproxy.h
+++ b/src/organizerproxy.h
@@ -35,9 +35,11 @@ public:
virtual MOBase::IPluginList *pluginList();
virtual MOBase::IModList *modList();
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 void refreshModList(bool saveChanges);
+ virtual bool onAboutToRun(const std::function<bool(const QString&)> &func);
+ virtual bool onModInstalled(const std::function<void (const QString &)> &func);
+
private:
MainWindow *m_Proxied;
const QString &m_PluginName;
diff --git a/src/resources.qrc b/src/resources.qrc
index 2300a15e..3287ad5d 100644
--- a/src/resources.qrc
+++ b/src/resources.qrc
@@ -55,5 +55,15 @@
<file alias="backup">resources/document-save_32.png</file>
<file alias="restore">resources/edit-undo.png</file>
<file alias="sort">resources/arrange-boxes.png</file>
+ <file alias="badge_1">resources/badge_1.png</file>
+ <file alias="badge_2">resources/badge_2.png</file>
+ <file alias="badge_3">resources/badge_3.png</file>
+ <file alias="badge_4">resources/badge_4.png</file>
+ <file alias="badge_5">resources/badge_5.png</file>
+ <file alias="badge_6">resources/badge_6.png</file>
+ <file alias="badge_7">resources/badge_7.png</file>
+ <file alias="badge_8">resources/badge_8.png</file>
+ <file alias="badge_9">resources/badge_9.png</file>
+ <file alias="badge_more">resources/badge_more.png</file>
</qresource>
</RCC>
diff --git a/src/resources/badge_1.png b/src/resources/badge_1.png
new file mode 100644
index 00000000..5a525b50
--- /dev/null
+++ b/src/resources/badge_1.png
Binary files differ
diff --git a/src/resources/badge_2.png b/src/resources/badge_2.png
new file mode 100644
index 00000000..93ac67e2
--- /dev/null
+++ b/src/resources/badge_2.png
Binary files differ
diff --git a/src/resources/badge_3.png b/src/resources/badge_3.png
new file mode 100644
index 00000000..f21a7bef
--- /dev/null
+++ b/src/resources/badge_3.png
Binary files differ
diff --git a/src/resources/badge_4.png b/src/resources/badge_4.png
new file mode 100644
index 00000000..becfaf46
--- /dev/null
+++ b/src/resources/badge_4.png
Binary files differ
diff --git a/src/resources/badge_5.png b/src/resources/badge_5.png
new file mode 100644
index 00000000..08ef8b16
--- /dev/null
+++ b/src/resources/badge_5.png
Binary files differ
diff --git a/src/resources/badge_6.png b/src/resources/badge_6.png
new file mode 100644
index 00000000..1a08d784
--- /dev/null
+++ b/src/resources/badge_6.png
Binary files differ
diff --git a/src/resources/badge_7.png b/src/resources/badge_7.png
new file mode 100644
index 00000000..c173a347
--- /dev/null
+++ b/src/resources/badge_7.png
Binary files differ
diff --git a/src/resources/badge_8.png b/src/resources/badge_8.png
new file mode 100644
index 00000000..32c7b675
--- /dev/null
+++ b/src/resources/badge_8.png
Binary files differ
diff --git a/src/resources/badge_9.png b/src/resources/badge_9.png
new file mode 100644
index 00000000..bf5f2cc8
--- /dev/null
+++ b/src/resources/badge_9.png
Binary files differ
diff --git a/src/resources/badge_more.png b/src/resources/badge_more.png
new file mode 100644
index 00000000..e0f27f24
--- /dev/null
+++ b/src/resources/badge_more.png
Binary files differ
diff --git a/src/version.rc b/src/version.rc
index 1efdde0d..5e9b62c5 100644
--- a/src/version.rc
+++ b/src/version.rc
@@ -1,7 +1,7 @@
#include "Winver.h"
-#define VER_FILEVERSION 1,2,1,0
-#define VER_FILEVERSION_STR "1,2,1,0\0"
+#define VER_FILEVERSION 1,2,2,0
+#define VER_FILEVERSION_STR "1,2,2,0\0"
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION