mirror of
https://github.com/ModOrganizer2/modorganizer.git
synced 2026-07-27 13:58:24 -07:00
Compare commits
29
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af89733121 | ||
|
|
baf1240be7 | ||
|
|
6e4626852c | ||
|
|
e8f56d65d2 | ||
|
|
5e7c875b29 | ||
|
|
b2a7c7c223 | ||
|
|
7b4582c1b1 | ||
|
|
5d7b23acef | ||
|
|
3628ec930b | ||
|
|
e22aeca3ff | ||
|
|
cbd6b288eb | ||
|
|
484749e612 | ||
|
|
5b3cdaa83b | ||
|
|
6d3f88b330 | ||
|
|
0feb4b702d | ||
|
|
5a4b6e70fd | ||
|
|
18574c2ba8 | ||
|
|
1eb783aae3 | ||
|
|
93a19799b8 | ||
|
|
2a31eb40fb | ||
|
|
cf0a1bc2be | ||
|
|
48c8cca578 | ||
|
|
977b407525 | ||
|
|
f4b1aba61a | ||
|
|
0eb1662a0e | ||
|
|
164ec25a75 | ||
|
|
6fb36d6c02 | ||
|
|
ea1f959ad5 | ||
|
|
7cf3b3455b |
@@ -18,5 +18,18 @@ staging_prepare/*
|
||||
staging_trans/*
|
||||
tools/python_zip/*
|
||||
Makefile
|
||||
html
|
||||
*.vcxproj
|
||||
*.pdb
|
||||
*.dll
|
||||
*.exp
|
||||
*.tlog
|
||||
*.user
|
||||
*.obj
|
||||
*.suo
|
||||
*.sln
|
||||
*.log
|
||||
*.filters
|
||||
*.lib
|
||||
syntax: regexp
|
||||
Makefile\.(Debug|Release)
|
||||
|
||||
+33
-10
@@ -22,6 +22,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include <QRegExp>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <boost/assign.hpp>
|
||||
|
||||
|
||||
namespace BBCode {
|
||||
@@ -43,7 +44,6 @@ public:
|
||||
// extract the tag name
|
||||
m_TagNameExp.indexIn(input, 1, QRegExp::CaretAtOffset);
|
||||
QString tagName = m_TagNameExp.cap(0).toLower();
|
||||
//qDebug("tag name %s", tagName.toUtf8().constData());
|
||||
TagMap::iterator tagIter = m_TagMap.find(tagName);
|
||||
if (tagIter != m_TagMap.end()) {
|
||||
// recognized tag
|
||||
@@ -60,7 +60,21 @@ public:
|
||||
length = closeTagPos + closeTag.length();
|
||||
QString temp = input.mid(0, length);
|
||||
if (tagIter->second.first.indexIn(temp) == 0) {
|
||||
return temp.replace(tagIter->second.first, tagIter->second.second);
|
||||
if (tagIter->second.second.isEmpty()) {
|
||||
if (tagName == "color") {
|
||||
QString color = tagIter->second.first.cap(1);
|
||||
QString content = tagIter->second.first.cap(2);
|
||||
auto colIter = m_ColorMap.find(color.toLower());
|
||||
if (colIter != m_ColorMap.end()) {
|
||||
color = colIter->second;
|
||||
}
|
||||
return temp.replace(tagIter->second.first, QString("<font style=\"color: #%1;\">%2</font>").arg(color, content));
|
||||
} else {
|
||||
qWarning("don't know how to deal with tag %s", qPrintable(tagName));
|
||||
}
|
||||
} else {
|
||||
return temp.replace(tagIter->second.first, tagIter->second.second);
|
||||
}
|
||||
} else {
|
||||
// expression doesn't match. either the input string is invalid
|
||||
// or the expression is
|
||||
@@ -96,7 +110,7 @@ private:
|
||||
m_TagMap["size="] = std::make_pair(QRegExp("\\[size=([^\\]]*)\\](.*)\\[/size\\]"),
|
||||
"<font size=\"\\1\">\\2</font>");
|
||||
m_TagMap["color="] = std::make_pair(QRegExp("\\[color=([^\\]]*)\\](.*)\\[/color\\]"),
|
||||
"<font style=\"color: #\\1;\">\\2</font>");
|
||||
"");
|
||||
m_TagMap["font="] = std::make_pair(QRegExp("\\[font=([^\\]]*)\\](.*)\\[/font\\]"),
|
||||
"<font face=\\1>\\2</font>");
|
||||
m_TagMap["center"] = std::make_pair(QRegExp("\\[center\\](.*)\\[/center\\]"),
|
||||
@@ -139,17 +153,25 @@ private:
|
||||
"<a href=\"\\1\">\\1</a>");
|
||||
m_TagMap["url="] = std::make_pair(QRegExp("\\[url=([^\\]]*)\\](.*)\\[/url\\]"),
|
||||
"<a href=\"\\1\">\\2</a>");
|
||||
/* m_TagMap["img"] = std::make_pair(QRegExp("\\[img\\](.*)\\[/img\\]"),
|
||||
"<img src=\"\\1\"/>");
|
||||
m_TagMap["img="] = std::make_pair(QRegExp("\\[img=([^\\]]*)\\](.*)\\[/img\\]"),
|
||||
"<img src=\"\\2\" align=\"\\1\" />");*/
|
||||
m_TagMap["img"] = std::make_pair(QRegExp("\\[img\\](.*)\\[/img\\]"), "");
|
||||
m_TagMap["img="] = std::make_pair(QRegExp("\\[img=([^\\]]*)\\](.*)\\[/img\\]"), "");
|
||||
m_TagMap["img"] = std::make_pair(QRegExp("\\[img\\](.*)\\[/img\\]"), " ");
|
||||
m_TagMap["img="] = std::make_pair(QRegExp("\\[img=([^\\]]*)\\](.*)\\[/img\\]"), " ");
|
||||
m_TagMap["email="] = std::make_pair(QRegExp("\\[email=\"?([^\\]]*)\"?\\](.*)\\[/email\\]"),
|
||||
"<a href=\"mailto:\\1\">\\2</a>");
|
||||
m_TagMap["youtube"] = std::make_pair(QRegExp("\\[youtube\\](.*)\\[/youtube\\]"),
|
||||
"<a href=\"http://www.youtube.com/v/\\1\">http://www.youtube.com/v/\\1</a>");
|
||||
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("red", "FF0000"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("green", "00FF00"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("blue", "0000FF"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("black", "000000"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("gray", "7F7F7F"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("white", "FFFFFF"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("yellow", "FFFF00"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("cyan", "00FFFF"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("magenta", "FF00FF"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("brown", "A52A2A"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("orange", "FFCC00"));
|
||||
|
||||
// make all patterns non-greedy and case-insensitive
|
||||
for (TagMap::iterator iter = m_TagMap.begin(); iter != m_TagMap.end(); ++iter) {
|
||||
iter->second.first.setCaseSensitivity(Qt::CaseInsensitive);
|
||||
@@ -157,10 +179,11 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
QRegExp m_TagNameExp;
|
||||
TagMap m_TagMap;
|
||||
std::map<QString, QString> m_ColorMap;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
BrowserDialog::BrowserDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::BrowserDialog)
|
||||
, m_AccessManager(new QNetworkAccessManager)
|
||||
, m_AccessManager(new QNetworkAccessManager(this))
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
@@ -255,16 +255,16 @@ void BrowserDialog::on_searchEdit_returnPressed()
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserDialog::on_browserTabWidget_currentChanged(QWidget *current)
|
||||
void BrowserDialog::on_refreshBtn_clicked()
|
||||
{
|
||||
BrowserView *currentView = qobject_cast<BrowserView*>(current);
|
||||
getCurrentView()->reload();
|
||||
}
|
||||
|
||||
void BrowserDialog::on_browserTabWidget_currentChanged(int index)
|
||||
{
|
||||
BrowserView *currentView = qobject_cast<BrowserView*>(ui->browserTabWidget->widget(index));
|
||||
if (currentView != NULL) {
|
||||
ui->backBtn->setEnabled(currentView->history()->canGoBack());
|
||||
ui->fwdBtn->setEnabled(currentView->history()->canGoForward());
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserDialog::on_refreshBtn_clicked()
|
||||
{
|
||||
getCurrentView()->reload();
|
||||
}
|
||||
|
||||
+2
-2
@@ -99,10 +99,10 @@ private slots:
|
||||
|
||||
void startSearch();
|
||||
|
||||
void on_browserTabWidget_currentChanged(QWidget *arg1);
|
||||
|
||||
void on_refreshBtn_clicked();
|
||||
|
||||
void on_browserTabWidget_currentChanged(int index);
|
||||
|
||||
private:
|
||||
|
||||
QString guessFileName(const QString &url);
|
||||
|
||||
@@ -47,6 +47,8 @@ public:
|
||||
static const int CATEGORY_SPECIAL_NOCATEGORY = 10003;
|
||||
static const int CATEGORY_SPECIAL_CONFLICT = 10004;
|
||||
static const int CATEGORY_SPECIAL_NOTENDORSED = 10005;
|
||||
static const int CATEGORY_SPECIAL_MANAGED = 10006;
|
||||
static const int CATEGORY_SPECIAL_UNMANAGED = 10007;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
+62
-18
@@ -20,8 +20,10 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "directoryrefresher.h"
|
||||
#include "utility.h"
|
||||
#include "report.h"
|
||||
#include "modinfo.h"
|
||||
#include <gameinfo.h>
|
||||
#include <QDir>
|
||||
#include <QString>
|
||||
|
||||
|
||||
using namespace MOBase;
|
||||
@@ -46,12 +48,20 @@ 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_Mods.clear();
|
||||
for (auto mod = mods.begin(); mod != mods.end(); ++mod) {
|
||||
QString name = std::get<0>(*mod);
|
||||
ModInfo::Ptr info = ModInfo::getByIndex(ModInfo::getIndex(name));
|
||||
m_Mods.push_back(EntryInfo(name, std::get<1>(*mod), info->stealFiles(), info->archives(), std::get<2>(*mod)));
|
||||
}
|
||||
|
||||
m_EnabledArchives = managedArchives;
|
||||
}
|
||||
|
||||
void DirectoryRefresher::cleanStructure(DirectoryEntry *structure)
|
||||
{
|
||||
@@ -61,24 +71,59 @@ void DirectoryRefresher::cleanStructure(DirectoryEntry *structure)
|
||||
}
|
||||
|
||||
static wchar_t *dirs[] = { L"fomod" };
|
||||
for (int i = 0; i < sizeof(files) / sizeof(wchar_t*); ++i) {
|
||||
structure->removeDir(dirs[i]);
|
||||
for (int i = 0; i < sizeof(dirs) / sizeof(wchar_t*); ++i) {
|
||||
structure->removeDir(std::wstring(dirs[i]));
|
||||
}
|
||||
}
|
||||
|
||||
void DirectoryRefresher::addModToStructure(DirectoryEntry *directoryStructure, const QString &modName, int priority, const QString &directory)
|
||||
void DirectoryRefresher::addModBSAToStructure(DirectoryEntry *directoryStructure, const QString &modName, int priority, const QString &directory, const QStringList &archives)
|
||||
{
|
||||
std::wstring directoryW = ToWString(QDir::toNativeSeparators(directory));
|
||||
|
||||
directoryStructure->addFromOrigin(ToWString(modName), directoryW, priority);
|
||||
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);
|
||||
foreach (const QString &archive, archives) {
|
||||
QFileInfo fileInfo(archive);
|
||||
if (m_EnabledArchives.find(fileInfo.fileName()) != m_EnabledArchives.end()) {
|
||||
directoryStructure->addFromBSA(ToWString(modName), directoryW,
|
||||
ToWString(QDir::toNativeSeparators(fileInfo.absoluteFilePath())), priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DirectoryRefresher::addModFilesToStructure(DirectoryEntry *directoryStructure, const QString &modName, int priority, const QString &directory, const QStringList &stealFiles)
|
||||
{
|
||||
std::wstring directoryW = ToWString(QDir::toNativeSeparators(directory));
|
||||
|
||||
if (stealFiles.length() > 0) {
|
||||
// instead of adding all the files of the target directory, we just change the root of the specified
|
||||
// files to this mod
|
||||
FilesOrigin origin = directoryStructure->createOrigin(ToWString(modName), directoryW, priority);
|
||||
foreach (const QString &filename, stealFiles) {
|
||||
QFileInfo fileInfo(filename);
|
||||
FileEntry::Ptr file = directoryStructure->findFile(ToWString(fileInfo.fileName()));
|
||||
if (file.get() != NULL) {
|
||||
if (file->getOrigin() == 0) {
|
||||
// replace data as the origin on this bsa
|
||||
file->removeOrigin(0);
|
||||
file->addOrigin(origin.getID(), file->getFileTime(), L"");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
directoryStructure->addFromOrigin(ToWString(modName), directoryW, priority);
|
||||
}
|
||||
}
|
||||
|
||||
void DirectoryRefresher::addModToStructure(DirectoryEntry *directoryStructure
|
||||
, const QString &modName
|
||||
, int priority
|
||||
, const QString &directory
|
||||
, const QStringList &stealFiles
|
||||
, const QStringList &archives)
|
||||
{
|
||||
addModFilesToStructure(directoryStructure, modName, priority, directory, stealFiles);
|
||||
addModBSAToStructure(directoryStructure, modName, priority, directory, archives);
|
||||
}
|
||||
|
||||
void DirectoryRefresher::refresh()
|
||||
{
|
||||
QMutexLocker locker(&m_RefreshLock);
|
||||
@@ -87,23 +132,22 @@ void DirectoryRefresher::refresh()
|
||||
|
||||
m_DirectoryStructure = new DirectoryEntry(L"data", NULL, 0);
|
||||
|
||||
std::wstring dataDirectory = GameInfo::instance().getGameDirectory() + L"\\data";
|
||||
m_DirectoryStructure->addFromOrigin(L"data", dataDirectory, 0);
|
||||
|
||||
// TODO what was the point of having the priority in this tuple? the list is already sorted by priority
|
||||
std::vector<std::tuple<QString, QString, int> >::const_iterator iter = m_Mods.begin();
|
||||
auto iter = m_Mods.begin();
|
||||
|
||||
//TODO i is the priority here, where higher = more important. the input vector is also sorted by priority but inverted!
|
||||
for (int i = 1; iter != m_Mods.end(); ++iter, ++i) {
|
||||
QString modName = std::get<0>(*iter);
|
||||
try {
|
||||
addModToStructure(m_DirectoryStructure, modName, i, std::get<1>(*iter));
|
||||
addModToStructure(m_DirectoryStructure, iter->modName, i, iter->absolutePath, iter->stealFiles, iter->archives);
|
||||
} catch (const std::exception &e) {
|
||||
emit error(tr("failed to read bsa: %1").arg(e.what()));
|
||||
}
|
||||
emit progress((i * 100) / m_Mods.size() + 1);
|
||||
}
|
||||
|
||||
std::wstring dataDirectory = GameInfo::instance().getGameDirectory() + L"\\data";
|
||||
m_DirectoryStructure->addFromOrigin(L"data", dataDirectory, 0);
|
||||
|
||||
emit progress(100);
|
||||
|
||||
cleanStructure(m_DirectoryStructure);
|
||||
|
||||
@@ -20,11 +20,13 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
#ifndef DIRECTORYREFRESHER_H
|
||||
#define DIRECTORYREFRESHER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <vector>
|
||||
#include <QMutex>
|
||||
#include <tuple>
|
||||
#include <directoryentry.h>
|
||||
#include <QObject>
|
||||
#include <QMutex>
|
||||
#include <QStringList>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <tuple>
|
||||
|
||||
|
||||
/**
|
||||
@@ -60,7 +62,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
|
||||
@@ -77,12 +79,34 @@ public:
|
||||
|
||||
/**
|
||||
* @brief add files for a mod to the directory structure, including bsas
|
||||
* @param directoryStructure
|
||||
* @param modName
|
||||
* @param priorityBSA
|
||||
* @param priority
|
||||
* @param directory
|
||||
* @param priorityDir
|
||||
* @param stealFiles
|
||||
* @param archives
|
||||
*/
|
||||
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, const QStringList &stealFiles, const QStringList &archives);
|
||||
|
||||
/**
|
||||
* @brief add only the bsas of a mod to the directory structure
|
||||
* @param directoryStructure
|
||||
* @param modName
|
||||
* @param priority
|
||||
* @param directory
|
||||
* @param archives
|
||||
*/
|
||||
void addModBSAToStructure(MOShared::DirectoryEntry *directoryStructure, const QString &modName, int priority, const QString &directory, const QStringList &archives);
|
||||
|
||||
/**
|
||||
* @brief add only regular files ofr a mod to the directory structure
|
||||
* @param directoryStructure
|
||||
* @param modName
|
||||
* @param priority
|
||||
* @param directory
|
||||
* @param stealFiles
|
||||
*/
|
||||
void addModFilesToStructure(MOShared::DirectoryEntry *directoryStructure, const QString &modName, int priority, const QString &directory, const QStringList &stealFiles);
|
||||
|
||||
public slots:
|
||||
|
||||
@@ -99,7 +123,22 @@ signals:
|
||||
|
||||
private:
|
||||
|
||||
std::vector<std::tuple<QString, QString, int> > m_Mods;
|
||||
struct EntryInfo {
|
||||
EntryInfo(const QString &modName, const QString &absolutePath,
|
||||
const QStringList &stealFiles, const QStringList &archives, int priority)
|
||||
: modName(modName), absolutePath(absolutePath), stealFiles(stealFiles)
|
||||
, archives(archives), priority(priority) {}
|
||||
QString modName;
|
||||
QString absolutePath;
|
||||
QStringList stealFiles;
|
||||
QStringList archives;
|
||||
int priority;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
std::vector<EntryInfo> m_Mods;
|
||||
std::set<QString> m_EnabledArchives;
|
||||
MOShared::DirectoryEntry *m_DirectoryStructure;
|
||||
QMutex m_RefreshLock;
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity type="win32" name="dlls" version="1.0.0.0" processorArchitecture="x86"/>
|
||||
<file name="icuin49.dll"/>
|
||||
<file name="icuuc49.dll"/>
|
||||
<file name="icudt49.dll"/>
|
||||
<file name="icuin52.dll"/>
|
||||
<file name="icuuc52.dll"/>
|
||||
<file name="icudt52.dll"/>
|
||||
<file name="Qt5Core.dll"/>
|
||||
<file name="Qt5Declarative.dll"/>
|
||||
<file name="Qt5Gui.dll"/>
|
||||
@@ -14,4 +14,4 @@
|
||||
<file name="Qt5Widgets.dll"/>
|
||||
<file name="Qt5Xml.dll"/>
|
||||
<file name="Qt5XmlPatterns.dll"/>
|
||||
</assembly>
|
||||
</assembly>
|
||||
@@ -82,7 +82,7 @@ QVariant DownloadList::data(const QModelIndex &index, int role) const
|
||||
text += tr("Information missing, please select \"Query Info\" from the context menu to re-retrieve.");
|
||||
} else {
|
||||
const MOBase::ModRepositoryFileInfo *info = m_Manager->getFileInfo(index.row());
|
||||
return QString("%1 (ID %2) %3").arg(info->modName).arg(m_Manager->getModID(index.row())).arg(info->version.canonicalString());
|
||||
return QString("%1 (ID %2) %3<br><span>%4</span>").arg(info->modName).arg(m_Manager->getModID(index.row())).arg(info->version.canonicalString()).arg(info->description);
|
||||
}
|
||||
return text;
|
||||
} else {
|
||||
|
||||
+123
-84
@@ -26,6 +26,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "utility.h"
|
||||
#include "json.h"
|
||||
#include "selectiondialog.h"
|
||||
#include "bbcode.h"
|
||||
#include <utility.h>
|
||||
#include <QTimer>
|
||||
#include <QFileInfo>
|
||||
@@ -147,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()
|
||||
@@ -252,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;
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
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;
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
if (Exists) {
|
||||
qDebug("%s exists", qPrintable(file));
|
||||
continue;
|
||||
|
||||
QStringList nameFilters(m_SupportedExtensions);
|
||||
foreach (const QString &extension, m_SupportedExtensions) {
|
||||
nameFilters.append("*." + extension);
|
||||
}
|
||||
|
||||
QString fileName = QDir::fromNativeSeparators(m_OutputDirectory) + "/" + file;
|
||||
nameFilters.append(QString("*").append(UNFINISHED));
|
||||
QDir dir(QDir::fromNativeSeparators(m_OutputDirectory));
|
||||
|
||||
DownloadInfo *info = DownloadInfo::createFromMeta(fileName, m_ShowHidden);
|
||||
if (info != NULL) {
|
||||
m_ActiveDownloads.push_front(info);
|
||||
// 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 (orphans.size() > 0) {
|
||||
qDebug("%d orphaned meta files will be deleted", orphans.size());
|
||||
shellDelete(orphans, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_ActiveDownloads.size() != downloadsBefore) {
|
||||
qDebug("downloads after refresh: %d", m_ActiveDownloads.size());
|
||||
// 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;
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
emit update(-1);
|
||||
} catch (const std::bad_alloc&) {
|
||||
reportError(tr("Memory allocation error (in refreshing directory)."));
|
||||
}
|
||||
emit update(-1);
|
||||
}
|
||||
|
||||
|
||||
@@ -391,6 +398,7 @@ void DownloadManager::removePending(int modID, int fileID)
|
||||
|
||||
void DownloadManager::startDownload(QNetworkReply *reply, DownloadInfo *newDownload, bool resume)
|
||||
{
|
||||
reply->setReadBufferSize(1024 * 1024); // don't read more than 1MB at once to avoid memory troubles
|
||||
newDownload->m_Reply = reply;
|
||||
setState(newDownload, STATE_DOWNLOADING);
|
||||
if (newDownload->m_Urls.count() == 0) {
|
||||
@@ -403,6 +411,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")
|
||||
@@ -412,6 +421,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()));
|
||||
|
||||
@@ -420,11 +430,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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,7 +461,7 @@ void DownloadManager::addNXMDownload(const QString &url)
|
||||
|
||||
emit update(-1);
|
||||
emit downloadAdded();
|
||||
m_RequestIDs.insert(m_NexusInterface->requestFileInfo(nxmInfo.modId(), nxmInfo.fileId(), this, nxmInfo.fileId()));
|
||||
m_RequestIDs.insert(m_NexusInterface->requestFileInfo(nxmInfo.modId(), nxmInfo.fileId(), this, nxmInfo.fileId(), ""));
|
||||
}
|
||||
|
||||
|
||||
@@ -592,8 +606,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);
|
||||
}
|
||||
@@ -618,6 +635,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();
|
||||
}
|
||||
@@ -918,10 +940,10 @@ void DownloadManager::setState(DownloadManager::DownloadInfo *info, DownloadMana
|
||||
info->m_Reply->abort();
|
||||
} break;
|
||||
case STATE_FETCHINGMODINFO: {
|
||||
m_RequestIDs.insert(m_NexusInterface->requestDescription(info->m_FileInfo->modID, this, info->m_DownloadID));
|
||||
m_RequestIDs.insert(m_NexusInterface->requestDescription(info->m_FileInfo->modID, this, info->m_DownloadID, QString()));
|
||||
} break;
|
||||
case STATE_FETCHINGFILEINFO: {
|
||||
m_RequestIDs.insert(m_NexusInterface->requestFiles(info->m_FileInfo->modID, this, info->m_DownloadID));
|
||||
m_RequestIDs.insert(m_NexusInterface->requestFiles(info->m_FileInfo->modID, this, info->m_DownloadID, QString()));
|
||||
} break;
|
||||
case STATE_READY: {
|
||||
createMetaFile(info);
|
||||
@@ -954,32 +976,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)."));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1159,14 +1189,14 @@ void DownloadManager::nxmFileInfoAvailable(int modID, int fileID, QVariant userD
|
||||
info->fileName = result["uri"].toString();
|
||||
info->fileCategory = result["category_id"].toInt();
|
||||
info->fileTime = matchDate(result["date"].toString());
|
||||
info->description = result["description"].toString();
|
||||
info->description = BBCode::convertToHTML(result["description"].toString());
|
||||
|
||||
info->repository = "Nexus";
|
||||
info->modID = modID;
|
||||
info->fileID = fileID;
|
||||
|
||||
QObject *test = info;
|
||||
m_RequestIDs.insert(m_NexusInterface->requestDownloadURL(modID, fileID, this, qVariantFromValue(test)));
|
||||
m_RequestIDs.insert(m_NexusInterface->requestDownloadURL(modID, fileID, this, qVariantFromValue(test), QString()));
|
||||
}
|
||||
|
||||
|
||||
@@ -1266,7 +1296,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);
|
||||
}
|
||||
|
||||
@@ -1308,8 +1337,11 @@ void DownloadManager::downloadFinished()
|
||||
DownloadInfo *info = findDownload(this->sender(), &index);
|
||||
if (info != NULL) {
|
||||
QNetworkReply *reply = info->m_Reply;
|
||||
QByteArray data = info->m_Reply->readAll();
|
||||
info->m_Output.write(data);
|
||||
QByteArray data;
|
||||
if (reply->isOpen()) {
|
||||
data = reply->readAll();
|
||||
info->m_Output.write(data);
|
||||
}
|
||||
info->m_Output.close();
|
||||
TaskProgressManager::instance().forgetMe(info->m_TaskProgressId);
|
||||
|
||||
@@ -1355,7 +1387,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()) {
|
||||
@@ -1405,6 +1436,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;
|
||||
@@ -1415,7 +1454,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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -522,9 +522,10 @@ bool InstallationManager::doInstall(GuessedValue<QString> &modName, int modID,
|
||||
return false;
|
||||
}
|
||||
|
||||
QString targetDirectory = QDir::fromNativeSeparators(m_ModsDirectory.mid(0).append("\\").append(modName));
|
||||
QString targetDirectoryNative = m_ModsDirectory.mid(0).append("\\").append(modName);
|
||||
QString targetDirectory = QDir::fromNativeSeparators(targetDirectoryNative);
|
||||
|
||||
qDebug("installing to \"%s\"", targetDirectory.toUtf8().constData());
|
||||
qDebug("installing to \"%s\"", targetDirectoryNative.toUtf8().constData());
|
||||
|
||||
m_InstallationProgress.setWindowTitle(tr("Extracting files"));
|
||||
m_InstallationProgress.setLabelText(QString());
|
||||
|
||||
+106
-18
@@ -21,6 +21,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "report.h"
|
||||
#include <QMutexLocker>
|
||||
#include <QFile>
|
||||
#include <QIcon>
|
||||
#include <QDateTime>
|
||||
#include <Windows.h>
|
||||
|
||||
@@ -29,7 +30,7 @@ QMutex LogBuffer::s_Mutex;
|
||||
|
||||
|
||||
LogBuffer::LogBuffer(int messageCount, QtMsgType minMsgType, const QString &outputFileName)
|
||||
: QObject(NULL), m_OutFileName(outputFileName), m_ShutDown(false),
|
||||
: QAbstractItemModel(NULL), m_OutFileName(outputFileName), m_ShutDown(false),
|
||||
m_MinMsgType(minMsgType), m_NumMessages(0)
|
||||
{
|
||||
m_Messages.resize(messageCount);
|
||||
@@ -51,7 +52,16 @@ LogBuffer::~LogBuffer()
|
||||
void LogBuffer::logMessage(QtMsgType type, const QString &message)
|
||||
{
|
||||
if (type >= m_MinMsgType) {
|
||||
m_Messages.at(m_NumMessages % m_Messages.size()) = message;
|
||||
Message msg = { type, QTime::currentTime(), message };
|
||||
if (m_NumMessages < m_Messages.size()) {
|
||||
beginInsertRows(QModelIndex(), m_NumMessages, m_NumMessages + 1);
|
||||
}
|
||||
m_Messages.at(m_NumMessages % m_Messages.size()) = msg;
|
||||
if (m_NumMessages < m_Messages.size()) {
|
||||
endInsertRows();
|
||||
} else {
|
||||
emit dataChanged(createIndex(0, 0), createIndex(m_Messages.size(), 0));
|
||||
}
|
||||
++m_NumMessages;
|
||||
if (type >= QtCriticalMsg) {
|
||||
write();
|
||||
@@ -77,7 +87,7 @@ void LogBuffer::write() const
|
||||
unsigned int i = (m_NumMessages > m_Messages.size()) ? m_NumMessages - m_Messages.size()
|
||||
: 0U;
|
||||
for (; i < m_NumMessages; ++i) {
|
||||
file.write(m_Messages.at(i % m_Messages.size()).toUtf8());
|
||||
file.write(m_Messages.at(i % m_Messages.size()).toString().toUtf8());
|
||||
file.write("\r\n");
|
||||
}
|
||||
::SetLastError(lastError);
|
||||
@@ -99,21 +109,6 @@ void LogBuffer::init(int messageCount, QtMsgType minMsgType, const QString &outp
|
||||
#endif
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
|
||||
void LogBuffer::log(QtMsgType type, const QMessageLogContext &context, const QString &message)
|
||||
{
|
||||
QMutexLocker guard(&s_Mutex);
|
||||
if (!s_Instance.isNull()) {
|
||||
s_Instance->logMessage(type, message);
|
||||
}
|
||||
fprintf(stdout, "(%s:%u) %s\n", context.file, context.line, qPrintable(message));
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
|
||||
char LogBuffer::msgTypeID(QtMsgType type)
|
||||
{
|
||||
switch (type) {
|
||||
@@ -125,6 +120,26 @@ char LogBuffer::msgTypeID(QtMsgType type)
|
||||
}
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
|
||||
void LogBuffer::log(QtMsgType type, const QMessageLogContext &context, const QString &message)
|
||||
{
|
||||
QMutexLocker guard(&s_Mutex);
|
||||
if (!s_Instance.isNull()) {
|
||||
s_Instance->logMessage(type, message);
|
||||
}
|
||||
// fprintf(stdout, "(%s:%u) %s\n", context.file, context.line, qPrintable(message));
|
||||
if (type == QtDebugMsg) {
|
||||
fprintf(stdout, "%s [%c] %s\n", qPrintable(QTime::currentTime().toString()), msgTypeID(type), qPrintable(message));
|
||||
} else {
|
||||
fprintf(stdout, "%s [%c] (%s:%u) %s\n", qPrintable(QTime::currentTime().toString()), msgTypeID(type),
|
||||
context.file, context.line, qPrintable(message));
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void LogBuffer::log(QtMsgType type, const char *message)
|
||||
{
|
||||
QMutexLocker guard(&s_Mutex);
|
||||
@@ -137,6 +152,73 @@ void LogBuffer::log(QtMsgType type, const char *message)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
QModelIndex LogBuffer::index(int row, int column, const QModelIndex&) const
|
||||
{
|
||||
return createIndex(row, column, row);
|
||||
}
|
||||
|
||||
QModelIndex LogBuffer::parent(const QModelIndex&) const
|
||||
{
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
int LogBuffer::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
else
|
||||
return std::min(m_NumMessages, m_Messages.size());
|
||||
}
|
||||
|
||||
int LogBuffer::columnCount(const QModelIndex&) const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
QVariant LogBuffer::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
unsigned offset = m_NumMessages < m_Messages.size() ? 0
|
||||
: m_NumMessages - m_Messages.size();
|
||||
unsigned int msgIndex = (offset + index.row() + 1) % m_Messages.size();
|
||||
switch (role) {
|
||||
case Qt::DisplayRole: {
|
||||
if (index.column() == 0) {
|
||||
return m_Messages.at(msgIndex).time;
|
||||
} else if (index.column() == 1) {
|
||||
const QString &msg = m_Messages.at(msgIndex).message;
|
||||
if (msg.length() < 200) {
|
||||
return msg;
|
||||
} else {
|
||||
return msg.mid(0, 200) + "...";
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case Qt::DecorationRole: {
|
||||
if (index.column() == 1) {
|
||||
switch (m_Messages.at(msgIndex).type) {
|
||||
case QtDebugMsg: return QIcon(":/MO/gui/information");
|
||||
case QtWarningMsg: return QIcon(":/MO/gui/warning");
|
||||
case QtCriticalMsg: return QIcon(":/MO/gui/important");
|
||||
case QtFatalMsg: return QIcon(":/MO/gui/problem");
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case Qt::UserRole: {
|
||||
if (index.column() == 1) {
|
||||
switch (m_Messages.at(msgIndex).type) {
|
||||
case QtDebugMsg: return "D";
|
||||
case QtWarningMsg: return "W";
|
||||
case QtCriticalMsg: return "C";
|
||||
case QtFatalMsg: return "F";
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void LogBuffer::writeNow()
|
||||
{
|
||||
QMutexLocker guard(&s_Mutex);
|
||||
@@ -171,3 +253,9 @@ void log(const char *format, ...)
|
||||
va_end(argList);
|
||||
}
|
||||
|
||||
|
||||
|
||||
QString LogBuffer::Message::toString() const
|
||||
{
|
||||
return QString("%1 [%2] %3").arg(time.toString()).arg(msgTypeID(type)).arg(message);
|
||||
}
|
||||
|
||||
+23
-2
@@ -23,10 +23,12 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include <QObject>
|
||||
#include <QMutex>
|
||||
#include <QScopedPointer>
|
||||
#include <QStringListModel>
|
||||
#include <QTime>
|
||||
#include <vector>
|
||||
|
||||
|
||||
class LogBuffer : public QObject
|
||||
class LogBuffer : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -42,12 +44,22 @@ public:
|
||||
static void writeNow();
|
||||
static void cleanQuit();
|
||||
|
||||
static LogBuffer *instance() { return s_Instance.data(); }
|
||||
|
||||
public:
|
||||
|
||||
virtual ~LogBuffer();
|
||||
|
||||
void logMessage(QtMsgType type, const QString &message);
|
||||
|
||||
// QAbstractItemModel interface
|
||||
public:
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent) const;
|
||||
QModelIndex parent(const QModelIndex &child) const;
|
||||
int rowCount(const QModelIndex &parent) const;
|
||||
int columnCount(const QModelIndex &parent) const;
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
@@ -62,6 +74,15 @@ private:
|
||||
|
||||
static char msgTypeID(QtMsgType type);
|
||||
|
||||
private:
|
||||
|
||||
struct Message {
|
||||
QtMsgType type;
|
||||
QTime time;
|
||||
QString message;
|
||||
QString toString() const;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
static QScopedPointer<LogBuffer> s_Instance;
|
||||
@@ -71,7 +92,7 @@ private:
|
||||
bool m_ShutDown;
|
||||
QtMsgType m_MinMsgType;
|
||||
unsigned int m_NumMessages;
|
||||
std::vector<QString> m_Messages;
|
||||
std::vector<Message> m_Messages;
|
||||
|
||||
};
|
||||
|
||||
|
||||
+4
-6
@@ -174,7 +174,9 @@ void cleanupDir()
|
||||
"QtXml4.dll",
|
||||
"QtWebKit4.dll",
|
||||
"qjpeg4.dll",
|
||||
"NCC/GamebryoBase.dll"
|
||||
"NCC/GamebryoBase.dll",
|
||||
"plugins/helloWorld.dll",
|
||||
"plugins/testnexus.py"
|
||||
};
|
||||
|
||||
static const int NUM_FILES = sizeof(fileNames) / sizeof(QString);
|
||||
@@ -195,7 +197,6 @@ bool isNxmLink(const QString &link)
|
||||
return link.left(6).toLower() == "nxm://";
|
||||
}
|
||||
|
||||
|
||||
LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *exceptionPtrs)
|
||||
{
|
||||
typedef BOOL (WINAPI *FuncMiniDumpWriteDump)(HANDLE process, DWORD pid, HANDLE file, MINIDUMP_TYPE dumpType,
|
||||
@@ -257,14 +258,11 @@ LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *exceptionPtrs
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void registerMetaTypes()
|
||||
{
|
||||
registerExecutable();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool HaveWriteAccess(const std::wstring &path)
|
||||
{
|
||||
bool writable = false;
|
||||
@@ -333,7 +331,7 @@ int main(int argc, char *argv[])
|
||||
, ToWString(QDir::currentPath()).c_str(), SW_SHOWNORMAL);
|
||||
return 1;
|
||||
}
|
||||
LogBuffer::init(200, QtDebugMsg, application.applicationDirPath() + "/logs/mo_interface.log");
|
||||
LogBuffer::init(100, QtDebugMsg, application.applicationDirPath() + "/logs/mo_interface.log");
|
||||
|
||||
qDebug("Working directory: %s", qPrintable(QDir::toNativeSeparators(QDir::currentPath())));
|
||||
qDebug("MO at: %s", qPrintable(QDir::toNativeSeparators(application.applicationDirPath())));
|
||||
|
||||
+629
-627
File diff suppressed because it is too large
Load Diff
+52
-39
@@ -64,11 +64,13 @@ class ModListSortProxy;
|
||||
class ModListGroupCategoriesProxy;
|
||||
|
||||
|
||||
class MainWindow : public QMainWindow, public MOBase::IOrganizer, public MOBase::IPluginDiagnose
|
||||
class MainWindow : public QMainWindow, public MOBase::IPluginDiagnose
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(MOBase::IPluginDiagnose)
|
||||
|
||||
friend class OrganizerProxy;
|
||||
|
||||
private:
|
||||
|
||||
struct SignalCombinerAnd
|
||||
@@ -88,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);
|
||||
@@ -96,8 +99,6 @@ public:
|
||||
void readSettings();
|
||||
|
||||
bool addProfile();
|
||||
void refreshLists();
|
||||
void refreshESPList();
|
||||
void refreshBSAList();
|
||||
void refreshDataTree();
|
||||
void refreshSaveList();
|
||||
@@ -117,34 +118,6 @@ public:
|
||||
|
||||
void loadPlugins();
|
||||
|
||||
virtual MOBase::IGameInfo &gameInfo() const;
|
||||
virtual MOBase::IModRepositoryBridge *createNexusBridge() const;
|
||||
virtual QString profileName() const;
|
||||
virtual QString profilePath() const;
|
||||
virtual QString downloadsPath() const;
|
||||
virtual MOBase::VersionInfo appVersion() const;
|
||||
virtual MOBase::IModInterface *getMod(const QString &name);
|
||||
virtual MOBase::IModInterface *createMod(MOBase::GuessedValue<QString> &name);
|
||||
virtual bool removeMod(MOBase::IModInterface *mod);
|
||||
virtual void modDataChanged(MOBase::IModInterface *mod);
|
||||
virtual QVariant pluginSetting(const QString &pluginName, const QString &key) const;
|
||||
virtual void setPluginSetting(const QString &pluginName, const QString &key, const QVariant &value);
|
||||
virtual QVariant persistent(const QString &pluginName, const QString &key, const QVariant &def = QVariant()) const;
|
||||
virtual void setPersistent(const QString &pluginName, const QString &key, const QVariant &value, bool sync = true);
|
||||
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 QList<FileInfo> findFileInfos(const QString &path, const std::function<bool(const FileInfo&)> &filter) const;
|
||||
|
||||
virtual MOBase::IDownloadManager *downloadManager();
|
||||
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 = true);
|
||||
|
||||
virtual std::vector<unsigned int> activeProblems() const;
|
||||
virtual QString shortDescription(unsigned int key) const;
|
||||
virtual QString fullDescription(unsigned int key) const;
|
||||
@@ -153,13 +126,20 @@ public:
|
||||
|
||||
void addPrimaryCategoryCandidates(QMenu *primaryCategoryMenu, ModInfo::Ptr info);
|
||||
|
||||
void saveArchiveList();
|
||||
bool saveArchiveList();
|
||||
|
||||
void createStdoutPipe(HANDLE *stdOutRead, HANDLE *stdOutWrite);
|
||||
std::string readFromPipe(HANDLE stdOutRead);
|
||||
void processLOOTOut(const std::string &lootOut, std::string &reportURL, std::string &errorMessages, QProgressDialog &dialog);
|
||||
|
||||
HANDLE startApplication(const QString &executable, const QStringList &args = QStringList(), const QString &cwd = "", const QString &profile = "");
|
||||
|
||||
void updateModInDirectoryStructure(unsigned int index, ModInfo::Ptr modInfo);
|
||||
|
||||
public slots:
|
||||
|
||||
void refreshLists();
|
||||
|
||||
void displayColumnSelection(const QPoint &pos);
|
||||
|
||||
void externalMessage(const QString &message);
|
||||
@@ -200,6 +180,9 @@ protected:
|
||||
|
||||
private:
|
||||
|
||||
void refreshESPList();
|
||||
void refreshModList(bool saveChanges = true);
|
||||
|
||||
void actionToToolButton(QAction *&sourceAction);
|
||||
bool verifyPlugin(MOBase::IPlugin *plugin);
|
||||
void registerPluginTool(MOBase::IPluginTool *tool);
|
||||
@@ -211,8 +194,6 @@ private:
|
||||
|
||||
void setExecutableIndex(int index);
|
||||
|
||||
bool nexusLogin();
|
||||
|
||||
bool testForSteam();
|
||||
void startSteam();
|
||||
|
||||
@@ -224,6 +205,13 @@ private:
|
||||
bool refreshProfiles(bool selectProfile = true);
|
||||
void refreshExecutablesList();
|
||||
void installMod();
|
||||
MOBase::IModInterface *installMod(const QString &fileName);
|
||||
MOBase::IModInterface *getMod(const QString &name);
|
||||
MOBase::IModInterface *createMod(MOBase::GuessedValue<QString> &name);
|
||||
bool removeMod(MOBase::IModInterface *mod);
|
||||
|
||||
QList<MOBase::IOrganizer::FileInfo> findFileInfos(const QString &path, const std::function<bool (const MOBase::IOrganizer::FileInfo &)> &filter) const;
|
||||
|
||||
bool modifyExecutablesDialog();
|
||||
void displayModInformation(ModInfo::Ptr modInfo, unsigned int index, int tab);
|
||||
void displayModInformation(int row, int tab = 0);
|
||||
@@ -267,7 +255,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);
|
||||
@@ -275,8 +263,6 @@ private:
|
||||
|
||||
void setCategoryListVisible(bool visible);
|
||||
|
||||
void updateProblemsButton();
|
||||
|
||||
SaveGameGamebryo *getSaveGame(const QString &name);
|
||||
SaveGameGamebryo *getSaveGame(QListWidgetItem *item);
|
||||
|
||||
@@ -298,6 +284,14 @@ private:
|
||||
bool createBackup(const QString &filePath, const QDateTime &time);
|
||||
QString queryRestore(const QString &filePath);
|
||||
|
||||
QMenu *modListContextMenu();
|
||||
|
||||
std::set<QString> enabledArchives();
|
||||
|
||||
void scheduleUpdateButton();
|
||||
|
||||
void updateModActiveState(int index, bool active);
|
||||
|
||||
private:
|
||||
|
||||
static const unsigned int PROBLEM_PLUGINSNOTLOADED = 1;
|
||||
@@ -367,6 +361,7 @@ private:
|
||||
bool m_ArchivesInit;
|
||||
QTimer m_CheckBSATimer;
|
||||
QTimer m_SaveMetaTimer;
|
||||
QTimer m_UpdateProblemsTimer;
|
||||
|
||||
QTime m_StartTime;
|
||||
SaveGameInfoWidget *m_CurrentSaveView;
|
||||
@@ -380,6 +375,7 @@ private:
|
||||
QFile m_PluginsCheck;
|
||||
|
||||
SignalAboutToRunApplication m_AboutToRun;
|
||||
SignalModInstalled m_ModInstalled;
|
||||
|
||||
QString m_CurrentLanguage;
|
||||
std::vector<QTranslator*> m_Translators;
|
||||
@@ -391,6 +387,10 @@ private:
|
||||
|
||||
std::vector<QTreeWidgetItem*> m_RemoveWidget;
|
||||
|
||||
QByteArray m_ArchiveListHash;
|
||||
|
||||
bool m_DidUpdateMasterList;
|
||||
|
||||
private slots:
|
||||
|
||||
void showMessage(const QString &message);
|
||||
@@ -456,6 +456,8 @@ private slots:
|
||||
|
||||
void linkClicked(const QString &url);
|
||||
|
||||
bool nexusLogin();
|
||||
|
||||
void loginSuccessful(bool necessary);
|
||||
void loginSuccessfulUpdate(bool necessary);
|
||||
void loginFailed(const QString &message);
|
||||
@@ -482,11 +484,12 @@ private slots:
|
||||
void modlistChanged(int row);
|
||||
|
||||
void nxmUpdatesAvailable(const std::vector<int> &modIDs, QVariant userData, QVariant resultData, int requestID);
|
||||
// void nxmEndorsementToggled(int, QVariant, QVariant resultData, int);
|
||||
void nxmEndorsementToggled(int, QVariant, QVariant resultData, int);
|
||||
void nxmDownloadURLs(int modID, int fileID, QVariant userData, QVariant resultData, int requestID);
|
||||
void nxmRequestFailed(int modID, int fileID, QVariant userData, int requestID, const QString &errorString);
|
||||
|
||||
void editCategories();
|
||||
void deselectFilters();
|
||||
|
||||
void displayModInformation(const QString &modName, int tab);
|
||||
void modOpenNext();
|
||||
@@ -513,6 +516,9 @@ private slots:
|
||||
void startExeAction();
|
||||
|
||||
void checkBSAList();
|
||||
|
||||
void updateProblemsButton();
|
||||
|
||||
void saveModMetas();
|
||||
|
||||
void updateStyle(const QString &style);
|
||||
@@ -556,6 +562,7 @@ private slots:
|
||||
void requestDownload(const QUrl &url, QNetworkReply *reply);
|
||||
|
||||
private slots: // ui slots
|
||||
void profileRefresh();
|
||||
// actions
|
||||
void on_actionAdd_Profile_triggered();
|
||||
void on_actionInstallMod_triggered();
|
||||
@@ -576,7 +583,6 @@ private slots: // ui slots
|
||||
void on_modList_customContextMenuRequested(const QPoint &pos);
|
||||
void on_modList_doubleClicked(const QModelIndex &index);
|
||||
void on_profileBox_currentIndexChanged(int index);
|
||||
void on_profileRefreshBtn_clicked();
|
||||
void on_savegameList_customContextMenuRequested(const QPoint &pos);
|
||||
void on_startButton_clicked();
|
||||
void on_tabWidget_currentChanged(int index);
|
||||
@@ -594,6 +600,13 @@ private slots: // ui slots
|
||||
void on_restoreButton_clicked();
|
||||
void on_restoreModsButton_clicked();
|
||||
void on_saveModsButton_clicked();
|
||||
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);
|
||||
void on_manageArchivesBox_toggled(bool checked);
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
||||
+1046
-954
File diff suppressed because it is too large
Load Diff
@@ -81,6 +81,7 @@ void MessageDialog::resizeEvent(QResizeEvent *event)
|
||||
|
||||
void MessageDialog::showMessage(const QString &text, QWidget *reference, bool bringToFront)
|
||||
{
|
||||
qDebug("%s", qPrintable(text));
|
||||
if (reference != NULL) {
|
||||
if (bringToFront || (qApp->activeWindow() != NULL)) {
|
||||
MessageDialog *dialog = new MessageDialog(text, reference);
|
||||
|
||||
+233
-117
@@ -73,6 +73,16 @@ ModInfo::Ptr ModInfo::createFrom(const QDir &dir, DirectoryEntry **directoryStru
|
||||
}
|
||||
|
||||
|
||||
ModInfo::Ptr ModInfo::createFromPlugin(const QString &espName, const QStringList &bsaNames
|
||||
, DirectoryEntry ** directoryStructure)
|
||||
{
|
||||
QMutexLocker locker(&s_Mutex);
|
||||
ModInfo::Ptr result = ModInfo::Ptr(new ModInfoForeign(espName, bsaNames, directoryStructure));
|
||||
s_Collection.push_back(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void ModInfo::createFromOverwrite()
|
||||
{
|
||||
QMutexLocker locker(&s_Mutex);
|
||||
@@ -174,17 +184,37 @@ unsigned int ModInfo::findMod(const boost::function<bool (ModInfo::Ptr)> &filter
|
||||
}
|
||||
|
||||
|
||||
void ModInfo::updateFromDisc(const QString &modDirectory, DirectoryEntry **directoryStructure)
|
||||
void ModInfo::updateFromDisc(const QString &modDirectory, DirectoryEntry **directoryStructure, bool displayForeign)
|
||||
{
|
||||
QMutexLocker lock(&s_Mutex);
|
||||
s_Collection.clear();
|
||||
s_NextID = 0;
|
||||
// list all directories in the mod directory and make a mod out of each
|
||||
QDir mods(QDir::fromNativeSeparators(modDirectory));
|
||||
mods.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
QDirIterator modIter(mods);
|
||||
while (modIter.hasNext()) {
|
||||
createFrom(QDir(modIter.next()), directoryStructure);
|
||||
|
||||
{ // list all directories in the mod directory and make a mod out of each
|
||||
QDir mods(QDir::fromNativeSeparators(modDirectory));
|
||||
mods.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
QDirIterator modIter(mods);
|
||||
while (modIter.hasNext()) {
|
||||
createFrom(QDir(modIter.next()), directoryStructure);
|
||||
}
|
||||
}
|
||||
|
||||
{ // list plugins in the data directory and make a foreign-managed mod out of each
|
||||
std::vector<std::wstring> dlcPlugins = GameInfo::instance().getDLCPlugins();
|
||||
QDir dataDir(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory())) + "/data");
|
||||
foreach (const QFileInfo &file, dataDir.entryInfoList(QStringList() << "*.esp" << "*.esm")) {
|
||||
if ((file.baseName() != "Update") // hide update
|
||||
&& (file.baseName() != ToQString(GameInfo::instance().getGameName())) // hide the game esp
|
||||
&& (displayForeign // show non-dlc bundles only if the user wants them
|
||||
|| std::find(dlcPlugins.begin(), dlcPlugins.end(), ToWString(file.fileName())) != dlcPlugins.end())) {
|
||||
QStringList archives;
|
||||
foreach (const QString archiveName, dataDir.entryList(QStringList() << file.baseName() + "*.bsa")) {
|
||||
archives.append(dataDir.absoluteFilePath(archiveName));
|
||||
}
|
||||
|
||||
createFromPlugin(file.fileName(), archives, directoryStructure);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createFromOverwrite();
|
||||
@@ -219,7 +249,7 @@ ModInfo::ModInfo()
|
||||
void ModInfo::checkChunkForUpdate(const std::vector<int> &modIDs, QObject *receiver)
|
||||
{
|
||||
if (modIDs.size() != 0) {
|
||||
NexusInterface::instance()->requestUpdates(modIDs, receiver, QVariant());
|
||||
NexusInterface::instance()->requestUpdates(modIDs, receiver, QVariant(), QString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,6 +282,12 @@ void ModInfo::setVersion(const VersionInfo &version)
|
||||
m_Version = version;
|
||||
}
|
||||
|
||||
bool ModInfo::hasFlag(ModInfo::EFlag flag) const
|
||||
{
|
||||
std::vector<EFlag> flags = getFlags();
|
||||
return std::find(flags.begin(), flags.end(), flag) != flags.end();
|
||||
}
|
||||
|
||||
|
||||
bool ModInfo::categorySet(int categoryID) const
|
||||
{
|
||||
@@ -293,18 +329,136 @@ void ModInfo::testValid()
|
||||
}
|
||||
|
||||
|
||||
ModInfoWithConflictInfo::ModInfoWithConflictInfo(DirectoryEntry **directoryStructure)
|
||||
: m_DirectoryStructure(directoryStructure) {}
|
||||
|
||||
void ModInfoWithConflictInfo::clearCaches()
|
||||
{
|
||||
m_LastConflictCheck = QTime();
|
||||
}
|
||||
|
||||
std::vector<ModInfo::EFlag> ModInfoWithConflictInfo::getFlags() const
|
||||
{
|
||||
std::vector<ModInfo::EFlag> result;
|
||||
switch (isConflicted()) {
|
||||
case CONFLICT_MIXED: {
|
||||
result.push_back(ModInfo::FLAG_CONFLICT_MIXED);
|
||||
} break;
|
||||
case CONFLICT_OVERWRITE: {
|
||||
result.push_back(ModInfo::FLAG_CONFLICT_OVERWRITE);
|
||||
} break;
|
||||
case CONFLICT_OVERWRITTEN: {
|
||||
result.push_back(ModInfo::FLAG_CONFLICT_OVERWRITTEN);
|
||||
} break;
|
||||
case CONFLICT_REDUNDANT: {
|
||||
result.push_back(ModInfo::FLAG_CONFLICT_REDUNDANT);
|
||||
} break;
|
||||
default: { /* NOP */ }
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
ModInfoWithConflictInfo::EConflictType ModInfoWithConflictInfo::isConflicted() const
|
||||
{
|
||||
// this is costy so cache the result
|
||||
QTime now = QTime::currentTime();
|
||||
if (m_LastConflictCheck.isNull() || (m_LastConflictCheck.secsTo(now) > 10)) {
|
||||
bool overwrite = false;
|
||||
bool overwritten = false;
|
||||
bool regular = false;
|
||||
|
||||
int dataID = 0;
|
||||
if ((*m_DirectoryStructure)->originExists(L"data")) {
|
||||
dataID = (*m_DirectoryStructure)->getOriginByName(L"data").getID();
|
||||
}
|
||||
|
||||
std::wstring name = ToWString(this->name());
|
||||
if ((*m_DirectoryStructure)->originExists(name)) {
|
||||
FilesOrigin &origin = (*m_DirectoryStructure)->getOriginByName(name);
|
||||
std::vector<FileEntry::Ptr> files = origin.getFiles();
|
||||
for (auto iter = files.begin(); iter != files.end() && (!overwrite || !overwritten || !regular); ++iter) {
|
||||
const std::vector<int> &alternatives = (*iter)->getAlternatives();
|
||||
if (alternatives.size() == 0) {
|
||||
// no alternatives -> no conflict
|
||||
regular = true;
|
||||
} else {
|
||||
for (auto altIter = alternatives.begin(); altIter != alternatives.end(); ++altIter) {
|
||||
// don't treat files overwritten in data as "conflict"
|
||||
if (*altIter != dataID) {
|
||||
bool ignore = false;
|
||||
if ((*iter)->getOrigin(ignore) == origin.getID()) {
|
||||
overwrite = true;
|
||||
break;
|
||||
} else {
|
||||
overwritten = true;
|
||||
break;
|
||||
}
|
||||
} else if (alternatives.size() == 1) {
|
||||
// only alternative is data -> no conflict
|
||||
regular = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_LastConflictCheck = QTime::currentTime();
|
||||
|
||||
if (overwrite && overwritten) m_CurrentConflictState = CONFLICT_MIXED;
|
||||
else if (overwrite) m_CurrentConflictState = CONFLICT_OVERWRITE;
|
||||
else if (overwritten) {
|
||||
if (!regular) {
|
||||
m_CurrentConflictState = CONFLICT_REDUNDANT;
|
||||
} else {
|
||||
m_CurrentConflictState = CONFLICT_OVERWRITTEN;
|
||||
}
|
||||
}
|
||||
else m_CurrentConflictState = CONFLICT_NONE;
|
||||
}
|
||||
|
||||
return m_CurrentConflictState;
|
||||
}
|
||||
|
||||
|
||||
bool ModInfoWithConflictInfo::isRedundant() const
|
||||
{
|
||||
std::wstring name = ToWString(this->name());
|
||||
if ((*m_DirectoryStructure)->originExists(name)) {
|
||||
FilesOrigin &origin = (*m_DirectoryStructure)->getOriginByName(name);
|
||||
std::vector<FileEntry::Ptr> files = origin.getFiles();
|
||||
bool ignore = false;
|
||||
for (auto iter = files.begin(); iter != files.end(); ++iter) {
|
||||
if ((*iter)->getOrigin(ignore) == origin.getID()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
ModInfoRegular::ModInfoRegular(const QDir &path, DirectoryEntry **directoryStructure)
|
||||
: ModInfo(), m_Name(path.dirName()), m_Path(path.absolutePath()), m_MetaInfoChanged(false),
|
||||
m_EndorsedState(ENDORSED_UNKNOWN), m_DirectoryStructure(directoryStructure)
|
||||
: ModInfoWithConflictInfo(directoryStructure)
|
||||
, m_Name(path.dirName())
|
||||
, m_Path(path.absolutePath())
|
||||
, m_MetaInfoChanged(false)
|
||||
, m_EndorsedState(ENDORSED_UNKNOWN)
|
||||
{
|
||||
testValid();
|
||||
m_CreationTime = QFileInfo(path.absolutePath()).created();
|
||||
// read out the meta-file for information
|
||||
readMeta();
|
||||
|
||||
connect(&m_NexusBridge, SIGNAL(descriptionAvailable(int,QVariant,QVariant)), this, SLOT(nxmDescriptionAvailable(int,QVariant,QVariant)));
|
||||
connect(&m_NexusBridge, SIGNAL(endorsementToggled(int,QVariant,QVariant)), this, SLOT(nxmEndorsementToggled(int,QVariant,QVariant)));
|
||||
connect(&m_NexusBridge, SIGNAL(requestFailed(int,int,QVariant,QString)), this, SLOT(nxmRequestFailed(int,int,QVariant,QString)));
|
||||
connect(&m_NexusBridge, SIGNAL(descriptionAvailable(int,QVariant,QVariant))
|
||||
, this, SLOT(nxmDescriptionAvailable(int,QVariant,QVariant)));
|
||||
connect(&m_NexusBridge, SIGNAL(endorsementToggled(int,QVariant,QVariant))
|
||||
, this, SLOT(nxmEndorsementToggled(int,QVariant,QVariant)));
|
||||
connect(&m_NexusBridge, SIGNAL(requestFailed(int,int,QVariant,QString))
|
||||
, this, SLOT(nxmRequestFailed(int,int,QVariant,QString)));
|
||||
}
|
||||
|
||||
|
||||
@@ -602,7 +756,7 @@ void ModInfoRegular::setNeverEndorse()
|
||||
bool ModInfoRegular::remove()
|
||||
{
|
||||
m_MetaInfoChanged = false;
|
||||
return shellDelete(QStringList(absolutePath()));
|
||||
return shellDelete(QStringList(absolutePath()), true);
|
||||
}
|
||||
|
||||
void ModInfoRegular::endorse(bool doEndorse)
|
||||
@@ -612,11 +766,6 @@ void ModInfoRegular::endorse(bool doEndorse)
|
||||
}
|
||||
}
|
||||
|
||||
void ModInfoRegular::clearCaches()
|
||||
{
|
||||
m_LastConflictCheck = QTime();
|
||||
}
|
||||
|
||||
|
||||
QString ModInfoRegular::absolutePath() const
|
||||
{
|
||||
@@ -636,22 +785,7 @@ void ModInfoRegular::ignoreUpdate(bool ignore)
|
||||
|
||||
std::vector<ModInfo::EFlag> ModInfoRegular::getFlags() const
|
||||
{
|
||||
std::vector<ModInfo::EFlag> result;
|
||||
switch (isConflicted()) {
|
||||
case CONFLICT_MIXED: {
|
||||
result.push_back(ModInfo::FLAG_CONFLICT_MIXED);
|
||||
} break;
|
||||
case CONFLICT_OVERWRITE: {
|
||||
result.push_back(ModInfo::FLAG_CONFLICT_OVERWRITE);
|
||||
} break;
|
||||
case CONFLICT_OVERWRITTEN: {
|
||||
result.push_back(ModInfo::FLAG_CONFLICT_OVERWRITTEN);
|
||||
} break;
|
||||
case CONFLICT_REDUNDANT: {
|
||||
result.push_back(ModInfo::FLAG_CONFLICT_REDUNDANT);
|
||||
} break;
|
||||
default: { /* NOP */ }
|
||||
}
|
||||
std::vector<ModInfo::EFlag> result = ModInfoWithConflictInfo::getFlags();
|
||||
if ((m_NexusID != -1) && (endorsedState() == ENDORSED_FALSE)) {
|
||||
result.push_back(ModInfo::FLAG_NOTENDORSED);
|
||||
}
|
||||
@@ -712,92 +846,22 @@ ModInfoRegular::EEndorsedState ModInfoRegular::endorsedState() const
|
||||
return m_EndorsedState;
|
||||
}
|
||||
|
||||
ModInfoRegular::EConflictType ModInfoRegular::isConflicted() const
|
||||
{
|
||||
// this is costy so cache the result
|
||||
QTime now = QTime::currentTime();
|
||||
if (m_LastConflictCheck.isNull() || (m_LastConflictCheck.secsTo(now) > 10)) {
|
||||
bool overwrite = false;
|
||||
bool overwritten = false;
|
||||
bool regular = false;
|
||||
|
||||
int dataID = 0;
|
||||
if ((*m_DirectoryStructure)->originExists(L"data")) {
|
||||
dataID = (*m_DirectoryStructure)->getOriginByName(L"data").getID();
|
||||
}
|
||||
|
||||
std::wstring name = ToWString(m_Name);
|
||||
if ((*m_DirectoryStructure)->originExists(name)) {
|
||||
FilesOrigin &origin = (*m_DirectoryStructure)->getOriginByName(name);
|
||||
std::vector<FileEntry::Ptr> files = origin.getFiles();
|
||||
for (auto iter = files.begin(); iter != files.end() && (!overwrite || !overwritten || !regular); ++iter) {
|
||||
const std::vector<int> &alternatives = (*iter)->getAlternatives();
|
||||
if (alternatives.size() == 0) {
|
||||
// no alternatives -> no conflict
|
||||
regular = true;
|
||||
} else {
|
||||
for (auto altIter = alternatives.begin(); altIter != alternatives.end(); ++altIter) {
|
||||
// don't treat files overwritten in data as "conflict"
|
||||
if (*altIter != dataID) {
|
||||
bool ignore = false;
|
||||
if ((*iter)->getOrigin(ignore) == origin.getID()) {
|
||||
overwrite = true;
|
||||
break;
|
||||
} else {
|
||||
overwritten = true;
|
||||
break;
|
||||
}
|
||||
} else if (alternatives.size() == 1) {
|
||||
// only alternative is data -> no conflict
|
||||
regular = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_LastConflictCheck = QTime::currentTime();
|
||||
|
||||
if (overwrite && overwritten) m_CurrentConflictState = CONFLICT_MIXED;
|
||||
else if (overwrite) m_CurrentConflictState = CONFLICT_OVERWRITE;
|
||||
else if (overwritten) {
|
||||
if (!regular) {
|
||||
m_CurrentConflictState = CONFLICT_REDUNDANT;
|
||||
} else {
|
||||
m_CurrentConflictState = CONFLICT_OVERWRITTEN;
|
||||
}
|
||||
}
|
||||
else m_CurrentConflictState = CONFLICT_NONE;
|
||||
}
|
||||
|
||||
return m_CurrentConflictState;
|
||||
}
|
||||
|
||||
|
||||
bool ModInfoRegular::isRedundant() const
|
||||
{
|
||||
std::wstring name = ToWString(m_Name);
|
||||
if ((*m_DirectoryStructure)->originExists(name)) {
|
||||
FilesOrigin &origin = (*m_DirectoryStructure)->getOriginByName(name);
|
||||
std::vector<FileEntry::Ptr> files = origin.getFiles();
|
||||
bool ignore = false;
|
||||
for (auto iter = files.begin(); iter != files.end(); ++iter) {
|
||||
if ((*iter)->getOrigin(ignore) == origin.getID()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QDateTime ModInfoRegular::getLastNexusQuery() const
|
||||
{
|
||||
return m_LastNexusQuery;
|
||||
}
|
||||
|
||||
|
||||
QStringList ModInfoRegular::archives() const
|
||||
{
|
||||
QStringList result;
|
||||
QDir dir(this->absolutePath());
|
||||
foreach (const QString &archive, dir.entryList(QStringList("*.bsa"))) {
|
||||
result.append(this->absolutePath() + "/" + archive);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<QString> ModInfoRegular::getIniTweaks() const
|
||||
{
|
||||
QString metaFileName = absolutePath().append("/meta.ini");
|
||||
@@ -874,9 +938,61 @@ int ModInfoOverwrite::getHighlight() const
|
||||
return (isValid() ? HIGHLIGHT_IMPORTANT : HIGHLIGHT_INVALID) | HIGHLIGHT_CENTER;
|
||||
}
|
||||
|
||||
|
||||
QString ModInfoOverwrite::getDescription() const
|
||||
{
|
||||
return tr("This pseudo mod contains files from the virtual data tree that got "
|
||||
"modified (i.e. by the construction kit)");
|
||||
}
|
||||
|
||||
QStringList ModInfoOverwrite::archives() const
|
||||
{
|
||||
QStringList result;
|
||||
QDir dir(this->absolutePath());
|
||||
foreach (const QString &archive, dir.entryList(QStringList("*.bsa"))) {
|
||||
result.append(this->absolutePath() + "/" + archive);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QString ModInfoForeign::name() const
|
||||
{
|
||||
return m_Name;
|
||||
}
|
||||
|
||||
QDateTime ModInfoForeign::creationTime() const
|
||||
{
|
||||
return m_CreationTime;
|
||||
}
|
||||
|
||||
QString ModInfoForeign::absolutePath() const
|
||||
{
|
||||
return QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory())) + "/data";
|
||||
}
|
||||
|
||||
std::vector<ModInfo::EFlag> ModInfoForeign::getFlags() const
|
||||
{
|
||||
std::vector<ModInfo::EFlag> result = ModInfoWithConflictInfo::getFlags();
|
||||
result.push_back(FLAG_FOREIGN);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int ModInfoForeign::getHighlight() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
QString ModInfoForeign::getDescription() const
|
||||
{
|
||||
return tr("This pseudo mod represents content managed outside MO. It isn't modified by MO.");
|
||||
}
|
||||
|
||||
ModInfoForeign::ModInfoForeign(const QString &referenceFile, const QStringList &archives,
|
||||
DirectoryEntry **directoryStructure)
|
||||
: ModInfoWithConflictInfo(directoryStructure)
|
||||
, m_ReferenceFile(referenceFile)
|
||||
, m_Archives(archives)
|
||||
{
|
||||
m_CreationTime = QFileInfo(referenceFile).created();
|
||||
m_Name = QFileInfo(m_ReferenceFile).baseName();
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user