diff options
| author | Tannin <devnull@localhost> | 2014-05-25 15:39:45 +0200 |
|---|---|---|
| committer | Tannin <devnull@localhost> | 2014-05-25 15:39:45 +0200 |
| commit | cf0a1bc2be22c8784fd098e00e05e46373afe602 (patch) | |
| tree | 3f2140aae72dbebb1ef5c475eb019bb246f469d2 | |
| parent | 48c8cca578c415152e64b3c3a6e1523dbc76b4d8 (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
| -rw-r--r-- | src/directoryrefresher.cpp | 10 | ||||
| -rw-r--r-- | src/directoryrefresher.h | 10 | ||||
| -rw-r--r-- | src/downloadmanager.cpp | 183 | ||||
| -rw-r--r-- | src/downloadmanager.h | 1 | ||||
| -rw-r--r-- | src/mainwindow.cpp | 154 | ||||
| -rw-r--r-- | src/mainwindow.h | 7 | ||||
| -rw-r--r-- | src/mainwindow.ui | 23 | ||||
| -rw-r--r-- | src/organizerproxy.cpp | 6 | ||||
| -rw-r--r-- | src/organizerproxy.h | 4 | ||||
| -rw-r--r-- | src/resources.qrc | 10 | ||||
| -rw-r--r-- | src/resources/badge_1.png | bin | 0 -> 1119 bytes | |||
| -rw-r--r-- | src/resources/badge_2.png | bin | 0 -> 1223 bytes | |||
| -rw-r--r-- | src/resources/badge_3.png | bin | 0 -> 1346 bytes | |||
| -rw-r--r-- | src/resources/badge_4.png | bin | 0 -> 1200 bytes | |||
| -rw-r--r-- | src/resources/badge_5.png | bin | 0 -> 1269 bytes | |||
| -rw-r--r-- | src/resources/badge_6.png | bin | 0 -> 1244 bytes | |||
| -rw-r--r-- | src/resources/badge_7.png | bin | 0 -> 1190 bytes | |||
| -rw-r--r-- | src/resources/badge_8.png | bin | 0 -> 1252 bytes | |||
| -rw-r--r-- | src/resources/badge_9.png | bin | 0 -> 1259 bytes | |||
| -rw-r--r-- | src/resources/badge_more.png | bin | 0 -> 1629 bytes | |||
| -rw-r--r-- | src/version.rc | 4 |
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><html><head/><body><p><span style=" font-weight:600;">Managed</span> Archives are always loaded and the priority of their mod (left pane) applies to them. MO will also provide conflict information for managed archives.<br/><span style=" font-weight:600;">Unmanaged</span> Archives are only loaded if there is a plugin of the same name (&quot;Plugins&quot; tab) with the same priority as that plugin!</p><p><span style=" font-style:italic;">If you don't understand this it's safest to leave all archives unchecked except the grayed out ones.</span></p></body></html></string>
+ </property>
+ <property name="text">
+ <string><html><head/><body><p>Check an archive to have MO manage it. (<a href="#"><span style=" text-decoration: underline; color:#0000ff;">read more</span></a>)</p></body></html></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><html><head/><body><p>Marked Archives (<img src=":/MO/gui/warning_16"/>) are still loaded on Skyrim but the <a href="http://forums.bethsoft.com/topic/1354395-update-bsas-and-you/"><span style=" text-decoration: underline; color:#0000ff;">regular file override</span></a> mechanism will apply: Loose files override BSAs, no matter the mod/plugin priority.</p></body></html></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 Binary files differnew file mode 100644 index 00000000..5a525b50 --- /dev/null +++ b/src/resources/badge_1.png diff --git a/src/resources/badge_2.png b/src/resources/badge_2.png Binary files differnew file mode 100644 index 00000000..93ac67e2 --- /dev/null +++ b/src/resources/badge_2.png diff --git a/src/resources/badge_3.png b/src/resources/badge_3.png Binary files differnew file mode 100644 index 00000000..f21a7bef --- /dev/null +++ b/src/resources/badge_3.png diff --git a/src/resources/badge_4.png b/src/resources/badge_4.png Binary files differnew file mode 100644 index 00000000..becfaf46 --- /dev/null +++ b/src/resources/badge_4.png diff --git a/src/resources/badge_5.png b/src/resources/badge_5.png Binary files differnew file mode 100644 index 00000000..08ef8b16 --- /dev/null +++ b/src/resources/badge_5.png diff --git a/src/resources/badge_6.png b/src/resources/badge_6.png Binary files differnew file mode 100644 index 00000000..1a08d784 --- /dev/null +++ b/src/resources/badge_6.png diff --git a/src/resources/badge_7.png b/src/resources/badge_7.png Binary files differnew file mode 100644 index 00000000..c173a347 --- /dev/null +++ b/src/resources/badge_7.png diff --git a/src/resources/badge_8.png b/src/resources/badge_8.png Binary files differnew file mode 100644 index 00000000..32c7b675 --- /dev/null +++ b/src/resources/badge_8.png diff --git a/src/resources/badge_9.png b/src/resources/badge_9.png Binary files differnew file mode 100644 index 00000000..bf5f2cc8 --- /dev/null +++ b/src/resources/badge_9.png diff --git a/src/resources/badge_more.png b/src/resources/badge_more.png Binary files differnew file mode 100644 index 00000000..e0f27f24 --- /dev/null +++ b/src/resources/badge_more.png 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
|
