From 6fb36d6c028d4fe88043c764e42b54df9b06f48b Mon Sep 17 00:00:00 2001 From: Tannin Date: Sun, 4 May 2014 14:50:01 +0200 Subject: - main window now has a small view displaying log messages - mod list will now be highlighted when grouping is active is active - download tooltip now supports bbcode markup in the description - bbcode translator will now translate some named colors - algorithm for detection of mod order problems is now more sophisticated - exposed more functionality to python plugins - updated to qt 4.8.6 dlls - bugfix: plugin list wasn't - bugfix: state changes in mod list wasn't always reported - bugfix: loot client will now create necessary directory - bugfix: NCC sometimes used wrong source path for extracting - bugfix: removed noisy debug message --- src/bbcode.cpp | 32 +- src/directoryrefresher.cpp | 4 + src/downloadmanager.cpp | 3 +- src/installationmanager.cpp | 5 +- src/logbuffer.cpp | 82 +- src/logbuffer.h | 25 +- src/main.cpp | 5 - src/mainwindow.cpp | 76 +- src/mainwindow.h | 3 +- src/mainwindow.ui | 1852 ++++++++++++++++++++++--------------------- src/modlist.cpp | 61 +- src/modlist.h | 2 + src/modlistsortproxy.cpp | 10 +- src/modlistsortproxy.h | 18 + src/resources.qrc | 4 +- src/singleinstance.cpp | 2 +- src/version.rc | 4 +- 17 files changed, 1203 insertions(+), 985 deletions(-) (limited to 'src') diff --git a/src/bbcode.cpp b/src/bbcode.cpp index fe7decfd..80721cd2 100644 --- a/src/bbcode.cpp +++ b/src/bbcode.cpp @@ -22,6 +22,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include 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("%2").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\\]"), "\\2"); m_TagMap["color="] = std::make_pair(QRegExp("\\[color=([^\\]]*)\\](.*)\\[/color\\]"), - "\\2"); + ""); m_TagMap["font="] = std::make_pair(QRegExp("\\[font=([^\\]]*)\\](.*)\\[/font\\]"), "\\2"); m_TagMap["center"] = std::make_pair(QRegExp("\\[center\\](.*)\\[/center\\]"), @@ -139,10 +153,6 @@ private: "\\1"); m_TagMap["url="] = std::make_pair(QRegExp("\\[url=([^\\]]*)\\](.*)\\[/url\\]"), "\\2"); -/* 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\\]"), @@ -150,6 +160,11 @@ private: m_TagMap["youtube"] = std::make_pair(QRegExp("\\[youtube\\](.*)\\[/youtube\\]"), "http://www.youtube.com/v/\\1"); + 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 m_ColorMap; }; diff --git a/src/directoryrefresher.cpp b/src/directoryrefresher.cpp index 70bcf5b6..43e13a37 100644 --- a/src/directoryrefresher.cpp +++ b/src/directoryrefresher.cpp @@ -93,6 +93,7 @@ void DirectoryRefresher::refresh() //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); +qDebug("load files for mod %s", qPrintable(modName)); try { addModToStructure(m_DirectoryStructure, modName, i, std::get<1>(*iter)); } catch (const std::exception &e) { @@ -102,11 +103,14 @@ void DirectoryRefresher::refresh() } std::wstring dataDirectory = GameInfo::instance().getGameDirectory() + L"\\data"; +qDebug("load files for data folder"); m_DirectoryStructure->addFromOrigin(L"data", dataDirectory, 0); emit progress(100); +qDebug("cleanup structure"); cleanStructure(m_DirectoryStructure); +qDebug("all done"); emit refreshed(); } diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index e79c3ba6..03c282f0 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -27,6 +27,7 @@ along with Mod Organizer. If not, see . #include "json.h" #include "selectiondialog.h" #include +#include #include #include #include @@ -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; diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp index 7b8ed176..c6ddabce 100644 --- a/src/installationmanager.cpp +++ b/src/installationmanager.cpp @@ -522,9 +522,10 @@ bool InstallationManager::doInstall(GuessedValue &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()); diff --git a/src/logbuffer.cpp b/src/logbuffer.cpp index 689d2b55..b9fa9417 100644 --- a/src/logbuffer.cpp +++ b/src/logbuffer.cpp @@ -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); +} diff --git a/src/logbuffer.h b/src/logbuffer.h index 68753996..caada1d9 100644 --- a/src/logbuffer.h +++ b/src/logbuffer.h @@ -23,10 +23,12 @@ along with Mod Organizer. If not, see . #include #include #include +#include +#include #include -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 s_Instance; @@ -71,7 +92,7 @@ private: bool m_ShutDown; QtMsgType m_MinMsgType; unsigned int m_NumMessages; - std::vector m_Messages; + std::vector m_Messages; }; diff --git a/src/main.cpp b/src/main.cpp index aafb1992..3d00b10a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 65b3c795..391743a6 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -95,6 +95,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #include #include #include @@ -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() << 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); @@ -670,10 +681,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(""); } @@ -1415,9 +1428,11 @@ HANDLE MainWindow::spawnBinaryDirect(const QFileInfo &binary, const QString &arg QCoreApplication::processEvents(); } + // need to make sure all data is saved before we start the application if (m_CurrentProfile != nullptr) { m_CurrentProfile->writeModlistNow(true); } + savePluginList(); // TODO: should also pass arguments if (m_AboutToRun(binary.absoluteFilePath())) { @@ -2250,10 +2265,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; @@ -2278,12 +2293,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 @@ -5245,10 +5262,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() @@ -5342,6 +5359,8 @@ void MainWindow::on_bossButton_clicked() m_CurrentProfile->writeModlistNow(); + bool success = false; + try { this->setEnabled(false); ON_BLOCK_EXIT([&] () { this->setEnabled(true); }); @@ -5383,30 +5402,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()); + } } } @@ -5506,3 +5534,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")); +} diff --git a/src/mainwindow.h b/src/mainwindow.h index 83671015..3caa08ef 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -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 &filter) const; @@ -594,6 +594,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 diff --git a/src/mainwindow.ui b/src/mainwindow.ui index c7d35981..7ad3a90d 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -27,652 +27,143 @@ 0 - - - 4 - - - 6 - - - 6 - - - 6 - - - 6 - + - - - - - Categories - - - - 3 - - - 7 - - - 3 - - - 1 - - - - - - 100 - 0 - - - - - 161 - 16777215 - - - - Qt::CustomContextMenu - - - QAbstractItemView::ExtendedSelection - - - false - - - - 1 - - - - - - - - - - - - - - 0 - 0 - - + - Qt::Horizontal + Qt::Vertical - - - - 2 - + + - - - - - - 0 - 0 - - - - Profile - - - profileBox - - - - - - - Pick a module collection - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Create profiles here. Each profile contains its own list of active mods and esps. This way you can quickly switch between setups for different play throughs.</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Please note that right now your esp load order is not kept seperate for different profiles.</span></p></body></html> - - - - - - - - 24 - 16777215 - - - - Refresh list - - - Refresh list. This is usually not necessary unless you modified data outside the program. - - - - - - - :/MO/gui/resources/view-refresh.png:/MO/gui/resources/view-refresh.png - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Restore Backup... - - - - - - - :/MO/gui/restore:/MO/gui/restore - - - + - - - Create Backup - - - + + + Categories - - - :/MO/gui/backup:/MO/gui/backup - - - - - - - - - - 330 - 400 - - - - - - - - - 64 - 64 - 64 - - - - - - - 255 - 0 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - - - 64 - 64 - 64 - - - - - - - 255 - 0 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - - - 120 - 120 - 120 - - - - - - - 255 - 0 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - - Qt::CustomContextMenu - - - List of available mods. - - - This is a list of installed mods. Use the checkboxes to activate/deactivate mods and drag & drop mods to change their "installation" orders. - - - - - - QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked - - - true - - - true - - - QAbstractItemView::DragDrop - - - Qt::MoveAction - - - true - - - QAbstractItemView::ExtendedSelection - - - QAbstractItemView::SelectRows - - - 20 - - - true - - - true - - - false - - - 20 - - - true - - - false - - - - - - - - - - 20 - 16777215 - - - - x - - - - 20 - 20 - - - - true - - - - - - - - 0 - 0 - - - - Filter - - - - - - - - 8 - true - - - - - - - - - - - - No groups + + + 3 - - - - Categories + + 7 - - - - Nexus IDs + + 3 - - - - - - - Namefilter - - - - - - - - - - - - - - - - - 0 - 0 - - - - - 0 - 40 - - - - - 9 - 75 - true - - - - Pick a program to run. - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Choose the program to run. Once you start using ModOrganizer, you should always run your game and tools from here or through shortcuts created here, otherwise mods installed through MO will not be visible.</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You can add new Tools to this list, but I can't promise tools I haven't tested will work.</span></p></body></html> - - - - 32 - 32 - + + 1 - - false - - - - - - - - - - 0 - 0 - - - - - 120 - 0 - - - - - 16777215 - 16777215 - - - - - 10 - 75 - true - - - - Run program - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Run the selected program with ModOrganizer enabled.</span></p></body></html> - - - - - - Run - - - - :/MO/gui/run:/MO/gui/run - - - - 36 - 36 - - - - - - - - 0 - 0 - - + - 140 + 100 0 - 16777215 + 161 16777215 - - - 0 - 0 - - - - Create a shortcut in your start menu or on the desktop to the specified program - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This creates a start menu shortcut that directly starts the selected program with the MO active.</span></p></body></html> - - - Shortcut + + Qt::CustomContextMenu - - - :/MO/gui/link:/MO/gui/link + + QAbstractItemView::ExtendedSelection + + false + + + + 1 + + - - - + + + - - - - 340 - 250 - + + + + 0 + 0 + - - - 16777215 - 16777215 - + + Qt::Horizontal - - Qt::NoContextMenu - - - QTabWidget::Rounded - - - 0 - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - Plugins - - - - 6 - - - 6 - - - 6 - - - 0 + + + + 2 - + - + + + + 0 + 0 + + - Sort + Profile + + + profileBox + + + + + + + Pick a module collection + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Create profiles here. Each profile contains its own list of active mods and esps. This way you can quickly switch between setups for different play throughs.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Please note that right now your esp load order is not kept seperate for different profiles.</span></p></body></html> + + + + + + + + 24 + 16777215 + + + + Refresh list + + + Refresh list. This is usually not necessary unless you modified data outside the program. + + + - :/MO/gui/sort:/MO/gui/sort + :/MO/gui/resources/view-refresh.png:/MO/gui/resources/view-refresh.png - + Qt::Horizontal @@ -685,7 +176,7 @@ p, li { white-space: pre-wrap; } - + Restore Backup... @@ -696,16 +187,10 @@ p, li { white-space: pre-wrap; } :/MO/gui/restore:/MO/gui/restore - - - 16 - 16 - - - + Create Backup @@ -721,11 +206,11 @@ p, li { white-space: pre-wrap; } - + - 250 - 250 + 330 + 400 @@ -740,6 +225,24 @@ p, li { white-space: pre-wrap; } + + + + 255 + 0 + 0 + + + + + + + 0 + 170 + 0 + + + @@ -751,6 +254,24 @@ p, li { white-space: pre-wrap; } + + + + 255 + 0 + 0 + + + + + + + 0 + 170 + 0 + + + @@ -762,6 +283,24 @@ p, li { white-space: pre-wrap; } + + + + 255 + 0 + 0 + + + + + + + 0 + 170 + 0 + + + @@ -769,23 +308,25 @@ p, li { white-space: pre-wrap; } Qt::CustomContextMenu - List of available esp/esm files + List of available mods. - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This list contains the esps and esms contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html> + This is a list of installed mods. Use the checkboxes to activate/deactivate mods and drag & drop mods to change their "installation" orders. - + + + + + QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked + + true - - false + + true - QAbstractItemView::InternalMove + QAbstractItemView::DragDrop Qt::MoveAction @@ -800,356 +341,811 @@ p, li { white-space: pre-wrap; } QAbstractItemView::SelectRows - 0 - - - true + 20 - false + true true + + false + + + 20 + + + true + false - + - + + + + 20 + 16777215 + + - + x - - Namefilter + + + 20 + 20 + + + + true - - - - - - - Archives - - - - 6 - - - 6 - - - 6 - - - 6 - - - - - Qt::CustomContextMenu - - - List of available BS Archives. Archives not checked here are not managed by MO and ignore installation order. - - - BSA files are archives (comparable to .zip files) that contain data assets (meshes, textures, ...) to be used by the game. As such they "compete" with loose files in your data directory over which is loaded. -By default, BSAs that share their base name with an enabled ESP (i.e. plugin.esp and plugin.bsa) are automatically loaded and will have precedence over all loose files, the installation order you set up to the left is then ignored! - -BSAs checked here are loaded in such a way that your installation order is obeyed properly. - - - QAbstractItemView::NoEditTriggers - - - true - - - false - - - false - - - QAbstractItemView::DragDrop - - - Qt::MoveAction - - - QAbstractItemView::SingleSelection - - - QAbstractItemView::SelectRows - - - 20 - - - true - - - 1 - - - false - - - 200 - - - - File - - - - - - - - <html><head/><body><p>Marked Archives (<img src=":/MO/gui/warning_16"/>) are still loaded on Skyrim but the <a href="http://forums.bethsoft.com/topic/1354395-update-bsas-and-you/"><span style=" text-decoration: underline; color:#0000ff;">regular file override</span></a> mechanism will apply: Loose files override BSAs, no matter the mod/plugin priority.</p></body></html> - - - true - - - - - - - - Data - - - - 6 - - - 6 - - - 6 - - - 6 - - - - - refresh data-directory overview - - - Refresh the overview. This may take a moment. - - - Refresh - - - - :/MO/gui/resources/view-refresh.png:/MO/gui/resources/view-refresh.png - - - - - - - - Qt::CustomContextMenu + + + + 0 + 0 + - - This is an overview of your data directory as visible to the game (and tools). + + Filter - - true + + + + + + + 8 + true + + + + - - 400 - - + + + + + + + No groups + + + - File + Categories - - + + - Mod + Nexus IDs - + + + + + + + Namefilter + - - - - Filter the above list so that only conflicts are displayed. - - - Filter the above list so that only conflicts are displayed. - - - Show only conflicts - - - - - - Saves - - - - 6 - - - 6 - - - 6 - - - 6 - + + - - - Qt::CustomContextMenu - - - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + + + + + + + 0 + 0 + + + + + 0 + 40 + + + + + 9 + 75 + true + + + + Pick a program to run. + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of all savegames for this game. Hover over a list entry to get detailed information about the save including a list of esps/esms that were used at the time this save was created but aren't active now.</span></p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you click &quot;Fix Mods...&quot; in the context menu, MO will try to activate all mods and esps to fix those missing esps. It will not disable anything!</span></p></body></html> - +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Choose the program to run. Once you start using ModOrganizer, you should always run your game and tools from here or through shortcuts created here, otherwise mods installed through MO will not be visible.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You can add new Tools to this list, but I can't promise tools I haven't tested will work.</span></p></body></html> + + + + 32 + 32 + + + + false + + + + + + + + + + 0 + 0 + + + + + 120 + 0 + + + + + 16777215 + 16777215 + + + + + 10 + 75 + true + + + + Run program + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Run the selected program with ModOrganizer enabled.</span></p></body></html> + + + + + + Run + + + + :/MO/gui/run:/MO/gui/run + + + + 36 + 36 + + + + + + + + + 0 + 0 + + + + + 140 + 0 + + + + + 16777215 + 16777215 + + + + + 0 + 0 + + + + Create a shortcut in your start menu or on the desktop to the specified program + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This creates a start menu shortcut that directly starts the selected program with the MO active.</span></p></body></html> + + + Shortcut + + + + :/MO/gui/link:/MO/gui/link + + + + + + - - - - - Downloads - - - - 2 - - - 2 - - - 2 - - - 2 - - - - - - - 320 - 0 - + + + + 340 + 250 + + + + + 16777215 + 16777215 + + + + Qt::NoContextMenu + + + QTabWidget::Rounded + + + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Plugins + + + + 6 - - Qt::PreventContextMenu + + 6 - - + + 6 - - This is a list of mods you downloaded from Nexus. Double click one to install it. + + 0 - - Qt::ScrollBarAlwaysOn + + + + + + Sort + + + + :/MO/gui/sort:/MO/gui/sort + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Restore Backup... + + + + + + + :/MO/gui/restore:/MO/gui/restore + + + + 16 + 16 + + + + + + + + Create Backup + + + + + + + :/MO/gui/backup:/MO/gui/backup + + + + + + + + + + 250 + 250 + + + + + + + + + 64 + 64 + 64 + + + + + + + + + 64 + 64 + 64 + + + + + + + + + 120 + 120 + 120 + + + + + + + + Qt::CustomContextMenu + + + List of available esp/esm files + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This list contains the esps and esms contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html> + + + true + + + false + + + QAbstractItemView::InternalMove + + + Qt::MoveAction + + + true + + + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectRows + + + 0 + + + true + + + false + + + true + + + false + + + + + + + + + + + + Namefilter + + + + + + + + + + Archives + + + + 6 - - Qt::ScrollBarAlwaysOff + + 6 - - true + + 6 - - QAbstractItemView::DragDrop + + 6 - - Qt::MoveAction + + + + Qt::CustomContextMenu + + + List of available BS Archives. Archives not checked here are not managed by MO and ignore installation order. + + + BSA files are archives (comparable to .zip files) that contain data assets (meshes, textures, ...) to be used by the game. As such they "compete" with loose files in your data directory over which is loaded. +By default, BSAs that share their base name with an enabled ESP (i.e. plugin.esp and plugin.bsa) are automatically loaded and will have precedence over all loose files, the installation order you set up to the left is then ignored! + +BSAs checked here are loaded in such a way that your installation order is obeyed properly. + + + QAbstractItemView::NoEditTriggers + + + true + + + false + + + false + + + QAbstractItemView::DragDrop + + + Qt::MoveAction + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + 20 + + + true + + + 1 + + + false + + + 200 + + + + File + + + + + + + + <html><head/><body><p>Marked Archives (<img src=":/MO/gui/warning_16"/>) are still loaded on Skyrim but the <a href="http://forums.bethsoft.com/topic/1354395-update-bsas-and-you/"><span style=" text-decoration: underline; color:#0000ff;">regular file override</span></a> mechanism will apply: Loose files override BSAs, no matter the mod/plugin priority.</p></body></html> + + + true + + + + + + + + Data + + + + 6 - - true + + 6 - - QAbstractItemView::SingleSelection + + 6 - - QAbstractItemView::SelectRows + + 6 - - QAbstractItemView::ScrollPerPixel + + + + refresh data-directory overview + + + Refresh the overview. This may take a moment. + + + Refresh + + + + :/MO/gui/resources/view-refresh.png:/MO/gui/resources/view-refresh.png + + + + + + + + + Qt::CustomContextMenu + + + This is an overview of your data directory as visible to the game (and tools). + + + true + + + 400 + + + + File + + + + + Mod + + + + + + + + + + Filter the above list so that only conflicts are displayed. + + + Filter the above list so that only conflicts are displayed. + + + Show only conflicts + + + + + + + + Saves + + + + 6 - - 0 + + 6 - - false + + 6 - - true + + 6 - - 100 - - - true - - - - - - - - - - - Show Hidden + + + + Qt::CustomContextMenu + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of all savegames for this game. Hover over a list entry to get detailed information about the save including a list of esps/esms that were used at the time this save was created but aren't active now.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you click &quot;Fix Mods...&quot; in the context menu, MO will try to activate all mods and esps to fix those missing esps. It will not disable anything!</span></p></body></html> + + + + + + + + Downloads + + + + 2 - - - - - - Qt::Horizontal + + 2 - - - 40 - 20 - + + 2 - - - - - - Namefilter + + 2 - - - + + + + + + + 320 + 0 + + + + Qt::PreventContextMenu + + + + + + This is a list of mods you downloaded from Nexus. Double click one to install it. + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAlwaysOff + + + true + + + QAbstractItemView::DragDrop + + + Qt::MoveAction + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + QAbstractItemView::ScrollPerPixel + + + 0 + + + false + + + true + + + 100 + + + true + + + + + + + + + + + Show Hidden + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Namefilter + + + + + + + + @@ -1157,6 +1153,20 @@ p, li { white-space: pre-wrap; } + + + Qt::ActionsContextMenu + + + QAbstractItemView::NoSelection + + + false + + + true + + @@ -1370,6 +1380,14 @@ Right now this has very limited functionality Endorse Mod Organizer + + + Copy Log to Clipboard + + + Ctrl+C + + diff --git a/src/modlist.cpp b/src/modlist.cpp index 836406e4..25b0eb52 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -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; diff --git a/src/modlist.h b/src/modlist.h index cc5955d0..314839fe 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -239,6 +239,8 @@ private: bool dropMod(const QMimeData *mimeData, int row, const QModelIndex &parent); + ModStates state(unsigned int modIndex) const; + private slots: private: diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp index 4d767230..49f37726 100644 --- a/src/modlistsortproxy.cpp +++ b/src/modlistsortproxy.cpp @@ -28,8 +28,11 @@ along with Mod Organizer. If not, see . 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 &categories) diff --git a/src/modlistsortproxy.h b/src/modlistsortproxy.h index 3e18ea4e..f1b01c7e 100644 --- a/src/modlistsortproxy.h +++ b/src/modlistsortproxy.h @@ -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 m_EnabledColumns; QString m_CurrentFilter; + bool m_FilterActive; + }; #endif // MODLISTSORTPROXY_H diff --git a/src/resources.qrc b/src/resources.qrc index bf53ea95..2300a15e 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -24,13 +24,13 @@ resources/go-previous_16.png resources/view-refresh_16.png resources/software-update-available.png - resources/emblem-important.png + resources/emblem-important.png resources/check.png mo_icon.ico resources/dialog-warning.png resources/symbol-backup.png resources/applications-accessories.png - resources/emblem-unreadable.png + resources/emblem-unreadable.png resources/internet-web-browser.png resources/system-software-update.png resources/help-browser_32.png diff --git a/src/singleinstance.cpp b/src/singleinstance.cpp index 029e8366..2befab70 100644 --- a/src/singleinstance.cpp +++ b/src/singleinstance.cpp @@ -85,7 +85,7 @@ void SingleInstance::sendMessage(const QString &message) socket.write(message.toUtf8()); if (!socket.waitForBytesWritten(s_Timeout)) { - reportError(tr("failed to connect to running instance: %1").arg(socket.errorString())); + reportError(tr("failed to communicate with running instance: %1").arg(socket.errorString())); return; } diff --git a/src/version.rc b/src/version.rc index f76ac8dc..1efdde0d 100644 --- a/src/version.rc +++ b/src/version.rc @@ -1,7 +1,7 @@ #include "Winver.h" -#define VER_FILEVERSION 1,2,0,0 -#define VER_FILEVERSION_STR "1,2,0,0\0" +#define VER_FILEVERSION 1,2,1,0 +#define VER_FILEVERSION_STR "1,2,1,0\0" VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION -- cgit v1.3.1