mirror of
https://github.com/ModOrganizer2/modorganizer.git
synced 2026-07-27 13:58:24 -07:00
Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0eb1662a0e | ||
|
|
164ec25a75 | ||
|
|
6fb36d6c02 | ||
|
|
ea1f959ad5 | ||
|
|
7cf3b3455b |
+24
-8
@@ -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,10 +153,6 @@ 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["email="] = std::make_pair(QRegExp("\\[email=\"?([^\\]]*)\"?\\](.*)\\[/email\\]"),
|
||||
@@ -150,6 +160,11 @@ private:
|
||||
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 = boost::assign::map_list_of("red", "FF0000")("green", "00FF00")("blue", "0000FF")
|
||||
("black", "000000")("gray", "7F7F7F")("white", "FFFFFF")
|
||||
("yellow", "FFFF00")("cyan", "00FFFF")("magenta", "FF00FF")
|
||||
("brown", "A52A2A")("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 +172,11 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
QRegExp m_TagNameExp;
|
||||
TagMap m_TagMap;
|
||||
std::map<QString, QString> m_ColorMap;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -27,6 +27,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "json.h"
|
||||
#include "selectiondialog.h"
|
||||
#include <utility.h>
|
||||
#include <bbcode.h>
|
||||
#include <QTimer>
|
||||
#include <QFileInfo>
|
||||
#include <QRegExp>
|
||||
@@ -1159,7 +1160,7 @@ 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;
|
||||
|
||||
@@ -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());
|
||||
|
||||
+79
-3
@@ -29,7 +29,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 +51,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 +86,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);
|
||||
@@ -125,6 +134,67 @@ char LogBuffer::msgTypeID(QtMsgType type)
|
||||
}
|
||||
}
|
||||
|
||||
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()) % m_Messages.size();
|
||||
switch (role) {
|
||||
case Qt::DisplayRole: {
|
||||
if (index.column() == 0) {
|
||||
return m_Messages.at(msgIndex).time;
|
||||
} else if (index.column() == 1) {
|
||||
return m_Messages.at(msgIndex).message;
|
||||
}
|
||||
} 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::log(QtMsgType type, const char *message)
|
||||
{
|
||||
QMutexLocker guard(&s_Mutex);
|
||||
@@ -171,3 +241,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;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -195,7 +195,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 +256,11 @@ LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *exceptionPtrs
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void registerMetaTypes()
|
||||
{
|
||||
registerExecutable();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool HaveWriteAccess(const std::wstring &path)
|
||||
{
|
||||
bool writable = false;
|
||||
@@ -314,7 +310,6 @@ bool HaveWriteAccess(const std::wstring &path)
|
||||
return writable;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
MOApplication application(argc, argv);
|
||||
|
||||
+66
-48
@@ -95,6 +95,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include <QDesktopWidget>
|
||||
#include <QtPlugin>
|
||||
#include <QIdentityProxyModel>
|
||||
#include <QClipboard>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/assign.hpp>
|
||||
@@ -167,6 +168,16 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget
|
||||
ui->setupUi(this);
|
||||
this->setWindowTitle(ToQString(GameInfo::instance().getGameName()) + " Mod Organizer v" + m_Updater.getVersion().displayString());
|
||||
|
||||
ui->logList->setModel(LogBuffer::instance());
|
||||
ui->logList->setColumnWidth(0, 100);
|
||||
ui->logList->setAutoScroll(true);
|
||||
ui->logList->scrollToBottom();
|
||||
ui->logList->addAction(ui->actionCopy_Log_to_Clipboard);
|
||||
int splitterSize = this->size().height(); // actually total window size, but the splitter doesn't seem to return the true value
|
||||
ui->topLevelSplitter->setSizes(QList<int>() << splitterSize - 100 << 100);
|
||||
connect(ui->logList->model(), SIGNAL(rowsInserted(const QModelIndex &, int, int)), ui->logList, SLOT(scrollToBottom()));
|
||||
connect(ui->logList->model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), ui->logList, SLOT(scrollToBottom()));
|
||||
|
||||
m_RefreshProgress = new QProgressBar(statusBar());
|
||||
m_RefreshProgress->setTextVisible(true);
|
||||
m_RefreshProgress->setRange(0, 100);
|
||||
@@ -653,8 +664,9 @@ void MainWindow::saveArchiveList()
|
||||
}
|
||||
}
|
||||
}
|
||||
archiveFile.commit();
|
||||
qDebug("%s saved", qPrintable(QDir::toNativeSeparators(m_CurrentProfile->getArchivesFileName())));
|
||||
if (archiveFile.commitIfDifferent(m_ArchiveListHash)) {
|
||||
qDebug("%s saved", qPrintable(QDir::toNativeSeparators(m_CurrentProfile->getArchivesFileName())));
|
||||
}
|
||||
} else {
|
||||
qWarning("archive list not initialised");
|
||||
}
|
||||
@@ -670,10 +682,12 @@ void MainWindow::savePluginList()
|
||||
m_PluginList.saveLoadOrder(*m_DirectoryStructure);
|
||||
}
|
||||
|
||||
void MainWindow::modFilterActive(bool active)
|
||||
void MainWindow::modFilterActive(bool filterActive)
|
||||
{
|
||||
if (active) {
|
||||
if (filterActive) {
|
||||
ui->modList->setStyleSheet("QTreeView { border: 2px ridge #f00; }");
|
||||
} else if (ui->groupCombo->currentIndex() != 0) {
|
||||
ui->modList->setStyleSheet("QTreeView { border: 2px ridge #337733; }");
|
||||
} else {
|
||||
ui->modList->setStyleSheet("");
|
||||
}
|
||||
@@ -1410,11 +1424,12 @@ HANDLE MainWindow::spawnBinaryDirect(const QFileInfo &binary, const QString &arg
|
||||
}
|
||||
}
|
||||
|
||||
while (m_RefreshProgress->isVisible()) {
|
||||
while (m_DirectoryUpdate) {
|
||||
::Sleep(100);
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
|
||||
// need to make sure all data is saved before we start the application
|
||||
if (m_CurrentProfile != nullptr) {
|
||||
m_CurrentProfile->writeModlistNow(true);
|
||||
}
|
||||
@@ -1428,28 +1443,6 @@ HANDLE MainWindow::spawnBinaryDirect(const QFileInfo &binary, const QString &arg
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void MainWindow::spawnProgram(const QString &fileName, const QString &argumentsArg,
|
||||
const QString &profileName, const QDir ¤tDirectory)
|
||||
{
|
||||
QFileInfo binary;
|
||||
QString arguments = argumentsArg;
|
||||
QString steamAppID;
|
||||
try {
|
||||
const Executable &exe = m_ExecutablesList.find(fileName);
|
||||
steamAppID = exe.m_SteamAppID;
|
||||
if (arguments == "") {
|
||||
arguments = exe.m_Arguments;
|
||||
}
|
||||
binary = exe.m_BinaryInfo;
|
||||
} catch (const std::runtime_error&) {
|
||||
qWarning("\"%s\" not set up as executable", fileName.toUtf8().constData());
|
||||
binary = QFileInfo(fileName);
|
||||
}
|
||||
spawnBinaryDirect(binary, arguments, profileName, currentDirectory, steamAppID);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
void MainWindow::spawnBinary(const QFileInfo &binary, const QString &arguments, const QDir ¤tDirectory, bool closeAfterStart, const QString &steamAppID)
|
||||
{
|
||||
@@ -2211,7 +2204,10 @@ void MainWindow::storeSettings()
|
||||
result = settings.status();
|
||||
}
|
||||
if (result == QSettings::NoError) {
|
||||
shellRename(iniFile + ".new", iniFile, true, this);
|
||||
if (!shellRename(iniFile + ".new", iniFile, true, this)) {
|
||||
QMessageBox::critical(this, tr("Failed to write settings"),
|
||||
tr("An error occured trying to write back MO settings: %1").arg(windowsErrorString(::GetLastError())));
|
||||
}
|
||||
} else {
|
||||
QString reason = result == QSettings::AccessError ? tr("File is write protected")
|
||||
: result == QSettings::FormatError ? tr("Invalid file format (probably a bug)")
|
||||
@@ -2247,10 +2243,10 @@ void MainWindow::on_tabWidget_currentChanged(int index)
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::installMod(const QString &fileName)
|
||||
IModInterface *MainWindow::installMod(const QString &fileName)
|
||||
{
|
||||
if (m_CurrentProfile == NULL) {
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool hasIniTweaks = false;
|
||||
@@ -2275,12 +2271,14 @@ void MainWindow::installMod(const QString &fileName)
|
||||
displayModInformation(modInfo, modIndex, ModInfoDialog::TAB_INIFILES);
|
||||
}
|
||||
testExtractBSA(modIndex);
|
||||
return modInfo.data();
|
||||
} else {
|
||||
reportError(tr("mod \"%1\" not found").arg(modName));
|
||||
}
|
||||
} else if (m_InstallationManager.wasCancelled()) {
|
||||
QMessageBox::information(this, tr("Installation cancelled"), tr("The mod was not installed completely."), QMessageBox::Ok);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QString MainWindow::resolvePath(const QString &fileName) const
|
||||
@@ -2754,14 +2752,11 @@ void MainWindow::refresher_progress(int percent)
|
||||
|
||||
void MainWindow::directory_refreshed()
|
||||
{
|
||||
statusBar()->hide();
|
||||
|
||||
DirectoryEntry *newStructure = m_DirectoryRefresher.getDirectoryStructure();
|
||||
if (newStructure != NULL) {
|
||||
DirectoryEntry *oldStructure = m_DirectoryStructure;
|
||||
m_DirectoryStructure = newStructure;
|
||||
delete oldStructure;
|
||||
|
||||
refreshDataTree();
|
||||
} else {
|
||||
// TODO: don't know why this happens, this slot seems to get called twice with only one emit
|
||||
@@ -2781,6 +2776,7 @@ void MainWindow::directory_refreshed()
|
||||
ModInfo::Ptr modInfo = ModInfo::getByIndex(i);
|
||||
modInfo->clearCaches();
|
||||
}
|
||||
statusBar()->hide();
|
||||
}
|
||||
|
||||
|
||||
@@ -5242,10 +5238,10 @@ void MainWindow::on_groupCombo_currentIndexChanged(int index)
|
||||
connect(ui->modList, SIGNAL(expanded(QModelIndex)),newModel, SLOT(expanded(QModelIndex)));
|
||||
connect(ui->modList, SIGNAL(collapsed(QModelIndex)), newModel, SLOT(collapsed(QModelIndex)));
|
||||
connect(newModel, SIGNAL(expandItem(QModelIndex)), this, SLOT(expandModList(QModelIndex)));
|
||||
|
||||
} else {
|
||||
m_ModListSortProxy->setSourceModel(&m_ModList);
|
||||
}
|
||||
modFilterActive(m_ModListSortProxy->isFilterActive());
|
||||
}
|
||||
|
||||
void MainWindow::on_linkButton_pressed()
|
||||
@@ -5339,6 +5335,8 @@ void MainWindow::on_bossButton_clicked()
|
||||
|
||||
m_CurrentProfile->writeModlistNow();
|
||||
|
||||
bool success = false;
|
||||
|
||||
try {
|
||||
this->setEnabled(false);
|
||||
ON_BLOCK_EXIT([&] () { this->setEnabled(true); });
|
||||
@@ -5354,7 +5352,6 @@ void MainWindow::on_bossButton_clicked()
|
||||
HANDLE stdOutWrite = INVALID_HANDLE_VALUE;
|
||||
HANDLE stdOutRead = INVALID_HANDLE_VALUE;
|
||||
createStdoutPipe(&stdOutRead, &stdOutWrite);
|
||||
|
||||
HANDLE loot = startBinary(QFileInfo(qApp->applicationDirPath() + "/loot/lootcli.exe"),
|
||||
parameters.join(" "),
|
||||
m_CurrentProfile->getName(),
|
||||
@@ -5380,30 +5377,39 @@ void MainWindow::on_bossButton_clicked()
|
||||
if (remainder.length() > 0) {
|
||||
processLOOTOut(remainder, reportURL, errorMessages, dialog);
|
||||
}
|
||||
DWORD exitCode = 0UL;
|
||||
::GetExitCodeProcess(loot, &exitCode);
|
||||
if (exitCode != 0UL) {
|
||||
reportError(tr("loot failed. Exit code was: %1").arg(exitCode));
|
||||
return;
|
||||
} else {
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
reportError(tr("failed to run boss: %1").arg(e.what()));
|
||||
reportError(tr("failed to run loot: %1").arg(e.what()));
|
||||
}
|
||||
|
||||
if (errorMessages.length() > 0) {
|
||||
QMessageBox *warn = new QMessageBox(QMessageBox::Warning, tr("Errors occured"), errorMessages.c_str(), QMessageBox::Ok, this);
|
||||
warn->setModal(false);
|
||||
warn->show();
|
||||
}
|
||||
|
||||
if (reportURL.length() > 0) {
|
||||
m_IntegratedBrowser.setWindowTitle("LOOT Report");
|
||||
QString report(reportURL.c_str());
|
||||
if (QFile::exists(report)) {
|
||||
m_IntegratedBrowser.openUrl(QUrl::fromLocalFile(report));
|
||||
} else {
|
||||
qWarning("report file missing");
|
||||
if (success) {
|
||||
if (reportURL.length() > 0) {
|
||||
m_IntegratedBrowser.setWindowTitle("LOOT Report");
|
||||
QString report(reportURL.c_str());
|
||||
if (QFile::exists(report)) {
|
||||
m_IntegratedBrowser.openUrl(QUrl::fromLocalFile(report));
|
||||
} else {
|
||||
qWarning("report file missing");
|
||||
}
|
||||
}
|
||||
}
|
||||
refreshESPList();
|
||||
refreshESPList();
|
||||
|
||||
if (GameInfo::instance().getLoadOrderMechanism() == GameInfo::TYPE_FILETIME) {
|
||||
QFile::remove(m_CurrentProfile->getLoadOrderFileName());
|
||||
if (GameInfo::instance().getLoadOrderMechanism() == GameInfo::TYPE_FILETIME) {
|
||||
QFile::remove(m_CurrentProfile->getLoadOrderFileName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5503,3 +5509,15 @@ void MainWindow::on_restoreModsButton_clicked()
|
||||
refreshModList(false);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_actionCopy_Log_to_Clipboard_triggered()
|
||||
{
|
||||
QStringList lines;
|
||||
QAbstractItemModel *model = ui->logList->model();
|
||||
for (int i = 0; i < model->rowCount(); ++i) {
|
||||
lines.append(QString("%1 [%2] %3").arg(model->index(i, 0).data().toString())
|
||||
.arg(model->index(i, 1).data(Qt::UserRole).toString())
|
||||
.arg(model->index(i, 1).data().toString()));
|
||||
}
|
||||
QApplication::clipboard()->setText(lines.join("\n"));
|
||||
}
|
||||
|
||||
+4
-1
@@ -132,7 +132,7 @@ public:
|
||||
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 MOBase::IModInterface *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;
|
||||
@@ -391,6 +391,8 @@ private:
|
||||
|
||||
std::vector<QTreeWidgetItem*> m_RemoveWidget;
|
||||
|
||||
uint m_ArchiveListHash;
|
||||
|
||||
private slots:
|
||||
|
||||
void showMessage(const QString &message);
|
||||
@@ -594,6 +596,7 @@ private slots: // ui slots
|
||||
void on_restoreButton_clicked();
|
||||
void on_restoreModsButton_clicked();
|
||||
void on_saveModsButton_clicked();
|
||||
void on_actionCopy_Log_to_Clipboard_triggered();
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
||||
+975
-957
File diff suppressed because it is too large
Load Diff
+41
-20
@@ -375,20 +375,23 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
|
||||
int modID = index.row();
|
||||
|
||||
ModInfo::Ptr info = ModInfo::getByIndex(modID);
|
||||
IModList::ModStates oldState = state(modID);
|
||||
|
||||
bool result = false;
|
||||
|
||||
if (role == Qt::CheckStateRole) {
|
||||
bool enabled = value.toInt() == Qt::Checked;
|
||||
if (m_Profile->modEnabled(modID) != enabled) {
|
||||
m_Profile->setModEnabled(modID, enabled);
|
||||
m_Modified = true;
|
||||
|
||||
emit modlist_changed(index, role);
|
||||
}
|
||||
return true;
|
||||
result = true;
|
||||
} else if (role == Qt::EditRole) {
|
||||
bool res = false;
|
||||
switch (index.column()) {
|
||||
case COL_NAME: {
|
||||
res = renameMod(modID, value.toString());
|
||||
result = renameMod(modID, value.toString());
|
||||
} break;
|
||||
case COL_PRIORITY: {
|
||||
bool ok = false;
|
||||
@@ -397,47 +400,55 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
m_Profile->setModPriority(modID, newPriority);
|
||||
|
||||
emit modlist_changed(index, role);
|
||||
res = true;
|
||||
result = true;
|
||||
} else {
|
||||
res = false;
|
||||
result = false;
|
||||
}
|
||||
} break;
|
||||
case COL_MODID: {
|
||||
ModInfo::Ptr info = ModInfo::getByIndex(modID);
|
||||
bool ok = false;
|
||||
int newID = value.toInt(&ok);
|
||||
if (ok) {
|
||||
info->setNexusID(newID);
|
||||
emit modlist_changed(index, role);
|
||||
res = true;
|
||||
result = true;
|
||||
} else {
|
||||
res = false;
|
||||
result = false;
|
||||
}
|
||||
} break;
|
||||
case COL_VERSION: {
|
||||
ModInfo::Ptr info = ModInfo::getByIndex(modID);
|
||||
VersionInfo::VersionScheme scheme = info->getVersion().scheme();
|
||||
VersionInfo version(value.toString(), scheme);
|
||||
if (version.isValid()) {
|
||||
info->setVersion(version);
|
||||
res = true;
|
||||
result = true;
|
||||
} else {
|
||||
res = false;
|
||||
result = false;
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
qWarning("edit on column \"%s\" not supported",
|
||||
getColumnName(index.column()).toUtf8().constData());
|
||||
res = false;
|
||||
result = false;
|
||||
} break;
|
||||
}
|
||||
if (res) {
|
||||
if (result) {
|
||||
emit dataChanged(index, index);
|
||||
}
|
||||
return res;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
IModList::ModStates newState = state(modID);
|
||||
if (oldState != newState) {
|
||||
try {
|
||||
m_ModStateChanged(info->name(), newState);
|
||||
} catch (const std::exception &e) {
|
||||
qCritical("failed to invoke state changed notification: %s", e.what());
|
||||
} catch (...) {
|
||||
qCritical("failed to invoke state changed notification: unknown exception");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -578,10 +589,9 @@ void ModList::modInfoChanged(ModInfo::Ptr info)
|
||||
}
|
||||
}
|
||||
|
||||
IModList::ModStates ModList::state(const QString &name) const
|
||||
IModList::ModStates ModList::state(unsigned int modIndex) const
|
||||
{
|
||||
ModStates result;
|
||||
unsigned int modIndex = ModInfo::getIndex(name);
|
||||
IModList::ModStates result;
|
||||
if (modIndex != UINT_MAX) {
|
||||
result |= IModList::STATE_EXISTS;
|
||||
ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex);
|
||||
@@ -605,6 +615,13 @@ IModList::ModStates ModList::state(const QString &name) const
|
||||
return result;
|
||||
}
|
||||
|
||||
IModList::ModStates ModList::state(const QString &name) const
|
||||
{
|
||||
unsigned int modIndex = ModInfo::getIndex(name);
|
||||
|
||||
return state(modIndex);
|
||||
}
|
||||
|
||||
int ModList::priority(const QString &name) const
|
||||
{
|
||||
unsigned int modIndex = ModInfo::getIndex(name);
|
||||
@@ -744,6 +761,8 @@ void ModList::removeRowForce(int row)
|
||||
}
|
||||
if (m_Profile == NULL) return;
|
||||
|
||||
m_Profile->setModEnabled(row, false);
|
||||
|
||||
ModInfo::Ptr modInfo = ModInfo::getByIndex(row);
|
||||
|
||||
bool wasEnabled = m_Profile->modEnabled(row);
|
||||
@@ -770,6 +789,8 @@ void ModList::removeRow(int row, const QModelIndex&)
|
||||
}
|
||||
if (m_Profile == NULL) return;
|
||||
|
||||
m_Profile->setModEnabled(row, false);
|
||||
|
||||
ModInfo::Ptr modInfo = ModInfo::getByIndex(row);
|
||||
if (!modInfo->isRegular()) return;
|
||||
|
||||
|
||||
@@ -239,6 +239,8 @@ private:
|
||||
|
||||
bool dropMod(const QMimeData *mimeData, int row, const QModelIndex &parent);
|
||||
|
||||
ModStates state(unsigned int modIndex) const;
|
||||
|
||||
private slots:
|
||||
|
||||
private:
|
||||
|
||||
@@ -28,8 +28,11 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
ModListSortProxy::ModListSortProxy(Profile* profile, QObject *parent)
|
||||
: QSortFilterProxyModel(parent), m_Profile(profile),
|
||||
m_CategoryFilter(), m_CurrentFilter()
|
||||
: QSortFilterProxyModel(parent)
|
||||
, m_Profile(profile)
|
||||
, m_CategoryFilter()
|
||||
, m_CurrentFilter()
|
||||
, m_FilterActive(false)
|
||||
{
|
||||
m_EnabledColumns.set(ModList::COL_FLAGS);
|
||||
m_EnabledColumns.set(ModList::COL_NAME);
|
||||
@@ -47,7 +50,8 @@ void ModListSortProxy::setProfile(Profile *profile)
|
||||
|
||||
void ModListSortProxy::updateFilterActive()
|
||||
{
|
||||
emit filterActive((m_CategoryFilter.size() > 0) || !m_CurrentFilter.isEmpty());
|
||||
m_FilterActive = (m_CategoryFilter.size() > 0) || !m_CurrentFilter.isEmpty();
|
||||
emit filterActive(m_FilterActive);
|
||||
}
|
||||
|
||||
void ModListSortProxy::setCategoryFilter(const std::vector<int> &categories)
|
||||
|
||||
@@ -52,8 +52,24 @@ public:
|
||||
**/
|
||||
void disableAllVisible();
|
||||
|
||||
/**
|
||||
* @brief tests if a filtere matches for a mod
|
||||
* @param info mod information
|
||||
* @param enabled true if the mod is currently active
|
||||
* @return true if current active filters match for the specified mod
|
||||
*/
|
||||
bool filterMatchesMod(ModInfo::Ptr info, bool enabled) const;
|
||||
|
||||
/**
|
||||
* @return true if a filter is currently active
|
||||
*/
|
||||
bool isFilterActive() const { return m_FilterActive; }
|
||||
|
||||
/**
|
||||
* @brief tests if the specified index has child nodes
|
||||
* @param parent the node to test
|
||||
* @return true if there are child nodes
|
||||
*/
|
||||
virtual bool hasChildren ( const QModelIndex & parent = QModelIndex() ) const {
|
||||
return rowCount(parent) > 0;
|
||||
}
|
||||
@@ -86,6 +102,8 @@ private:
|
||||
std::bitset<ModList::COL_LASTCOLUMN + 1> m_EnabledColumns;
|
||||
QString m_CurrentFilter;
|
||||
|
||||
bool m_FilterActive;
|
||||
|
||||
};
|
||||
|
||||
#endif // MODLISTSORTPROXY_H
|
||||
|
||||
+6
-3
@@ -391,6 +391,8 @@ void PluginList::writePlugins(const QString &fileName, bool writeUnchecked) cons
|
||||
|
||||
file->write(textCodec->fromUnicode("# This file was automatically generated by Mod Organizer.\r\n"));
|
||||
|
||||
QStringList saveList;
|
||||
|
||||
bool invalidFileNames = false;
|
||||
int writtenCount = 0;
|
||||
for (size_t i = 0; i < m_ESPs.size(); ++i) {
|
||||
@@ -401,6 +403,7 @@ void PluginList::writePlugins(const QString &fileName, bool writeUnchecked) cons
|
||||
invalidFileNames = true;
|
||||
qCritical("invalid plugin name %s", m_ESPs[priority].m_Name.toUtf8().constData());
|
||||
} else {
|
||||
saveList << m_ESPs[priority].m_Name;
|
||||
file->write(textCodec->fromUnicode(m_ESPs[priority].m_Name));
|
||||
}
|
||||
file->write("\r\n");
|
||||
@@ -413,9 +416,9 @@ void PluginList::writePlugins(const QString &fileName, bool writeUnchecked) cons
|
||||
"Please see mo_interface.log for a list of affected plugins and rename them."));
|
||||
}
|
||||
|
||||
file.commit();
|
||||
|
||||
qDebug("%s saved", QDir::toNativeSeparators(fileName).toUtf8().constData());
|
||||
if (file.commitIfDifferent(m_LastSaveHash[fileName])) {
|
||||
qDebug("%s saved", QDir::toNativeSeparators(fileName).toUtf8().constData());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include <boost/signals2.hpp>
|
||||
#include <boost/ptr_container/ptr_vector.hpp>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "pdll.h"
|
||||
#include <BOSS-API.h>
|
||||
|
||||
@@ -278,6 +279,7 @@ private:
|
||||
private:
|
||||
|
||||
std::vector<ESPInfo> m_ESPs;
|
||||
mutable std::map<QString, uint> m_LastSaveHash;
|
||||
|
||||
std::map<QString, int> m_ESPsByName;
|
||||
std::vector<int> m_ESPsByPriority;
|
||||
|
||||
+3
-4
@@ -147,7 +147,6 @@ void Profile::writeModlistNow(bool onlyOnTimer) const
|
||||
|
||||
m_SaveTimer->stop();
|
||||
if (!m_Directory.exists()) return;
|
||||
#pragma message("right now, this is doing unnecessary saves. Need a flag that says that mod priority, enabled-state or name of a mod has changed")
|
||||
|
||||
try {
|
||||
QString fileName = getModlistFileName();
|
||||
@@ -175,9 +174,9 @@ void Profile::writeModlistNow(bool onlyOnTimer) const
|
||||
}
|
||||
}
|
||||
|
||||
file.commit();
|
||||
|
||||
qDebug("%s saved", QDir::toNativeSeparators(fileName).toUtf8().constData());
|
||||
if (file.commitIfDifferent(m_LastModlistHash)) {
|
||||
qDebug("%s saved", QDir::toNativeSeparators(fileName).toUtf8().constData());
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
reportError(tr("failed to write mod list: %1").arg(e.what()));
|
||||
return;
|
||||
|
||||
@@ -316,6 +316,7 @@ private:
|
||||
|
||||
QDir m_Directory;
|
||||
|
||||
mutable uint m_LastModlistHash;
|
||||
std::vector<ModStatus> m_ModStatus;
|
||||
std::vector<unsigned int> m_ModIndexByPriority;
|
||||
unsigned int m_NumRegularMods;
|
||||
|
||||
+2
-2
@@ -24,13 +24,13 @@
|
||||
<file alias="previous">resources/go-previous_16.png</file>
|
||||
<file alias="refresh">resources/view-refresh_16.png</file>
|
||||
<file alias="update_available">resources/software-update-available.png</file>
|
||||
<file>resources/emblem-important.png</file>
|
||||
<file alias="important">resources/emblem-important.png</file>
|
||||
<file>resources/check.png</file>
|
||||
<file>mo_icon.ico</file>
|
||||
<file alias="warning">resources/dialog-warning.png</file>
|
||||
<file alias="emblem_backup">resources/symbol-backup.png</file>
|
||||
<file alias="icon_tools">resources/applications-accessories.png</file>
|
||||
<file alias="emblem_problem">resources/emblem-unreadable.png</file>
|
||||
<file alias="problem">resources/emblem-unreadable.png</file>
|
||||
<file>resources/internet-web-browser.png</file>
|
||||
<file alias="update">resources/system-software-update.png</file>
|
||||
<file alias="help">resources/help-browser_32.png</file>
|
||||
|
||||
@@ -46,3 +46,23 @@ void SafeWriteFile::commit() {
|
||||
m_TempFile.setAutoRemove(false);
|
||||
m_TempFile.close();
|
||||
}
|
||||
|
||||
bool SafeWriteFile::commitIfDifferent(uint &inHash) {
|
||||
uint newHash = hash();
|
||||
if (newHash != inHash) {
|
||||
commit();
|
||||
inHash = newHash;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint SafeWriteFile::hash()
|
||||
{
|
||||
qint64 pos = m_TempFile.pos();
|
||||
m_TempFile.seek(0);
|
||||
QByteArray data = m_TempFile.readAll();
|
||||
m_TempFile.seek(pos);
|
||||
return qHash(data);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user