diff options
| author | Jeremy Rimpo <jeremy.rimpo@servermonkey.com> | 2017-12-17 21:36:57 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-12-17 21:36:57 -0600 |
| commit | b157ebb28c38a5ade879c0736a9dcb7fe0367a89 (patch) | |
| tree | 276eb064a25143f9f8fb61206de08f90cf4f43fd /src | |
| parent | 554b46847589fffb6cd7bc5c54689665c34ed95b (diff) | |
| parent | 385a888c0bc8e5b4d4a6791e46eed3b5963c403a (diff) | |
Merge pull request #154 from Silarn/mainline_dev
Implementing archive parsing some prioritization
Diffstat (limited to 'src')
| -rw-r--r-- | src/iuserinterface.h | 4 | ||||
| -rw-r--r-- | src/mainwindow.cpp | 201 | ||||
| -rw-r--r-- | src/mainwindow.h | 13 | ||||
| -rw-r--r-- | src/mainwindow.ui | 107 | ||||
| -rw-r--r-- | src/modinfo.cpp | 5 | ||||
| -rw-r--r-- | src/modinfodialog.cpp | 10 | ||||
| -rw-r--r-- | src/modinfooverwrite.cpp | 2 | ||||
| -rw-r--r-- | src/modinforegular.cpp | 2 | ||||
| -rw-r--r-- | src/modinfowithconflictinfo.cpp | 10 | ||||
| -rw-r--r-- | src/modlist.cpp | 13 | ||||
| -rw-r--r-- | src/organizercore.cpp | 21 | ||||
| -rw-r--r-- | src/organizercore.h | 1 | ||||
| -rw-r--r-- | src/pluginlist.cpp | 26 | ||||
| -rw-r--r-- | src/shared/directoryentry.cpp | 68 | ||||
| -rw-r--r-- | src/shared/directoryentry.h | 6 | ||||
| -rw-r--r-- | src/syncoverwritedialog.cpp | 6 |
16 files changed, 412 insertions, 83 deletions
diff --git a/src/iuserinterface.h b/src/iuserinterface.h index 255c7ac0..7ce71c24 100644 --- a/src/iuserinterface.h +++ b/src/iuserinterface.h @@ -28,6 +28,10 @@ public: virtual void displayModInformation(ModInfo::Ptr modInfo, unsigned int index, int tab) = 0;
+ virtual void updateBSAList(const QStringList &defaultArchives, const QStringList &activeArchives) = 0;
+
+ virtual MOBase::DelayedFileWriterBase &archivesWriter() = 0;
+
virtual ILockedWaitingForProcess* lock() = 0;
virtual void unlock() = 0;
};
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 85808e8d..22e99e37 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -200,6 +200,7 @@ MainWindow::MainWindow(QSettings &initSettings , m_OrganizerCore(organizerCore)
, m_PluginContainer(pluginContainer)
, m_DidUpdateMasterList(false)
+ , m_ArchiveListWriter(std::bind(&MainWindow::saveArchiveList, this))
{
QWebEngineProfile::defaultProfile()->setPersistentCookiesPolicy(QWebEngineProfile::NoPersistentCookies);
QWebEngineProfile::defaultProfile()->setHttpCacheMaximumSize(52428800);
@@ -278,6 +279,8 @@ MainWindow::MainWindow(QSettings &initSettings ui->espList->setItemDelegateForColumn(PluginList::COL_FLAGS, new GenericIconDelegate(ui->espList));
ui->espList->installEventFilter(m_OrganizerCore.pluginList());
+ ui->bsaList->setLocalMoveOnly(true);
+
bool pluginListAdjusted = registerWidgetState(ui->espList->objectName(), ui->espList->header(), "plugin_list_state");
registerWidgetState(ui->dataTree->objectName(), ui->dataTree->header());
registerWidgetState(ui->downloadView->objectName(),
@@ -358,6 +361,9 @@ MainWindow::MainWindow(QSettings &initSettings connect(this, SIGNAL(styleChanged(QString)), this, SLOT(updateStyle(QString)));
+ m_CheckBSATimer.setSingleShot(true);
+ connect(&m_CheckBSATimer, SIGNAL(timeout()), this, SLOT(checkBSAList()));
+
connect(ui->espList->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(esplistSelectionsChanged(QItemSelection)));
connect(ui->modList->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(modlistSelectionsChanged(QItemSelection)));
@@ -1142,17 +1148,17 @@ void MainWindow::updateTo(QTreeWidgetItem *subTree, const std::wstring &director fileChild->setData(1, Qt::UserRole, source);
fileChild->setData(1, Qt::UserRole + 1, originID);
- std::vector<int> alternatives = current->getAlternatives();
+ std::vector<std::pair<int, std::wstring>> alternatives = current->getAlternatives();
if (!alternatives.empty()) {
std::wostringstream altString;
altString << ToWString(tr("Also in: <br>"));
- for (std::vector<int>::iterator altIter = alternatives.begin();
+ for (std::vector<std::pair<int, std::wstring>>::iterator altIter = alternatives.begin();
altIter != alternatives.end(); ++altIter) {
if (altIter != alternatives.begin()) {
altString << " , ";
}
- altString << "<span style=\"white-space: nowrap;\"><i>" << m_OrganizerCore.directoryStructure()->getOriginByID(*altIter).getName() << "</font></span>";
+ altString << "<span style=\"white-space: nowrap;\"><i>" << m_OrganizerCore.directoryStructure()->getOriginByID(altIter->first).getName() << "</font></span>";
}
fileChild->setToolTip(1, QString("%1").arg(ToQString(altString.str())));
fileChild->setForeground(1, QBrush(Qt::red));
@@ -1378,6 +1384,151 @@ static QStringList toStringList(InputIterator current, InputIterator end) return result;
}
+void MainWindow::updateBSAList(const QStringList &defaultArchives, const QStringList &activeArchives)
+{
+ m_DefaultArchives = defaultArchives;
+ ui->bsaList->clear();
+ ui->bsaList->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
+ std::vector<std::pair<UINT32, QTreeWidgetItem*>> items;
+
+ BSAInvalidation * invalidation = m_OrganizerCore.managedGame()->feature<BSAInvalidation>();
+ std::vector<FileEntry::Ptr> files = m_OrganizerCore.directoryStructure()->getFiles();
+
+ QStringList plugins = m_OrganizerCore.findFiles("", [](const QString &fileName) -> bool {
+ return fileName.endsWith(".esp", Qt::CaseInsensitive)
+ || fileName.endsWith(".esm", Qt::CaseInsensitive)
+ || fileName.endsWith(".esl", Qt::CaseInsensitive);
+ });
+
+ auto hasAssociatedPlugin = [&](const QString &bsaName) -> bool {
+ for (const QString &pluginName : plugins) {
+ QFileInfo pluginInfo(pluginName);
+ if (bsaName.startsWith(QFileInfo(pluginName).baseName(), Qt::CaseInsensitive)
+ && (m_OrganizerCore.pluginList()->state(pluginInfo.fileName()) == IPluginList::STATE_ACTIVE)) {
+ return true;
+ }
+ }
+ return false;
+ };
+
+ for (FileEntry::Ptr current : files) {
+ QFileInfo fileInfo(ToQString(current->getName().c_str()));
+
+ if (fileInfo.suffix().toLower() == "bsa" || fileInfo.suffix().toLower() == "ba2") {
+ int index = activeArchives.indexOf(fileInfo.fileName());
+ if (index == -1) {
+ index = 0xFFFF;
+ }
+ else {
+ index += 2;
+ }
+
+ if ((invalidation != nullptr) && invalidation->isInvalidationBSA(fileInfo.fileName())) {
+ index = 1;
+ }
+
+ int originId = current->getOrigin();
+ FilesOrigin & origin = m_OrganizerCore.directoryStructure()->getOriginByID(originId);
+
+ QTreeWidgetItem * newItem = new QTreeWidgetItem(QStringList()
+ << fileInfo.fileName()
+ << ToQString(origin.getName()));
+ newItem->setData(0, Qt::UserRole, index);
+ newItem->setData(1, Qt::UserRole, originId);
+ newItem->setFlags(newItem->flags() & ~(Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable));
+ newItem->setCheckState(0, (index != -1) ? Qt::Checked : Qt::Unchecked);
+ newItem->setData(0, Qt::UserRole, false);
+ if (m_OrganizerCore.settings().forceEnableCoreFiles()
+ && defaultArchives.contains(fileInfo.fileName())) {
+ newItem->setCheckState(0, Qt::Checked);
+ newItem->setDisabled(true);
+ newItem->setData(0, Qt::UserRole, true);
+ } else if (fileInfo.fileName().compare("update.bsa", Qt::CaseInsensitive) == 0) {
+ newItem->setCheckState(0, Qt::Checked);
+ newItem->setDisabled(true);
+ } else if (hasAssociatedPlugin(fileInfo.fileName())) {
+ newItem->setCheckState(0, Qt::Checked);
+ newItem->setDisabled(true);
+ } else {
+ newItem->setCheckState(0, Qt::Unchecked);
+ newItem->setDisabled(true);
+ }
+ if (index < 0) index = 0;
+
+ UINT32 sortValue = ((origin.getPriority() & 0xFFFF) << 16) | (index & 0xFFFF);
+ items.push_back(std::make_pair(sortValue, newItem));
+ }
+ }
+ std::sort(items.begin(), items.end(), BySortValue);
+
+ for (auto iter = items.begin(); iter != items.end(); ++iter) {
+ int originID = iter->second->data(1, Qt::UserRole).toInt();
+
+ FilesOrigin origin = m_OrganizerCore.directoryStructure()->getOriginByID(originID);
+ QString modName("data");
+ unsigned int modIndex = ModInfo::getIndex(ToQString(origin.getName()));
+ if (modIndex != UINT_MAX) {
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex);
+ modName = modInfo->name();
+ }
+ QList<QTreeWidgetItem*> items = ui->bsaList->findItems(modName, Qt::MatchFixedString);
+ QTreeWidgetItem * subItem = nullptr;
+ if (items.length() > 0) {
+ subItem = items.at(0);
+ }
+ else {
+ subItem = new QTreeWidgetItem(QStringList(modName));
+ subItem->setFlags(subItem->flags() & ~Qt::ItemIsDragEnabled);
+ ui->bsaList->addTopLevelItem(subItem);
+ }
+ subItem->addChild(iter->second);
+ subItem->setExpanded(true);
+ }
+ checkBSAList();
+}
+
+void MainWindow::checkBSAList()
+{
+ DataArchives * archives = m_OrganizerCore.managedGame()->feature<DataArchives>();
+
+ if (archives != nullptr) {
+ ui->bsaList->blockSignals(true);
+ ON_BLOCK_EXIT([&]() { ui->bsaList->blockSignals(false); });
+
+ QStringList defaultArchives = archives->archives(m_OrganizerCore.currentProfile());
+
+ bool warning = false;
+
+ for (int i = 0; i < ui->bsaList->topLevelItemCount(); ++i) {
+ bool modWarning = false;
+ QTreeWidgetItem * tlItem = ui->bsaList->topLevelItem(i);
+ for (int j = 0; j < tlItem->childCount(); ++j) {
+ QTreeWidgetItem * item = tlItem->child(j);
+ QString filename = item->text(0);
+ item->setIcon(0, QIcon());
+ item->setToolTip(0, QString());
+
+ if (item->checkState(0) == Qt::Unchecked) {
+ if (defaultArchives.contains(filename)) {
+ item->setIcon(0, QIcon(":/MO/gui/warning"));
+ item->setToolTip(0, tr("This bsa is enabled in the ini file so it may be required!"));
+ modWarning = true;
+ }
+ }
+ }
+ if (modWarning) {
+ ui->bsaList->expandItem(ui->bsaList->topLevelItem(i));
+ warning = true;
+ }
+ }
+ if (warning) {
+ ui->tabWidget->setTabIcon(1, QIcon(":/MO/gui/warning"));
+ } else {
+ ui->tabWidget->setTabIcon(1, QIcon());
+ }
+ }
+}
+
void MainWindow::saveModMetas()
{
for (unsigned int i = 0; i < ModInfo::getNumMods(); ++i) {
@@ -1524,10 +1675,12 @@ void MainWindow::on_tabWidget_currentChanged(int index) if (index == 0) {
m_OrganizerCore.refreshESPList();
} else if (index == 1) {
- refreshDataTree();
+ m_OrganizerCore.refreshBSAList();
} else if (index == 2) {
- refreshSaveList();
+ refreshDataTree();
} else if (index == 3) {
+ refreshSaveList();
+ } else if (index == 4) {
ui->downloadView->scrollToBottom();
}
}
@@ -1806,6 +1959,7 @@ void MainWindow::modorder_changed() }
m_OrganizerCore.refreshBSAList();
m_OrganizerCore.currentProfile()->modlistWriter().write();
+ m_ArchiveListWriter.write();
m_OrganizerCore.directoryStructure()->getFileRegister()->sortOrigins();
{ // refresh selection
@@ -2741,6 +2895,27 @@ void MainWindow::replaceCategories_MenuHandler() { refreshFilters();
}
+void MainWindow::saveArchiveList()
+{
+ if (m_OrganizerCore.isArchivesInit()) {
+ SafeWriteFile archiveFile(m_OrganizerCore.currentProfile()->getArchivesFileName());
+ for (int i = 0; i < ui->bsaList->topLevelItemCount(); ++i) {
+ QTreeWidgetItem * tlItem = ui->bsaList->topLevelItem(i);
+ for (int j = 0; j < tlItem->childCount(); ++j) {
+ QTreeWidgetItem * item = tlItem->child(j);
+ if (item->checkState(0) == Qt::Checked) {
+ archiveFile->write(item->text(0).toUtf8().append("\r\n"));
+ }
+ }
+ }
+ if (archiveFile.commitIfDifferent(m_ArchiveListHash)) {
+ qDebug("%s saved", qPrintable(QDir::toNativeSeparators(m_OrganizerCore.currentProfile()->getArchivesFileName())));
+ }
+ } else {
+ qWarning("archive list not initialised");
+ }
+}
+
void MainWindow::checkModsForUpdates()
{
statusBar()->show();
@@ -3588,8 +3763,8 @@ void MainWindow::previewDataFile() };
addFunc(file->getOrigin());
- for (int i : file->getAlternatives()) {
- addFunc(i);
+ for (auto alt : file->getAlternatives()) {
+ addFunc(alt.first);
}
if (preview.numVariants() > 0) {
preview.exec();
@@ -3957,6 +4132,12 @@ void MainWindow::displayColumnSelection(const QPoint &pos) }
}
+void MainWindow::on_bsaList_itemChanged(QTreeWidgetItem*, int)
+{
+ m_ArchiveListWriter.write();
+ m_CheckBSATimer.start(500);
+}
+
void MainWindow::on_actionProblems_triggered()
{
ProblemsDialog problems(m_PluginContainer.plugins<IPluginDiagnose>(), this);
@@ -4543,6 +4724,12 @@ void MainWindow::on_categoriesOrBtn_toggled(bool checked) }
}
+void MainWindow::on_managedArchiveLabel_linkHovered(const QString&)
+{
+ QToolTip::showText(QCursor::pos(),
+ ui->managedArchiveLabel->toolTip());
+}
+
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
//Accept copy or move drags to the download window. Link drags are not
diff --git a/src/mainwindow.h b/src/mainwindow.h index 575bf020..45a41137 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -120,12 +120,15 @@ public: virtual void unlock() override;
bool addProfile();
+ void updateBSAList(const QStringList &defaultArchives, const QStringList &activeArchives);
void refreshDataTree();
void refreshSaveList();
void setModListSorting(int index);
void setESPListSorting(int index);
+ void saveArchiveList();
+
void registerPluginTool(MOBase::IPluginTool *tool);
void registerModPage(MOBase::IPluginModPage *modPage);
@@ -148,6 +151,8 @@ public: virtual bool closeWindow();
virtual void setWindowEnabled(bool enabled);
+ virtual MOBase::DelayedFileWriterBase &archivesWriter() override { return m_ArchiveListWriter; }
+
public slots:
void displayColumnSelection(const QPoint &pos);
@@ -346,6 +351,8 @@ private: std::vector<QTreeWidgetItem*> m_RemoveWidget;
+ QByteArray m_ArchiveListHash;
+
bool m_DidUpdateMasterList;
LockedDialogBase *m_LockDialog { nullptr };
@@ -355,6 +362,8 @@ private: std::vector<std::pair<QString, QHeaderView*>> m_PersistedGeometry;
+ MOBase::DelayedFileWriter m_ArchiveListWriter;
+
enum class ShortcutType {
Toolbar,
Desktop,
@@ -478,6 +487,8 @@ private slots: void startExeAction();
+ void checkBSAList();
+
void updateProblemsButton();
void saveModMetas();
@@ -552,6 +563,7 @@ private slots: // ui slots void on_categoriesList_itemSelectionChanged();
void on_linkButton_pressed();
void on_showHiddenBox_toggled(bool checked);
+ void on_bsaList_itemChanged(QTreeWidgetItem *item, int column);
void on_bossButton_clicked();
void on_saveButton_clicked();
@@ -561,6 +573,7 @@ private slots: // ui slots void on_actionCopy_Log_to_Clipboard_triggered();
void on_categoriesAndBtn_toggled(bool checked);
void on_categoriesOrBtn_toggled(bool checked);
+ void on_managedArchiveLabel_linkHovered(const QString &link);
};
diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 26b9e375..d8fa1432 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -902,6 +902,113 @@ p, li { white-space: pre-wrap; } </item>
</layout>
</widget>
+ <widget class="QWidget" name="bsaTab">
+ <attribute name="title">
+ <string>Archives</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_9">
+ <property name="leftMargin">
+ <number>6</number>
+ </property>
+
+ <property name="topMargin">
+ <number>6</number>
+ </property>
+ <property name="rightMargin">
+ <number>6</number>
+ </property>
+ <property name="bottomMargin">
+ <number>6</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_9" stretch="0,1">
+ <!--<item>-->
+ <!--<widget class="QCheckBox" name="manageArchivesBox">-->
+ <!--<property name="text">-->
+ <!--<string/>-->
+ <!--</property>-->
+ <!--<property name="checked">-->
+ <!--<bool>true</bool>-->
+ <!--</property>-->
+ <!--</widget>-->
+ <!--</item>-->
+ <item>
+ <widget class="QLabel" name="managedArchiveLabel">
+ <property name="toolTip">
+ <string><html><head/><body><p>BSAs / BA2s are bundles of game assets (textures, scripts, etc.). By default, the engine loads these bundles in a separate step from loose files. <p>Their load order is specified by the priority of the corresponding plugin (right pane, plugins tab).</p><p>If there is a matching plugin, the game will load them no matter what.</p></body></html></string>
+ </property>
+ <property name="text">
+ <string><html><head/><body><p>Currently detected archives. (<a href="#"><span style=" text-decoration: underline; color:#0000ff;">What is an archive?</span></a>)</p></body></html></string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="MOBase::SortableTreeWidget" name="bsaList">
+ <property name="contextMenuPolicy">
+ <enum>Qt::CustomContextMenu</enum>
+ </property>
+ <property name="toolTip">
+ <string>List of available BS Archives. Archives not checked here are not managed by MO and ignore installation order.</string>
+ </property>
+ <property name="whatsThis">
+ <string>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.</string>
+ </property>
+ <property name="editTriggers">
+ <set>QAbstractItemView::NoEditTriggers</set>
+ </property>
+ <property name="showDropIndicator" stdset="0">
+ <bool>false</bool>
+ </property>
+ <property name="dragEnabled">
+ <bool>false</bool>
+ </property>
+ <property name="dragDropOverwriteMode">
+ <bool>false</bool>
+ </property>
+ <property name="dragDropMode">
+ <enum>QAbstractItemView::NoDragDrop</enum>
+ </property>
+ <property name="defaultDropAction">
+ <enum>Qt::IgnoreAction</enum>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::SingleSelection</enum>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ <property name="indentation">
+ <number>20</number>
+ </property>
+ <property name="itemsExpandable">
+ <bool>true</bool>
+ </property>
+ <property name="columnCount">
+ <number>1</number>
+ </property>
+ <attribute name="headerVisible">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="headerDefaultSectionSize">
+ <number>200</number>
+ </attribute>
+ <column>
+ <property name="text">
+ <string>File</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ </layout>
+ </widget>
<widget class="QWidget" name="dataTab">
<attribute name="title">
<string>Data</string>
diff --git a/src/modinfo.cpp b/src/modinfo.cpp index 4f74086f..c14eedb7 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -94,7 +94,7 @@ QString ModInfo::getContentTypeName(int contentType) case CONTENT_PLUGIN: return tr("Plugins"); case CONTENT_TEXTURE: return tr("Textures"); case CONTENT_MESH: return tr("Meshes"); - case CONTENT_BSA: return tr("BSA"); + case CONTENT_BSA: return tr("Bethesda Archive"); case CONTENT_INTERFACE: return tr("UI Changes"); case CONTENT_SOUND: return tr("Sound Effects"); case CONTENT_SCRIPT: return tr("Scripts"); @@ -123,9 +123,10 @@ ModInfo::Ptr ModInfo::getByIndex(unsigned int index) { QMutexLocker locker(&s_Mutex); - if (index >= s_Collection.size()) { + if (index >= s_Collection.size() && index != ULONG_MAX) { throw MyException(tr("invalid mod index %1").arg(index)); } + if (index == ULONG_MAX) return s_Collection[ModInfo::getIndex("Overwrite")]; return s_Collection[index]; } diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index d43808b6..ccd2a122 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -266,22 +266,22 @@ void ModInfoDialog::refreshLists() QString fileName = relativeName.mid(0).prepend(m_RootPath);
bool archive;
if ((*iter)->getOrigin(archive) == m_Origin->getID()) {
- std::vector<int> alternatives = (*iter)->getAlternatives();
+ std::vector<std::pair<int, std::wstring>> alternatives = (*iter)->getAlternatives();
if (!alternatives.empty()) {
std::wostringstream altString;
- for (std::vector<int>::iterator altIter = alternatives.begin();
+ for (std::vector<std::pair<int, std::wstring>>::iterator altIter = alternatives.begin();
altIter != alternatives.end(); ++altIter) {
if (altIter != alternatives.begin()) {
altString << ", ";
}
- altString << m_Directory->getOriginByID(*altIter).getName();
+ altString << m_Directory->getOriginByID(altIter->first).getName();
}
QStringList fields(relativeName.prepend("..."));
fields.append(ToQString(altString.str()));
QTreeWidgetItem *item = new QTreeWidgetItem(fields);
item->setData(0, Qt::UserRole, fileName);
- item->setData(1, Qt::UserRole, ToQString(m_Directory->getOriginByID(alternatives[0]).getName()));
- item->setData(1, Qt::UserRole + 1, alternatives[0]);
+ item->setData(1, Qt::UserRole, ToQString(m_Directory->getOriginByID(alternatives.begin()->first).getName()));
+ item->setData(1, Qt::UserRole + 1, alternatives.begin()->first);
item->setData(1, Qt::UserRole + 2, archive);
ui->overwriteTree->addTopLevelItem(item);
++numOverwrite;
diff --git a/src/modinfooverwrite.cpp b/src/modinfooverwrite.cpp index 6b8c9bd9..360212c0 100644 --- a/src/modinfooverwrite.cpp +++ b/src/modinfooverwrite.cpp @@ -53,7 +53,7 @@ QStringList ModInfoOverwrite::archives() const { QStringList result; QDir dir(this->absolutePath()); - for (const QString &archive : dir.entryList(QStringList("*.bsa"))) { + for (const QString &archive : dir.entryList(QStringList({ "*.bsa", "*.ba2" }))) { result.append(this->absolutePath() + "/" + archive); } return result; diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index 9d94002b..5486bb2c 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -551,7 +551,7 @@ QStringList ModInfoRegular::archives() const { QStringList result; QDir dir(this->absolutePath()); - for (const QString &archive : dir.entryList(QStringList("*.bsa"))) { + for (const QString &archive : dir.entryList(QStringList({ "*.bsa", "*.ba2" }))) { result.append(this->absolutePath() + "/" + archive); } return result; diff --git a/src/modinfowithconflictinfo.cpp b/src/modinfowithconflictinfo.cpp index fbf2345f..b8ece783 100644 --- a/src/modinfowithconflictinfo.cpp +++ b/src/modinfowithconflictinfo.cpp @@ -57,8 +57,8 @@ void ModInfoWithConflictInfo::doConflictCheck() const std::vector<FileEntry::Ptr> files = origin.getFiles(); // for all files in this origin for (FileEntry::Ptr file : files) { - const std::vector<int> &alternatives = file->getAlternatives(); - if ((alternatives.size() == 0) || (alternatives[0] == dataID)) { + const std::vector<std::pair<int, std::wstring>> &alternatives = file->getAlternatives(); + if ((alternatives.size() == 0) || (alternatives.begin()->first == dataID)) { // no alternatives -> no conflict providesAnything = true; } else { @@ -71,9 +71,9 @@ void ModInfoWithConflictInfo::doConflictCheck() const } // for all non-providing alternative origins - for (int altId : alternatives) { - if ((altId != dataID) && (altId != origin.getID())) { - FilesOrigin &altOrigin = (*m_DirectoryStructure)->getOriginByID(altId); + for (auto altInfo : alternatives) { + if ((altInfo.first != dataID) && (altInfo.first != origin.getID())) { + FilesOrigin &altOrigin = (*m_DirectoryStructure)->getOriginByID(altInfo.first); unsigned int altIndex = ModInfo::getIndex(ToQString(altOrigin.getName())); if (origin.getPriority() > altOrigin.getPriority()) { m_OverwriteList.insert(altIndex); diff --git a/src/modlist.cpp b/src/modlist.cpp index 53350c59..3afa94b5 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -64,7 +64,7 @@ ModList::ModList(QObject *parent) m_ContentIcons[ModInfo::CONTENT_PLUGIN] = std::make_tuple(":/MO/gui/content/plugin", tr("Game Plugins (ESP/ESM/ESL)"));
m_ContentIcons[ModInfo::CONTENT_INTERFACE] = std::make_tuple(":/MO/gui/content/interface", tr("Interface"));
m_ContentIcons[ModInfo::CONTENT_MESH] = std::make_tuple(":/MO/gui/content/mesh", tr("Meshes"));
- m_ContentIcons[ModInfo::CONTENT_BSA] = std::make_tuple(":/MO/gui/content/bsa", tr("BSA"));
+ m_ContentIcons[ModInfo::CONTENT_BSA] = std::make_tuple(":/MO/gui/content/bsa", tr("Bethesda Archive"));
m_ContentIcons[ModInfo::CONTENT_SCRIPT] = std::make_tuple(":/MO/gui/content/script", tr("Scripts (Papyrus)"));
m_ContentIcons[ModInfo::CONTENT_SKSE] = std::make_tuple(":/MO/gui/content/skse", tr("Script Extender Plugin"));
m_ContentIcons[ModInfo::CONTENT_SKYPROC] = std::make_tuple(":/MO/gui/content/skyproc", tr("SkyProc Patcher"));
@@ -701,14 +701,13 @@ void ModList::highlightMods(const QItemSelection &selected, const MOShared::Dire if (fileEntry.get() != nullptr) {
QString fileName;
bool archive = false;
- std::vector<int> origins;
+ std::vector<std::pair<int, std::wstring>> origins;
{
- std::vector<int> alternatives = fileEntry->getAlternatives();
- origins.push_back(fileEntry->getOrigin(archive));
- origins.insert(origins.end(), alternatives.begin(), alternatives.end());
+ std::vector<std::pair<int, std::wstring>> alternatives = fileEntry->getAlternatives();
+ origins.insert(origins.end(), std::pair<int, std::wstring>(fileEntry->getOrigin(archive), fileEntry->getArchive()));
}
- for (int originId : origins) {
- MOShared::FilesOrigin &origin = directoryEntry.getOriginByID(originId);
+ for (auto originInfo : origins) {
+ MOShared::FilesOrigin &origin = directoryEntry.getOriginByID(originInfo.first);
for (unsigned int i = 0; i < ModInfo::getNumMods(); ++i) {
if (ModInfo::getByIndex(i)->internalName() == QString::fromStdWString(origin.getName())) {
ModInfo::getByIndex(i)->setPluginSelected(true);
diff --git a/src/organizercore.cpp b/src/organizercore.cpp index dd77f19a..98920479 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1002,9 +1002,9 @@ QStringList OrganizerCore::getFileOrigins(const QString &fileName) const if (file.get() != nullptr) {
result.append(ToQString(
m_DirectoryStructure->getOriginByID(file->getOrigin()).getName()));
- foreach (int i, file->getAlternatives()) {
+ foreach (auto i, file->getAlternatives()) {
result.append(
- ToQString(m_DirectoryStructure->getOriginByID(i).getName()));
+ ToQString(m_DirectoryStructure->getOriginByID(i.first).getName()));
}
} else {
qDebug("%s not found", qPrintable(fileName));
@@ -1030,9 +1030,9 @@ QList<MOBase::IOrganizer::FileInfo> OrganizerCore::findFileInfos( m_DirectoryStructure->getOriginByID(file->getOrigin(fromArchive))
.getName()));
info.archive = fromArchive ? ToQString(file->getArchive()) : "";
- foreach (int idx, file->getAlternatives()) {
+ foreach (auto idx, file->getAlternatives()) {
info.origins.append(
- ToQString(m_DirectoryStructure->getOriginByID(idx).getName()));
+ ToQString(m_DirectoryStructure->getOriginByID(idx.first).getName()));
}
if (filter(info)) {
@@ -1494,6 +1494,10 @@ void OrganizerCore::refreshBSAList() if (m_ActiveArchives.isEmpty()) {
m_ActiveArchives = m_DefaultArchives;
}
+
+ if (m_UserInterface != nullptr) {
+ m_UserInterface->updateBSAList(m_DefaultArchives, m_ActiveArchives);
+ }
m_ArchivesInit = true;
}
@@ -1572,6 +1576,9 @@ void OrganizerCore::updateModInDirectoryStructure(unsigned int index, // now we need to refresh the bsa list and save it so there is no confusion
// about what archives are avaiable and active
refreshBSAList();
+ if (m_UserInterface != nullptr) {
+ m_UserInterface->archivesWriter().writeImmediately(false);
+ }
std::vector<QString> archives = enabledArchives();
m_DirectoryRefresher.setMods(
@@ -1729,6 +1736,9 @@ void OrganizerCore::modStatusChanged(unsigned int index) = m_DirectoryStructure->getOriginByName(ToWString(modInfo->name()));
origin.enable(false);
}
+ if (m_UserInterface != nullptr) {
+ m_UserInterface->archivesWriter().write();
+ }
}
modInfo->clearCaches();
@@ -1885,6 +1895,9 @@ bool OrganizerCore::saveCurrentLists() try {
savePluginList();
+ if (m_UserInterface != nullptr) {
+ m_UserInterface->archivesWriter().write();
+ }
} catch (const std::exception &e) {
reportError(tr("failed to save load order: %1").arg(e.what()));
}
diff --git a/src/organizercore.h b/src/organizercore.h index cf030e0a..decb3d01 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -315,6 +315,7 @@ private: ModList m_ModList;
PluginList m_PluginList;
+
QList<std::function<void()>> m_PostLoginTasks;
QList<std::function<void()>> m_PostRefreshTasks;
diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index 6392d44b..775086fd 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -115,23 +115,23 @@ void PluginList::highlightPlugins(const QItemSelection &selected, const MOShared }
for (QModelIndex idx : selected.indexes()) {
ModInfo::Ptr selectedMod = ModInfo::getByIndex(idx.data(Qt::UserRole + 1).toInt());
- if (!selectedMod.isNull() && profile.modEnabled(idx.data(Qt::UserRole + 1).toInt())) { - QDir dir(selectedMod->absolutePath()); - QStringList plugins = dir.entryList(QStringList() << "*.esp" << "*.esm" << "*.esl"); - MOShared::FilesOrigin origin = directoryEntry.getOriginByName(selectedMod->internalName().toStdWString()); - if (plugins.size() > 0) { - for (auto plugin : plugins) { + if (!selectedMod.isNull() && profile.modEnabled(idx.data(Qt::UserRole + 1).toInt())) {
+ QDir dir(selectedMod->absolutePath());
+ QStringList plugins = dir.entryList(QStringList() << "*.esp" << "*.esm" << "*.esl");
+ MOShared::FilesOrigin origin = directoryEntry.getOriginByName(selectedMod->internalName().toStdWString());
+ if (plugins.size() > 0) {
+ for (auto plugin : plugins) {
MOShared::FileEntry::Ptr file = directoryEntry.findFile(plugin.toStdWString());
if (file->getOrigin() != origin.getID()) {
- const std::vector<int> alternatives = file->getAlternatives();
- if (std::find(alternatives.begin(), alternatives.end(), origin.getID()) == alternatives.end())
+ const std::vector<std::pair<int, std::wstring>> alternatives = file->getAlternatives();
+ if (std::find_if(alternatives.begin(), alternatives.end(), [&](const std::pair<int, std::wstring>& element) { return element.first == origin.getID(); }) == alternatives.end())
continue;
}
- std::map<QString, int>::iterator iter = m_ESPsByName.find(plugin.toLower()); - if (iter != m_ESPsByName.end()) { - m_ESPs[iter->second].m_ModSelected = true; - } - } + std::map<QString, int>::iterator iter = m_ESPsByName.find(plugin.toLower());
+ if (iter != m_ESPsByName.end()) {
+ m_ESPs[iter->second].m_ModSelected = true;
+ }
+ }
}
}
}
diff --git a/src/shared/directoryentry.cpp b/src/shared/directoryentry.cpp index df6a7b5a..e1cba08c 100644 --- a/src/shared/directoryentry.cpp +++ b/src/shared/directoryentry.cpp @@ -236,9 +236,10 @@ void FileEntry::addOrigin(int origin, FILETIME fileTime, const std::wstring &arc m_FileTime = fileTime;
m_Archive = archive;
} else if ((m_Parent != nullptr)
- && (m_Parent->getOriginByID(origin).getPriority() > m_Parent->getOriginByID(m_Origin).getPriority())) {
- if (std::find(m_Alternatives.begin(), m_Alternatives.end(), m_Origin) == m_Alternatives.end()) {
- m_Alternatives.push_back(m_Origin);
+ && (m_Parent->getOriginByID(origin).getPriority() > m_Parent->getOriginByID(m_Origin).getPriority())
+ && (archive.size() == 0 || m_Archive.size() > 0 )) {
+ if (std::find_if(m_Alternatives.begin(), m_Alternatives.end(), [&](const std::pair<int, std::wstring> &i) -> bool { return i.first == m_Origin; }) == m_Alternatives.end()) {
+ m_Alternatives.push_back(std::pair<int, std::wstring>(m_Origin, m_Archive));
}
m_Origin = origin;
m_FileTime = fileTime;
@@ -249,20 +250,20 @@ void FileEntry::addOrigin(int origin, FILETIME fileTime, const std::wstring &arc // already an origin
return;
}
- for (std::vector<int>::iterator iter = m_Alternatives.begin(); iter != m_Alternatives.end(); ++iter) {
- if (*iter == origin) {
+ for (std::vector<std::pair<int, std::wstring>>::iterator iter = m_Alternatives.begin(); iter != m_Alternatives.end(); ++iter) {
+ if (iter->first == origin) {
// already an origin
return;
}
if ((m_Parent != nullptr)
- && (m_Parent->getOriginByID(*iter).getPriority() < m_Parent->getOriginByID(origin).getPriority())) {
- m_Alternatives.insert(iter, origin);
+ && (m_Parent->getOriginByID(iter->first).getPriority() < m_Parent->getOriginByID(origin).getPriority())) {
+ m_Alternatives.insert(iter, std::pair<int, std::wstring>(origin, archive));
found = true;
break;
}
}
if (!found) {
- m_Alternatives.push_back(origin);
+ m_Alternatives.push_back(std::pair<int, std::wstring>(origin, archive));
}
}
}
@@ -272,14 +273,14 @@ bool FileEntry::removeOrigin(int origin) if (m_Origin == origin) {
if (!m_Alternatives.empty()) {
// find alternative with the highest priority
- std::vector<int>::iterator currentIter = m_Alternatives.begin();
- for (std::vector<int>::iterator iter = m_Alternatives.begin(); iter != m_Alternatives.end(); ++iter) {
- if ((m_Parent->getOriginByID(*iter).getPriority() > m_Parent->getOriginByID(*currentIter).getPriority()) &&
- (*iter != origin)) {
+ std::vector<std::pair<int, std::wstring>>::iterator currentIter = m_Alternatives.begin();
+ for (std::vector<std::pair<int, std::wstring>>::iterator iter = m_Alternatives.begin(); iter != m_Alternatives.end(); ++iter) {
+ if ((m_Parent->getOriginByID(iter->first).getPriority() > m_Parent->getOriginByID(currentIter->first).getPriority()) &&
+ (iter->first != origin)) {
currentIter = iter;
}
}
- int currentID = *currentIter;
+ int currentID = currentIter->first;
m_Alternatives.erase(currentIter);
m_Origin = currentID;
@@ -303,23 +304,13 @@ bool FileEntry::removeOrigin(int origin) return true;
}
} else {
- std::vector<int>::iterator newEnd = std::remove(m_Alternatives.begin(), m_Alternatives.end(), origin);
- m_Alternatives.erase(newEnd, m_Alternatives.end());
+ std::vector<std::pair<int, std::wstring>>::iterator newEnd = std::find_if(m_Alternatives.begin(), m_Alternatives.end(), [&](const std::pair<int, std::wstring> &i) -> bool { return i.first == origin; });
+ if (newEnd != m_Alternatives.end())
+ m_Alternatives.erase(newEnd, m_Alternatives.end());
}
return false;
}
-
-// sorted by priority descending
-static bool ByOriginPriority(DirectoryEntry *entry, int LHS, int RHS)
-{
- int l = entry->getOriginByID(LHS).getPriority(); if (l < 0) l = INT_MAX;
- int r = entry->getOriginByID(RHS).getPriority(); if (r < 0) r = INT_MAX;
-
- return l < r;
-}
-
-
FileEntry::FileEntry()
: m_Index(UINT_MAX), m_Name(), m_Origin(-1), m_Parent(nullptr), m_LastAccessed(time(nullptr))
{
@@ -339,10 +330,23 @@ FileEntry::~FileEntry() void FileEntry::sortOrigins()
{
- m_Alternatives.push_back(m_Origin);
- std::sort(m_Alternatives.begin(), m_Alternatives.end(), boost::bind(ByOriginPriority, m_Parent, _1, _2));
- m_Origin = m_Alternatives[m_Alternatives.size() - 1];
- m_Alternatives.pop_back();
+ m_Alternatives.push_back(std::pair<int, std::wstring>(m_Origin, m_Archive));
+ std::sort(m_Alternatives.begin(), m_Alternatives.end(), [&](const std::pair<int, std::wstring> &LHS, const std::pair<int, std::wstring> &RHS) -> bool {
+ if ((!LHS.second.size() && !RHS.second.size()) || (LHS.second.size() && RHS.second.size())) {
+ int l = m_Parent->getOriginByID(LHS.first).getPriority(); if (l < 0) l = INT_MAX;
+ int r = m_Parent->getOriginByID(RHS.first).getPriority(); if (r < 0) r = INT_MAX;
+
+ return l < r;
+ }
+
+ if (RHS.second.size()) return false;
+ return true;
+ });
+ if (!m_Alternatives.empty()) {
+ m_Origin = m_Alternatives.back().first;
+ m_Archive = m_Alternatives.back().second;
+ m_Alternatives.pop_back();
+ }
}
@@ -886,9 +890,9 @@ void FileRegister::unregisterFile(FileEntry::Ptr file) // unregister from origin
int originID = file->getOrigin(ignore);
m_OriginConnection->getByID(originID).removeFile(file->getIndex());
- const std::vector<int> &alternatives = file->getAlternatives();
+ const std::vector<std::pair<int, std::wstring>> &alternatives = file->getAlternatives();
for (auto iter = alternatives.begin(); iter != alternatives.end(); ++iter) {
- m_OriginConnection->getByID(*iter).removeFile(file->getIndex());
+ m_OriginConnection->getByID(iter->first).removeFile(file->getIndex());
}
// unregister from directory
diff --git a/src/shared/directoryentry.h b/src/shared/directoryentry.h index 04b8782b..8dbedaf4 100644 --- a/src/shared/directoryentry.h +++ b/src/shared/directoryentry.h @@ -72,7 +72,7 @@ public: // gets the list of alternative origins (origins with lower priority than the primary one).
// if sortOrigins has been called, it is sorted by priority (ascending)
- const std::vector<int> &getAlternatives() const { return m_Alternatives; }
+ const std::vector<std::pair<int, std::wstring>> &getAlternatives() const { return m_Alternatives; }
const std::wstring &getName() const { return m_Name; }
int getOrigin() const { return m_Origin; }
@@ -96,9 +96,9 @@ private: Index m_Index;
std::wstring m_Name;
- int m_Origin;
+ int m_Origin = -1;
std::wstring m_Archive;
- std::vector<int> m_Alternatives;
+ std::vector<std::pair<int, std::wstring>> m_Alternatives;
DirectoryEntry *m_Parent;
mutable FILETIME m_FileTime;
diff --git a/src/syncoverwritedialog.cpp b/src/syncoverwritedialog.cpp index aeed0a55..f03e29c5 100644 --- a/src/syncoverwritedialog.cpp +++ b/src/syncoverwritedialog.cpp @@ -98,9 +98,9 @@ void SyncOverwriteDialog::readTree(const QString &path, DirectoryEntry *director bool ignore;
int origin = entry->getOrigin(ignore);
addToComboBox(combo, ToQString(m_DirectoryStructure->getOriginByID(origin).getName()), origin);
- const std::vector<int> &alternatives = entry->getAlternatives();
- for (std::vector<int>::const_iterator iter = alternatives.begin(); iter != alternatives.end(); ++iter) {
- addToComboBox(combo, ToQString(m_DirectoryStructure->getOriginByID(*iter).getName()), *iter);
+ const std::vector<std::pair<int, std::wstring>> &alternatives = entry->getAlternatives();
+ for (std::vector<std::pair<int, std::wstring>>::const_iterator iter = alternatives.begin(); iter != alternatives.end(); ++iter) {
+ addToComboBox(combo, ToQString(m_DirectoryStructure->getOriginByID(iter->first).getName()), iter->first);
}
combo->setCurrentIndex(combo->count() - 1);
} else {
|
