summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorisanae <14251494+isanae@users.noreply.github.com>2019-12-10 10:48:09 -0500
committerisanae <14251494+isanae@users.noreply.github.com>2020-02-04 03:33:16 -0500
commit7e748d15c9d4fdf42b753f58e033899c5753b899 (patch)
tree1dd850ea652acf4cbcc8d43a8dc8d50dbc0bee72 /src
parente9da5b4fad488a5e1ff61d68cc6a24b68f0d4440 (diff)
split data tab
removed a bunch of undefined functions in MainWindow
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/datatab.cpp668
-rw-r--r--src/datatab.h83
-rw-r--r--src/mainwindow.cpp632
-rw-r--r--src/mainwindow.h44
-rw-r--r--src/modinfodialogfwd.h1
6 files changed, 774 insertions, 657 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 5d81f9da..51ce3960 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -144,6 +144,7 @@ SET(organizer_SRCS
loot.cpp
lootdialog.cpp
filterlist.cpp
+ datatab.cpp
shared/windows_error.cpp
shared/error_report.cpp
@@ -268,6 +269,7 @@ SET(organizer_HDRS
lootdialog.h
json.h
filterlist.h
+ datatab.h
shared/windows_error.h
shared/error_report.h
@@ -320,6 +322,7 @@ SET(organizer_RCS
source_group(src REGULAR_EXPRESSION ".*\\.(h|cpp|ui)")
set(application
+ datatab
filterlist
iuserinterface
main
diff --git a/src/datatab.cpp b/src/datatab.cpp
new file mode 100644
index 00000000..fb42a904
--- /dev/null
+++ b/src/datatab.cpp
@@ -0,0 +1,668 @@
+#include "datatab.h"
+#include "ui_mainwindow.h"
+#include "settings.h"
+#include "organizercore.h"
+#include "directoryentry.h"
+#include "messagedialog.h"
+#include <log.h>
+#include <report.h>
+
+using namespace MOShared;
+using namespace MOBase;
+
+// in mainwindow.cpp
+QString UnmanagedModName();
+
+
+DataTab::DataTab(
+ OrganizerCore& core, PluginContainer& pc,
+ QWidget* parent, Ui::MainWindow* mwui) :
+ m_core(core), m_pluginContainer(pc), m_archives(false), m_parent(parent),
+ ui{
+ mwui->btnRefreshData, mwui->dataTree,
+ mwui->conflictsCheckBox, mwui->showArchiveDataCheckBox}
+{
+ connect(
+ ui.refresh, &QPushButton::clicked,
+ [&]{ onRefresh(); });
+
+ connect(
+ ui.tree, &QTreeWidget::itemExpanded,
+ [&](auto* item){ onItemExpanded(item); });
+
+ connect(
+ ui.tree, &QTreeWidget::itemActivated,
+ [&](auto* item, int col){ onItemActivated(item, col); });
+
+ connect(
+ ui.tree, &QTreeWidget::customContextMenuRequested,
+ [&](auto pos){ onContextMenu(pos); });
+
+ connect(
+ ui.conflicts, &QCheckBox::toggled,
+ [&]{ onConflicts(); });
+
+ connect(
+ ui.archives, &QCheckBox::toggled,
+ [&]{ onArchives(); });
+}
+
+void DataTab::saveState(Settings& s) const
+{
+ s.geometry().saveState(ui.tree->header());
+}
+
+void DataTab::restoreState(const Settings& s)
+{
+ s.geometry().restoreState(ui.tree->header());
+}
+
+void DataTab::activated()
+{
+ refreshDataTreeKeepExpandedNodes();
+}
+
+QTreeWidgetItem* DataTab::singleSelection()
+{
+ const auto sel = ui.tree->selectedItems();
+ if (sel.count() != 1) {
+ return nullptr;
+ }
+
+ return sel[0];
+}
+
+void DataTab::openSelection()
+{
+ if (auto* item=singleSelection()) {
+ open(item);
+ }
+}
+
+void DataTab::open(QTreeWidgetItem* item)
+{
+ const auto isArchive = item->data(0, Qt::UserRole + 1).toBool();
+ const auto isDirectory = item->data(0, Qt::UserRole + 3).toBool();
+
+ if (isArchive || isDirectory) {
+ return;
+ }
+
+ const QString path = item->data(0, Qt::UserRole).toString();
+ const QFileInfo targetInfo(path);
+
+ m_core.processRunner()
+ .setFromFile(m_parent, targetInfo)
+ .setHooked(false)
+ .setWaitForCompletion(ProcessRunner::Refresh)
+ .run();
+}
+
+void DataTab::runSelectionHooked()
+{
+ if (auto* item=singleSelection()) {
+ runHooked(item);
+ }
+}
+
+void DataTab::runHooked(QTreeWidgetItem* item)
+{
+ const auto isArchive = item->data(0, Qt::UserRole + 1).toBool();
+ const auto isDirectory = item->data(0, Qt::UserRole + 3).toBool();
+
+ if (isArchive || isDirectory) {
+ return;
+ }
+
+ const QString path = item->data(0, Qt::UserRole).toString();
+ const QFileInfo targetInfo(path);
+
+ m_core.processRunner()
+ .setFromFile(m_parent, targetInfo)
+ .setHooked(true)
+ .setWaitForCompletion(ProcessRunner::Refresh)
+ .run();
+}
+
+void DataTab::previewSelection()
+{
+ if (auto* item=singleSelection()) {
+ preview(item);
+ }
+}
+
+void DataTab::preview(QTreeWidgetItem* item)
+{
+ QString fileName = QDir::fromNativeSeparators(item->data(0, Qt::UserRole).toString());
+ m_core.previewFileWithAlternatives(m_parent, fileName);
+}
+
+void DataTab::onRefresh()
+{
+ m_core.refreshDirectoryStructure();
+}
+
+void DataTab::refreshDataTree()
+{
+ QIcon folderIcon = (new QFileIconProvider())->icon(QFileIconProvider::Folder);
+ QIcon fileIcon = (new QFileIconProvider())->icon(QFileIconProvider::File);
+ ui.tree->clear();
+ QStringList columns("data");
+ columns.append("");
+ QTreeWidgetItem *subTree = new QTreeWidgetItem(columns);
+ subTree->setData(0, Qt::DecorationRole, (new QFileIconProvider())->icon(QFileIconProvider::Folder));
+ updateTo(subTree, L"", *m_core.directoryStructure(), ui.conflicts->isChecked(), &fileIcon, &folderIcon);
+ ui.tree->insertTopLevelItem(0, subTree);
+ subTree->setExpanded(true);
+}
+
+void DataTab::refreshDataTreeKeepExpandedNodes()
+{
+ QIcon folderIcon = (new QFileIconProvider())->icon(QFileIconProvider::Folder);
+ QIcon fileIcon = (new QFileIconProvider())->icon(QFileIconProvider::File);
+ QStringList expandedNodes;
+ QTreeWidgetItemIterator it1(ui.tree, QTreeWidgetItemIterator::NotHidden | QTreeWidgetItemIterator::HasChildren);
+ while (*it1) {
+ QTreeWidgetItem *current = (*it1);
+ if (current->isExpanded() && !(current->text(0)=="data")) {
+ expandedNodes.append(current->text(0)+"/"+current->parent()->text(0));
+ }
+ ++it1;
+ }
+
+ ui.tree->clear();
+ QStringList columns("data");
+ columns.append("");
+ QTreeWidgetItem *subTree = new QTreeWidgetItem(columns);
+ subTree->setData(0, Qt::DecorationRole, (new QFileIconProvider())->icon(QFileIconProvider::Folder));
+ updateTo(subTree, L"", *m_core.directoryStructure(), ui.conflicts->isChecked(), &fileIcon, &folderIcon);
+ ui.tree->insertTopLevelItem(0, subTree);
+ subTree->setExpanded(true);
+ QTreeWidgetItemIterator it2(ui.tree, QTreeWidgetItemIterator::HasChildren);
+ while (*it2) {
+ QTreeWidgetItem *current = (*it2);
+ if (!(current->text(0)=="data") && expandedNodes.contains(current->text(0)+"/"+current->parent()->text(0))) {
+ current->setExpanded(true);
+ }
+ ++it2;
+ }
+}
+
+void DataTab::updateTo(
+ QTreeWidgetItem *subTree, const std::wstring &directorySoFar,
+ const DirectoryEntry &directoryEntry, bool conflictsOnly,
+ QIcon *fileIcon, QIcon *folderIcon)
+{
+ bool isDirectory = true;
+ //QIcon folderIcon = (new QFileIconProvider())->icon(QFileIconProvider::Folder);
+ //QIcon fileIcon = (new QFileIconProvider())->icon(QFileIconProvider::File);
+
+ std::wostringstream temp;
+ temp << directorySoFar << "\\" << directoryEntry.getName();
+ {
+ std::vector<DirectoryEntry*>::const_iterator current, end;
+ directoryEntry.getSubDirectories(current, end);
+ for (; current != end; ++current) {
+ QString pathName = QString::fromStdWString((*current)->getName());
+ QStringList columns(pathName);
+ columns.append("");
+ if (!(*current)->isEmpty()) {
+ QTreeWidgetItem *directoryChild = new QTreeWidgetItem(columns);
+ directoryChild->setData(0, Qt::DecorationRole, *folderIcon);
+ directoryChild->setData(0, Qt::UserRole + 3, isDirectory);
+
+ if (conflictsOnly || !m_archives) {
+ updateTo(directoryChild, temp.str(), **current, conflictsOnly, fileIcon, folderIcon);
+ if (directoryChild->childCount() != 0) {
+ subTree->addChild(directoryChild);
+ }
+ else {
+ delete directoryChild;
+ }
+ }
+ else {
+ QTreeWidgetItem *onDemandLoad = new QTreeWidgetItem(QStringList());
+ onDemandLoad->setData(0, Qt::UserRole + 0, "__loaded_on_demand__");
+ onDemandLoad->setData(0, Qt::UserRole + 1, QString::fromStdWString(temp.str()));
+ onDemandLoad->setData(0, Qt::UserRole + 2, conflictsOnly);
+ directoryChild->addChild(onDemandLoad);
+ subTree->addChild(directoryChild);
+ }
+ }
+ else {
+ QTreeWidgetItem *directoryChild = new QTreeWidgetItem(columns);
+ directoryChild->setData(0, Qt::DecorationRole, *folderIcon);
+ directoryChild->setData(0, Qt::UserRole + 3, isDirectory);
+ subTree->addChild(directoryChild);
+ }
+ }
+ }
+
+
+ isDirectory = false;
+ {
+ for (const FileEntry::Ptr current : directoryEntry.getFiles()) {
+ if (conflictsOnly && (current->getAlternatives().size() == 0)) {
+ continue;
+ }
+
+ bool isArchive = false;
+ int originID = current->getOrigin(isArchive);
+ if (!m_archives && isArchive) {
+ continue;
+ }
+
+ QString fileName = QString::fromStdWString(current->getName());
+ QStringList columns(fileName);
+ FilesOrigin origin = m_core.directoryStructure()->getOriginByID(originID);
+
+ QString source;
+ const unsigned int modIndex = ModInfo::getIndex(
+ QString::fromStdWString(origin.getName()));
+
+ if (modIndex == UINT_MAX) {
+ source = UnmanagedModName();
+ } else {
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex);
+ source = modInfo->name();
+ }
+
+ std::pair<std::wstring, int> archive = current->getArchive();
+ if (archive.first.length() != 0) {
+ source.append(" (").append(QString::fromStdWString(archive.first)).append(")");
+ }
+ columns.append(source);
+ QTreeWidgetItem *fileChild = new QTreeWidgetItem(columns);
+ if (isArchive) {
+ QFont font = fileChild->font(0);
+ font.setItalic(true);
+ fileChild->setFont(0, font);
+ fileChild->setFont(1, font);
+ } else if (fileName.endsWith(ModInfo::s_HiddenExt)) {
+ QFont font = fileChild->font(0);
+ font.setStrikeOut(true);
+ fileChild->setFont(0, font);
+ fileChild->setFont(1, font);
+ }
+ fileChild->setData(0, Qt::UserRole, QString::fromStdWString(current->getFullPath()));
+ fileChild->setData(0, Qt::DecorationRole, *fileIcon);
+ fileChild->setData(0, Qt::UserRole + 3, isDirectory);
+ fileChild->setData(0, Qt::UserRole + 1, isArchive);
+ fileChild->setData(1, Qt::UserRole, source);
+ fileChild->setData(1, Qt::UserRole + 1, originID);
+
+ std::vector<std::pair<int, std::pair<std::wstring, int>>> alternatives = current->getAlternatives();
+
+ if (!alternatives.empty()) {
+ std::wostringstream altString;
+ altString << tr("Also in: <br>").toStdWString();
+ for (std::vector<std::pair<int, std::pair<std::wstring, int>>>::iterator altIter = alternatives.begin();
+ altIter != alternatives.end(); ++altIter) {
+ if (altIter != alternatives.begin()) {
+ altString << " , ";
+ }
+ altString << "<span style=\"white-space: nowrap;\"><i>" << m_core.directoryStructure()->getOriginByID(altIter->first).getName() << "</font></span>";
+ }
+ fileChild->setToolTip(1, QString("%1").arg(QString::fromStdWString(altString.str())));
+ fileChild->setForeground(1, QBrush(Qt::red));
+ } else {
+ fileChild->setToolTip(1, tr("No conflict"));
+ }
+ subTree->addChild(fileChild);
+ }
+ }
+
+
+ //subTree->sortChildren(0, Qt::AscendingOrder);
+}
+
+void DataTab::onItemExpanded(QTreeWidgetItem* item)
+{
+ if ((item->childCount() == 1) && (item->child(0)->data(0, Qt::UserRole).toString() == "__loaded_on_demand__")) {
+ // read the data we need from the sub-item, then dispose of it
+ QTreeWidgetItem *onDemandDataItem = item->child(0);
+ const QString path = onDemandDataItem->data(0, Qt::UserRole + 1).toString();
+ std::wstring wspath = path.toStdWString();
+ bool conflictsOnly = onDemandDataItem->data(0, Qt::UserRole + 2).toBool();
+
+ std::wstring virtualPath = (wspath + L"\\").substr(6) + item->text(0).toStdWString();
+ DirectoryEntry *dir = m_core.directoryStructure()->findSubDirectoryRecursive(virtualPath);
+ if (dir != nullptr) {
+ QIcon folderIcon = (new QFileIconProvider())->icon(QFileIconProvider::Folder);
+ QIcon fileIcon = (new QFileIconProvider())->icon(QFileIconProvider::File);
+ updateTo(item, wspath, *dir, conflictsOnly, &fileIcon, &folderIcon);
+ } else {
+ log::warn("failed to update view of {}", path);
+ }
+
+ m_removeLater.push_back(item);
+
+ QTimer::singleShot(5, [this]{
+ for (QTreeWidgetItem *item : m_removeLater) {
+ item->removeChild(item->child(0));
+ }
+ m_removeLater.clear();
+ });
+ }
+}
+
+void DataTab::onItemActivated(QTreeWidgetItem *item, int column)
+{
+ const auto isArchive = item->data(0, Qt::UserRole + 1).toBool();
+ const auto isDirectory = item->data(0, Qt::UserRole + 3).toBool();
+
+ if (isArchive || isDirectory) {
+ return;
+ }
+
+ const QString path = item->data(0, Qt::UserRole).toString();
+ const QFileInfo targetInfo(path);
+
+ const auto tryPreview = m_core.settings().interface().doubleClicksOpenPreviews();
+
+ if (tryPreview && m_pluginContainer.previewGenerator().previewSupported(targetInfo.suffix())) {
+ emit preview(item);
+ } else {
+ emit open(item);
+ }
+}
+
+void DataTab::onContextMenu(const QPoint &pos)
+{
+ auto* item = ui.tree->itemAt(pos.x(), pos.y());
+
+ QMenu menu;
+ if ((item != nullptr) && (item->childCount() == 0)
+ && (item->data(0, Qt::UserRole + 3).toBool() != true)) {
+ QString fileName = item->text(0);
+ const auto isArchive = item->data(0, Qt::UserRole + 1).toBool();
+ const auto isDirectory = item->data(0, Qt::UserRole + 3).toBool();
+
+ QAction* open = nullptr;
+ QAction* runHooked = nullptr;
+ QAction* preview = nullptr;
+
+ if (canRunFile(isArchive, fileName)) {
+ open = new QAction(tr("&Execute"), ui.tree);
+ runHooked = new QAction(tr("Execute with &VFS"), ui.tree);
+ } else if (canOpenFile(isArchive, fileName)) {
+ open = new QAction(tr("&Open"), ui.tree);
+ runHooked = new QAction(tr("Open with &VFS"), ui.tree);
+ }
+
+ if (m_pluginContainer.previewGenerator().previewSupported(QFileInfo(fileName).suffix())) {
+ preview = new QAction(tr("Preview"), ui.tree);
+ }
+
+ if (open) {
+ connect(open, &QAction::triggered, [&]{ openSelection(); });
+ }
+
+ if (runHooked) {
+ connect(runHooked, &QAction::triggered, [&]{ runSelectionHooked(); });
+ }
+
+ if (preview) {
+ connect(preview, &QAction::triggered, [&]{ previewSelection(); });
+ }
+
+ if (open && preview) {
+ if (m_core.settings().interface().doubleClicksOpenPreviews()) {
+ menu.addAction(preview);
+ menu.addAction(open);
+ } else {
+ menu.addAction(open);
+ menu.addAction(preview);
+ }
+ } else {
+ if (open) {
+ menu.addAction(open);
+ }
+
+ if (preview) {
+ menu.addAction(preview);
+ }
+ }
+
+ if (runHooked) {
+ menu.addAction(runHooked);
+ }
+
+ menu.addAction(tr("&Add as Executable"), [&]{ addAsExecutable(); });
+
+ if (!isArchive && !isDirectory) {
+ menu.addAction("Open Origin in Explorer", [&]{ openOriginInExplorer(); });
+ }
+
+ menu.addAction("Open Mod Info", [&]{ openModInfo(); });
+
+ menu.addSeparator();
+
+ // offer to hide/unhide file, but not for files from archives
+ if (!isArchive) {
+ if (item->text(0).endsWith(ModInfo::s_HiddenExt)) {
+ menu.addAction(tr("Un-Hide"), [&]{ unhideFile(); });
+ } else {
+ menu.addAction(tr("Hide"), [&]{ hideFile(); });
+ }
+ }
+
+ if (open || preview || runHooked) {
+ // bold the first option
+ auto* top = menu.actions()[0];
+ auto f = top->font();
+ f.setBold(true);
+ top->setFont(f);
+ }
+ }
+
+ menu.addAction(tr("Write To File..."), [&]{ writeDataToFile(); });
+ menu.addAction(tr("Refresh"), [&]{ onRefresh(); });
+
+ menu.exec(ui.tree->viewport()->mapToGlobal(pos));
+}
+
+void DataTab::onConflicts()
+{
+ refreshDataTreeKeepExpandedNodes();
+}
+
+void DataTab::onArchives()
+{
+ m_archives = (m_core.getArchiveParsing() && ui.archives->isChecked());
+ refreshDataTree();
+}
+
+void DataTab::addAsExecutable()
+{
+ auto* item = singleSelection();
+ if (!item) {
+ return;
+ }
+
+ const QFileInfo target(item->data(0, Qt::UserRole).toString());
+ const auto fec = spawn::getFileExecutionContext(m_parent, target);
+
+ switch (fec.type)
+ {
+ case spawn::FileExecutionTypes::Executable:
+ {
+ const QString name = QInputDialog::getText(
+ m_parent, tr("Enter Name"),
+ tr("Enter a name for the executable"),
+ QLineEdit::Normal,
+ target.completeBaseName());
+
+ if (!name.isEmpty()) {
+ //Note: If this already exists, you'll lose custom settings
+ m_core.executablesList()->setExecutable(Executable()
+ .title(name)
+ .binaryInfo(fec.binary)
+ .arguments(fec.arguments)
+ .workingDirectory(target.absolutePath()));
+
+ emit executablesChanged();
+ }
+
+ break;
+ }
+
+ case spawn::FileExecutionTypes::Other: // fall-through
+ default:
+ {
+ QMessageBox::information(
+ m_parent, tr("Not an executable"),
+ tr("This is not a recognized executable."));
+
+ break;
+ }
+ }
+}
+
+void DataTab::openOriginInExplorer()
+{
+ auto* item = singleSelection();
+ if (!item) {
+ return;
+ }
+
+ const auto isArchive = item->data(0, Qt::UserRole + 1).toBool();
+ const auto isDirectory = item->data(0, Qt::UserRole + 3).toBool();
+
+ if (isArchive || isDirectory) {
+ return;
+ }
+
+ const auto fullPath = item->data(0, Qt::UserRole).toString();
+
+ log::debug("opening in explorer: {}", fullPath);
+ shell::Explore(fullPath);
+}
+
+void DataTab::openModInfo()
+{
+ auto* item = singleSelection();
+ if (!item) {
+ return;
+ }
+
+ const auto originID = item->data(1, Qt::UserRole + 1).toInt();
+ if (originID == 0) {
+ // unmanaged
+ return;
+ }
+
+ const auto& origin = m_core.directoryStructure()->getOriginByID(originID);
+ const auto& name = QString::fromStdWString(origin.getName());
+
+ unsigned int index = ModInfo::getIndex(name);
+ if (index == UINT_MAX) {
+ log::error("can't open mod info, mod '{}' not found", name);
+ return;
+ }
+
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(index);
+ if (modInfo) {
+ emit displayModInformation(modInfo, index, ModInfoTabIDs::None);
+ }
+}
+
+void DataTab::hideFile()
+{
+ auto* item = singleSelection();
+ if (!item) {
+ return;
+ }
+
+ QString oldName = item->data(0, Qt::UserRole).toString();
+ QString newName = oldName + ModInfo::s_HiddenExt;
+
+ if (QFileInfo(newName).exists()) {
+ if (QMessageBox::question(m_parent, tr("Replace file?"), tr("There already is a hidden version of this file. Replace it?"),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ if (!QFile(newName).remove()) {
+ QMessageBox::critical(m_parent, tr("File operation failed"), tr("Failed to remove \"%1\". Maybe you lack the required file permissions?").arg(newName));
+ return;
+ }
+ } else {
+ return;
+ }
+ }
+
+ if (QFile::rename(oldName, newName)) {
+ emit originModified(item->data(1, Qt::UserRole + 1).toInt());
+ refreshDataTreeKeepExpandedNodes();
+ } else {
+ reportError(tr("failed to rename \"%1\" to \"%2\"").arg(oldName).arg(QDir::toNativeSeparators(newName)));
+ }
+}
+
+void DataTab::unhideFile()
+{
+ auto* item = singleSelection();
+ if (!item) {
+ return;
+ }
+
+ QString oldName = item->data(0, Qt::UserRole).toString();
+ QString newName = oldName.left(oldName.length() - ModInfo::s_HiddenExt.length());
+ if (QFileInfo(newName).exists()) {
+ if (QMessageBox::question(m_parent, tr("Replace file?"), tr("There already is a visible version of this file. Replace it?"),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ if (!QFile(newName).remove()) {
+ QMessageBox::critical(m_parent, tr("File operation failed"), tr("Failed to remove \"%1\". Maybe you lack the required file permissions?").arg(newName));
+ return;
+ }
+ } else {
+ return;
+ }
+ }
+ if (QFile::rename(oldName, newName)) {
+ emit originModified(item->data(1, Qt::UserRole + 1).toInt());
+ refreshDataTreeKeepExpandedNodes();
+ } else {
+ reportError(tr("failed to rename \"%1\" to \"%2\"").arg(QDir::toNativeSeparators(oldName)).arg(QDir::toNativeSeparators(newName)));
+ }
+}
+
+void DataTab::writeDataToFile(
+ QFile &file, const QString &directory, const DirectoryEntry &directoryEntry)
+{
+ for (FileEntry::Ptr current : directoryEntry.getFiles()) {
+ bool isArchive = false;
+ int origin = current->getOrigin(isArchive);
+ if (isArchive) {
+ // TODO: don't list files from archives. maybe make this an option?
+ continue;
+ }
+ QString fullName = directory + "\\" + ToQString(current->getName());
+ file.write(fullName.toUtf8());
+
+ file.write("\t(");
+ file.write(ToQString(m_core.directoryStructure()->getOriginByID(origin).getName()).toUtf8());
+ file.write(")\r\n");
+ }
+
+ // recurse into subdirectories
+ std::vector<DirectoryEntry*>::const_iterator current, end;
+ directoryEntry.getSubDirectories(current, end);
+ for (; current != end; ++current) {
+ writeDataToFile(file, directory + "\\" + ToQString((*current)->getName()), **current);
+ }
+}
+
+void DataTab::writeDataToFile()
+{
+ QString fileName = QFileDialog::getSaveFileName(m_parent);
+ if (!fileName.isEmpty()) {
+ QFile file(fileName);
+ if (!file.open(QIODevice::WriteOnly)) {
+ reportError(tr("failed to write to file %1").arg(fileName));
+ }
+
+ writeDataToFile(file, "data", *m_core.directoryStructure());
+ file.close();
+
+ MessageDialog::showMessage(tr("%1 written").arg(QDir::toNativeSeparators(fileName)), m_parent);
+ }
+}
diff --git a/src/datatab.h b/src/datatab.h
new file mode 100644
index 00000000..27d36936
--- /dev/null
+++ b/src/datatab.h
@@ -0,0 +1,83 @@
+#include "modinfodialogfwd.h"
+#include "modinfo.h"
+#include <QPushButton>
+#include <QTreeWidget>
+#include <QCheckBox>
+
+namespace Ui { class MainWindow; }
+class OrganizerCore;
+class Settings;
+class PluginContainer;
+
+namespace MOShared { class DirectoryEntry; }
+
+class DataTab : public QObject
+{
+ Q_OBJECT;
+
+public:
+ DataTab(
+ OrganizerCore& core, PluginContainer& pc,
+ QWidget* parent, Ui::MainWindow* ui);
+
+ void saveState(Settings& s) const;
+ void restoreState(const Settings& s);
+ void activated();
+
+ void refreshDataTreeKeepExpandedNodes();
+ void refreshDataTree();
+
+signals:
+ void executablesChanged();
+ void originModified(int originID);
+ void displayModInformation(ModInfo::Ptr m, unsigned int i, ModInfoTabIDs tab);
+
+private:
+ struct DataTabUi
+ {
+ QPushButton* refresh;
+ QTreeWidget* tree;
+ QCheckBox* conflicts;
+ QCheckBox* archives;
+ };
+
+ OrganizerCore& m_core;
+ PluginContainer& m_pluginContainer;
+ bool m_archives;
+ QWidget* m_parent;
+ DataTabUi ui;
+ std::vector<QTreeWidgetItem*> m_removeLater;
+
+ void onRefresh();
+ void onItemExpanded(QTreeWidgetItem* item);
+ void onItemActivated(QTreeWidgetItem* item, int col);
+ void onContextMenu(const QPoint &pos);
+ void onConflicts();
+ void onArchives();
+
+ void updateTo(
+ QTreeWidgetItem *subTree, const std::wstring &directorySoFar,
+ const MOShared::DirectoryEntry &directoryEntry, bool conflictsOnly,
+ QIcon *fileIcon, QIcon *folderIcon);
+
+ QTreeWidgetItem* singleSelection();
+
+ void openSelection();
+ void open(QTreeWidgetItem* item);
+
+ void runSelectionHooked();
+ void runHooked(QTreeWidgetItem* item);
+
+ void previewSelection();
+ void preview(QTreeWidgetItem* item);
+
+ void addAsExecutable();
+ void openOriginInExplorer();
+ void openModInfo();
+ void hideFile();
+ void unhideFile();
+ void writeDataToFile();
+ void writeDataToFile(
+ QFile &file, const QString &directory,
+ const MOShared::DirectoryEntry &directoryEntry);
+};
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index d6ccc905..2ed9bd3c 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -77,6 +77,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "eventfilter.h"
#include "statusbar.h"
#include "filterlist.h"
+#include "datatab.h"
#include <utility.h>
#include <dataarchives.h>
#include <bsainvalidation.h>
@@ -299,7 +300,19 @@ MainWindow::MainWindow(Settings &settings
const bool pluginListAdjusted =
settings.geometry().restoreState(ui->espList->header());
- settings.geometry().restoreState(ui->dataTree->header());
+ m_DataTab.reset(new DataTab(m_OrganizerCore, m_PluginContainer, this, ui));
+ m_DataTab->restoreState(settings);
+
+ connect(m_DataTab.get(), &DataTab::executablesChanged, [&]{ refreshExecutablesList(); });
+
+ connect(
+ m_DataTab.get(), &DataTab::originModified,
+ [&](int id){ originModified(id); });
+
+ connect(
+ m_DataTab.get(), &DataTab::displayModInformation,
+ [&](auto&& m, auto&& i, auto&& tab){ displayModInformation(m, i, tab); });
+
settings.geometry().restoreState(ui->downloadView->header());
ui->splitter->setStretchFactor(0, 3);
@@ -349,9 +362,6 @@ MainWindow::MainWindow(Settings &settings
connect(ui->espFilterEdit, SIGNAL(textChanged(QString)), m_PluginListSortProxy, SLOT(updateFilter(QString)));
connect(ui->espFilterEdit, SIGNAL(textChanged(QString)), this, SLOT(espFilterChanged(QString)));
- connect(ui->dataTree, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(expandDataTreeItem(QTreeWidgetItem*)));
- connect(ui->dataTree, SIGNAL(itemActivated(QTreeWidgetItem*, int)), this, SLOT(activateDataTreeItem(QTreeWidgetItem*, int)));
-
connect(m_OrganizerCore.directoryRefresher(), SIGNAL(refreshed()), this, SLOT(directory_refreshed()));
connect(m_OrganizerCore.directoryRefresher(), SIGNAL(progress(int)), this, SLOT(refresher_progress(int)));
connect(m_OrganizerCore.directoryRefresher(), SIGNAL(error(QString)), this, SLOT(showError(QString)));
@@ -1657,161 +1667,6 @@ void MainWindow::on_profileBox_currentIndexChanged(int index)
}
}
-void MainWindow::updateTo(QTreeWidgetItem *subTree, const std::wstring &directorySoFar, const DirectoryEntry &directoryEntry, bool conflictsOnly, QIcon *fileIcon, QIcon *folderIcon)
-{
- bool isDirectory = true;
- //QIcon folderIcon = (new QFileIconProvider())->icon(QFileIconProvider::Folder);
- //QIcon fileIcon = (new QFileIconProvider())->icon(QFileIconProvider::File);
-
- std::wostringstream temp;
- temp << directorySoFar << "\\" << directoryEntry.getName();
- {
- std::vector<DirectoryEntry*>::const_iterator current, end;
- directoryEntry.getSubDirectories(current, end);
- for (; current != end; ++current) {
- QString pathName = ToQString((*current)->getName());
- QStringList columns(pathName);
- columns.append("");
- if (!(*current)->isEmpty()) {
- QTreeWidgetItem *directoryChild = new QTreeWidgetItem(columns);
- directoryChild->setData(0, Qt::DecorationRole, *folderIcon);
- directoryChild->setData(0, Qt::UserRole + 3, isDirectory);
-
- if (conflictsOnly || !m_showArchiveData) {
- updateTo(directoryChild, temp.str(), **current, conflictsOnly, fileIcon, folderIcon);
- if (directoryChild->childCount() != 0) {
- subTree->addChild(directoryChild);
- }
- else {
- delete directoryChild;
- }
- }
- else {
- QTreeWidgetItem *onDemandLoad = new QTreeWidgetItem(QStringList());
- onDemandLoad->setData(0, Qt::UserRole + 0, "__loaded_on_demand__");
- onDemandLoad->setData(0, Qt::UserRole + 1, ToQString(temp.str()));
- onDemandLoad->setData(0, Qt::UserRole + 2, conflictsOnly);
- directoryChild->addChild(onDemandLoad);
- subTree->addChild(directoryChild);
- }
- }
- else {
- QTreeWidgetItem *directoryChild = new QTreeWidgetItem(columns);
- directoryChild->setData(0, Qt::DecorationRole, *folderIcon);
- directoryChild->setData(0, Qt::UserRole + 3, isDirectory);
- subTree->addChild(directoryChild);
- }
- }
- }
-
-
- isDirectory = false;
- {
- for (const FileEntry::Ptr current : directoryEntry.getFiles()) {
- if (conflictsOnly && (current->getAlternatives().size() == 0)) {
- continue;
- }
-
- bool isArchive = false;
- int originID = current->getOrigin(isArchive);
- if (!m_showArchiveData && isArchive) {
- continue;
- }
-
- QString fileName = ToQString(current->getName());
- QStringList columns(fileName);
- FilesOrigin origin = m_OrganizerCore.directoryStructure()->getOriginByID(originID);
-
- QString source;
- const unsigned int modIndex = ModInfo::getIndex(ToQString(origin.getName()));
-
- if (modIndex == UINT_MAX) {
- source = UnmanagedModName();
- } else {
- ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex);
- source = modInfo->name();
- }
-
- std::pair<std::wstring, int> archive = current->getArchive();
- if (archive.first.length() != 0) {
- source.append(" (").append(ToQString(archive.first)).append(")");
- }
- columns.append(source);
- QTreeWidgetItem *fileChild = new QTreeWidgetItem(columns);
- if (isArchive) {
- QFont font = fileChild->font(0);
- font.setItalic(true);
- fileChild->setFont(0, font);
- fileChild->setFont(1, font);
- } else if (fileName.endsWith(ModInfo::s_HiddenExt, Qt::CaseInsensitive)) {
- QFont font = fileChild->font(0);
- font.setStrikeOut(true);
- fileChild->setFont(0, font);
- fileChild->setFont(1, font);
- }
- fileChild->setData(0, Qt::UserRole, ToQString(current->getFullPath()));
- fileChild->setData(0, Qt::DecorationRole, *fileIcon);
- fileChild->setData(0, Qt::UserRole + 3, isDirectory);
- fileChild->setData(0, Qt::UserRole + 1, isArchive);
- fileChild->setData(1, Qt::UserRole, source);
- fileChild->setData(1, Qt::UserRole + 1, originID);
-
- std::vector<std::pair<int, std::pair<std::wstring, int>>> alternatives = current->getAlternatives();
-
- if (!alternatives.empty()) {
- std::wostringstream altString;
- altString << ToWString(tr("Also in: <br>"));
- for (std::vector<std::pair<int, std::pair<std::wstring, int>>>::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->first).getName() << "</font></span>";
- }
- fileChild->setToolTip(1, QString("%1").arg(ToQString(altString.str())));
- fileChild->setForeground(1, QBrush(Qt::red));
- } else {
- fileChild->setToolTip(1, tr("No conflict"));
- }
- subTree->addChild(fileChild);
- }
- }
-
-
- //subTree->sortChildren(0, Qt::AscendingOrder);
-}
-
-void MainWindow::delayedRemove()
-{
- for (QTreeWidgetItem *item : m_RemoveWidget) {
- item->removeChild(item->child(0));
- }
- m_RemoveWidget.clear();
-}
-
-void MainWindow::expandDataTreeItem(QTreeWidgetItem *item)
-{
- if ((item->childCount() == 1) && (item->child(0)->data(0, Qt::UserRole).toString() == "__loaded_on_demand__")) {
- // read the data we need from the sub-item, then dispose of it
- QTreeWidgetItem *onDemandDataItem = item->child(0);
- const QString path = onDemandDataItem->data(0, Qt::UserRole + 1).toString();
- std::wstring wspath = path.toStdWString();
- bool conflictsOnly = onDemandDataItem->data(0, Qt::UserRole + 2).toBool();
-
- std::wstring virtualPath = (wspath + L"\\").substr(6) + ToWString(item->text(0));
- DirectoryEntry *dir = m_OrganizerCore.directoryStructure()->findSubDirectoryRecursive(virtualPath);
- if (dir != nullptr) {
- QIcon folderIcon = (new QFileIconProvider())->icon(QFileIconProvider::Folder);
- QIcon fileIcon = (new QFileIconProvider())->icon(QFileIconProvider::File);
- updateTo(item, wspath, *dir, conflictsOnly, &fileIcon, &folderIcon);
- } else {
- log::warn("failed to update view of {}", path);
- }
- m_RemoveWidget.push_back(item);
- QTimer::singleShot(5, this, SLOT(delayedRemove()));
- }
-}
-
bool MainWindow::refreshProfiles(bool selectProfile)
{
QComboBox* profileBox = findChild<QComboBox*>("profileBox");
@@ -1893,58 +1748,6 @@ void MainWindow::refreshExecutablesList()
ui->executablesListBox->setEnabled(true);
}
-
-void MainWindow::refreshDataTree()
-{
- QCheckBox *conflictsBox = findChild<QCheckBox*>("conflictsCheckBox");
- QTreeWidget *tree = findChild<QTreeWidget*>("dataTree");
- QIcon folderIcon = (new QFileIconProvider())->icon(QFileIconProvider::Folder);
- QIcon fileIcon = (new QFileIconProvider())->icon(QFileIconProvider::File);
- tree->clear();
- QStringList columns("data");
- columns.append("");
- QTreeWidgetItem *subTree = new QTreeWidgetItem(columns);
- subTree->setData(0, Qt::DecorationRole, (new QFileIconProvider())->icon(QFileIconProvider::Folder));
- updateTo(subTree, L"", *m_OrganizerCore.directoryStructure(), conflictsBox->isChecked(), &fileIcon, &folderIcon);
- tree->insertTopLevelItem(0, subTree);
- subTree->setExpanded(true);
-}
-
-void MainWindow::refreshDataTreeKeepExpandedNodes()
-{
- QCheckBox *conflictsBox = findChild<QCheckBox*>("conflictsCheckBox");
- QTreeWidget *tree = findChild<QTreeWidget*>("dataTree");
- QIcon folderIcon = (new QFileIconProvider())->icon(QFileIconProvider::Folder);
- QIcon fileIcon = (new QFileIconProvider())->icon(QFileIconProvider::File);
- QStringList expandedNodes;
- QTreeWidgetItemIterator it1(tree, QTreeWidgetItemIterator::NotHidden | QTreeWidgetItemIterator::HasChildren);
- while (*it1) {
- QTreeWidgetItem *current = (*it1);
- if (current->isExpanded() && !(current->text(0)=="data")) {
- expandedNodes.append(current->text(0)+"/"+current->parent()->text(0));
- }
- ++it1;
- }
-
- tree->clear();
- QStringList columns("data");
- columns.append("");
- QTreeWidgetItem *subTree = new QTreeWidgetItem(columns);
- subTree->setData(0, Qt::DecorationRole, (new QFileIconProvider())->icon(QFileIconProvider::Folder));
- updateTo(subTree, L"", *m_OrganizerCore.directoryStructure(), conflictsBox->isChecked(), &fileIcon, &folderIcon);
- tree->insertTopLevelItem(0, subTree);
- subTree->setExpanded(true);
- QTreeWidgetItemIterator it2(tree, QTreeWidgetItemIterator::HasChildren);
- while (*it2) {
- QTreeWidgetItem *current = (*it2);
- if (!(current->text(0)=="data") && expandedNodes.contains(current->text(0)+"/"+current->parent()->text(0))) {
- current->setExpanded(true);
- }
- ++it2;
- }
-}
-
-
void MainWindow::refreshSavesIfOpen()
{
if (ui->tabWidget->currentIndex() == 3) {
@@ -2317,7 +2120,6 @@ void MainWindow::storeSettings()
s.geometry().saveVisibility(ui->categoriesGroup);
s.geometry().saveState(ui->espList->header());
- s.geometry().saveState(ui->dataTree->header());
s.geometry().saveState(ui->downloadView->header());
s.geometry().saveState(ui->modList->header());
@@ -2325,6 +2127,7 @@ void MainWindow::storeSettings()
s.widgets().saveIndex(ui->executablesListBox);
m_Filters->saveState(s);
+ m_DataTab->saveState(s);
}
QWidget* MainWindow::qtWidget()
@@ -2332,11 +2135,6 @@ QWidget* MainWindow::qtWidget()
return this;
}
-void MainWindow::on_btnRefreshData_clicked()
-{
- m_OrganizerCore.refreshDirectoryStructure();
-}
-
void MainWindow::on_btnRefreshDownloads_clicked()
{
m_OrganizerCore.downloadManager()->refreshList();
@@ -2349,7 +2147,7 @@ void MainWindow::on_tabWidget_currentChanged(int index)
} else if (index == 1) {
m_OrganizerCore.refreshBSAList();
} else if (index == 2) {
- refreshDataTreeKeepExpandedNodes();
+ m_DataTab->activated();
} else if (index == 3) {
refreshSaveList();
}
@@ -2558,12 +2356,10 @@ void MainWindow::directory_refreshed()
// now
updateProblemsButton();
-
//Some better check for the current tab is needed.
if (ui->tabWidget->currentIndex() == 2) {
- refreshDataTreeKeepExpandedNodes();
+ m_DataTab->refreshDataTreeKeepExpandedNodes();
}
-
}
void MainWindow::esplist_changed()
@@ -5254,93 +5050,6 @@ void MainWindow::languageChange(const QString &newLanguage)
ui->openFolderMenu->setMenu(openFolderMenu());
}
-void MainWindow::writeDataToFile(QFile &file, const QString &directory, const DirectoryEntry &directoryEntry)
-{
- for (FileEntry::Ptr current : directoryEntry.getFiles()) {
- bool isArchive = false;
- int origin = current->getOrigin(isArchive);
- if (isArchive) {
- // TODO: don't list files from archives. maybe make this an option?
- continue;
- }
- QString fullName = directory + "\\" + ToQString(current->getName());
- file.write(fullName.toUtf8());
-
- file.write("\t(");
- file.write(ToQString(m_OrganizerCore.directoryStructure()->getOriginByID(origin).getName()).toUtf8());
- file.write(")\r\n");
- }
-
- // recurse into subdirectories
- std::vector<DirectoryEntry*>::const_iterator current, end;
- directoryEntry.getSubDirectories(current, end);
- for (; current != end; ++current) {
- writeDataToFile(file, directory + "\\" + ToQString((*current)->getName()), **current);
- }
-}
-
-void MainWindow::writeDataToFile()
-{
- QString fileName = QFileDialog::getSaveFileName(this);
- if (!fileName.isEmpty()) {
- QFile file(fileName);
- if (!file.open(QIODevice::WriteOnly)) {
- reportError(tr("failed to write to file %1").arg(fileName));
- }
-
- writeDataToFile(file, "data", *m_OrganizerCore.directoryStructure());
- file.close();
-
- MessageDialog::showMessage(tr("%1 written").arg(QDir::toNativeSeparators(fileName)), this);
- }
-}
-
-void MainWindow::addAsExecutable()
-{
- if (m_ContextItem == nullptr) {
- return;
- }
-
- const QFileInfo target(m_ContextItem->data(0, Qt::UserRole).toString());
- const auto fec = spawn::getFileExecutionContext(this, target);
-
- switch (fec.type)
- {
- case spawn::FileExecutionTypes::Executable:
- {
- const QString name = QInputDialog::getText(
- this, tr("Enter Name"),
- tr("Enter a name for the executable"),
- QLineEdit::Normal,
- target.completeBaseName());
-
- if (!name.isEmpty()) {
- //Note: If this already exists, you'll lose custom settings
- m_OrganizerCore.executablesList()->setExecutable(Executable()
- .title(name)
- .binaryInfo(fec.binary)
- .arguments(fec.arguments)
- .workingDirectory(target.absolutePath()));
-
- refreshExecutablesList();
- }
-
- break;
- }
-
- case spawn::FileExecutionTypes::Other: // fall-through
- default:
- {
- QMessageBox::information(
- this, tr("Not an executable"),
- tr("This is not a recognized executable."));
-
- break;
- }
- }
-}
-
-
void MainWindow::originModified(int originID)
{
FilesOrigin &origin = m_OrganizerCore.directoryStructure()->getOriginByID(originID);
@@ -5350,56 +5059,6 @@ void MainWindow::originModified(int originID)
}
-void MainWindow::hideFile()
-{
- QString oldName = m_ContextItem->data(0, Qt::UserRole).toString();
- QString newName = oldName + ModInfo::s_HiddenExt;
-
- if (QFileInfo(newName).exists()) {
- if (QMessageBox::question(this, tr("Replace file?"), tr("There already is a hidden version of this file. Replace it?"),
- QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
- if (!QFile(newName).remove()) {
- QMessageBox::critical(this, tr("File operation failed"), tr("Failed to remove \"%1\". Maybe you lack the required file permissions?").arg(newName));
- return;
- }
- } else {
- return;
- }
- }
-
- if (QFile::rename(oldName, newName)) {
- originModified(m_ContextItem->data(1, Qt::UserRole + 1).toInt());
- refreshDataTreeKeepExpandedNodes();
- } else {
- reportError(tr("failed to rename \"%1\" to \"%2\"").arg(oldName).arg(QDir::toNativeSeparators(newName)));
- }
-}
-
-
-void MainWindow::unhideFile()
-{
- QString oldName = m_ContextItem->data(0, Qt::UserRole).toString();
- QString newName = oldName.left(oldName.length() - ModInfo::s_HiddenExt.length());
- if (QFileInfo(newName).exists()) {
- if (QMessageBox::question(this, tr("Replace file?"), tr("There already is a visible version of this file. Replace it?"),
- QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
- if (!QFile(newName).remove()) {
- QMessageBox::critical(this, tr("File operation failed"), tr("Failed to remove \"%1\". Maybe you lack the required file permissions?").arg(newName));
- return;
- }
- } else {
- return;
- }
- }
- if (QFile::rename(oldName, newName)) {
- originModified(m_ContextItem->data(1, Qt::UserRole + 1).toInt());
- refreshDataTreeKeepExpandedNodes();
- } else {
- reportError(tr("failed to rename \"%1\" to \"%2\"").arg(QDir::toNativeSeparators(oldName)).arg(QDir::toNativeSeparators(newName)));
- }
-}
-
-
void MainWindow::enableSelectedPlugins_clicked()
{
m_OrganizerCore.pluginList()->enableSelected(ui->espList->selectionModel());
@@ -5450,149 +5109,6 @@ void MainWindow::disableSelectedMods_clicked()
}
}
-
-void MainWindow::activateDataTreeItem(QTreeWidgetItem *item, int column)
-{
- const auto isArchive = item->data(0, Qt::UserRole + 1).toBool();
- const auto isDirectory = item->data(0, Qt::UserRole + 3).toBool();
-
- if (isArchive || isDirectory) {
- return;
- }
-
- const QString path = item->data(0, Qt::UserRole).toString();
- if (path.isEmpty()) {
- return;
- }
-
- const QFileInfo targetInfo(path);
-
- const auto tryPreview = m_OrganizerCore.settings().interface().doubleClicksOpenPreviews();
-
- if (tryPreview && m_PluginContainer.previewGenerator().previewSupported(targetInfo.suffix())) {
- previewDataFile(item);
- } else {
- openDataFile(item);
- }
-}
-
-void MainWindow::openDataFile()
-{
- if (m_ContextItem == nullptr) {
- return;
- }
-
- openDataFile(m_ContextItem);
-}
-
-void MainWindow::openDataFile(QTreeWidgetItem* item)
-{
- const auto isArchive = item->data(0, Qt::UserRole + 1).toBool();
- const auto isDirectory = item->data(0, Qt::UserRole + 3).toBool();
-
- if (isArchive || isDirectory) {
- return;
- }
-
- const QString path = item->data(0, Qt::UserRole).toString();
- const QFileInfo targetInfo(path);
-
- m_OrganizerCore.processRunner()
- .setFromFile(this, targetInfo)
- .setHooked(false)
- .setWaitForCompletion(ProcessRunner::Refresh)
- .run();
-}
-
-void MainWindow::runDataFileHooked()
-{
- if (m_ContextItem == nullptr) {
- return;
- }
-
- runDataFileHooked(m_ContextItem);
-}
-
-void MainWindow::runDataFileHooked(QTreeWidgetItem* item)
-{
- const auto isArchive = item->data(0, Qt::UserRole + 1).toBool();
- const auto isDirectory = item->data(0, Qt::UserRole + 3).toBool();
-
- if (isArchive || isDirectory) {
- return;
- }
-
- const QString path = item->data(0, Qt::UserRole).toString();
- const QFileInfo targetInfo(path);
-
- m_OrganizerCore.processRunner()
- .setFromFile(this, targetInfo)
- .setHooked(true)
- .setWaitForCompletion(ProcessRunner::Refresh)
- .run();
-}
-
-void MainWindow::previewDataFile()
-{
- if (m_ContextItem == nullptr) {
- return;
- }
-
- previewDataFile(m_ContextItem);
-}
-
-void MainWindow::previewDataFile(QTreeWidgetItem* item)
-{
- QString fileName = QDir::fromNativeSeparators(item->data(0, Qt::UserRole).toString());
- m_OrganizerCore.previewFileWithAlternatives(this, fileName);
-}
-
-void MainWindow::openDataOriginExplorer_clicked()
-{
- if (m_ContextItem == nullptr) {
- return;
- }
-
- const auto isArchive = m_ContextItem->data(0, Qt::UserRole + 1).toBool();
- const auto isDirectory = m_ContextItem->data(0, Qt::UserRole + 3).toBool();
-
- if (isArchive || isDirectory) {
- return;
- }
-
- const auto fullPath = m_ContextItem->data(0, Qt::UserRole).toString();
-
- log::debug("opening in explorer: {}", fullPath);
- shell::Explore(fullPath);
-}
-
-void MainWindow::openDataModInfo_clicked()
-{
- if (m_ContextItem == nullptr) {
- return;
- }
-
- const auto originID = m_ContextItem->data(1, Qt::UserRole + 1).toInt();
- if (originID == 0) {
- // unmanaged
- return;
- }
-
- const auto& origin = m_OrganizerCore.directoryStructure()->getOriginByID(originID);
- const auto& name = QString::fromStdWString(origin.getName());
-
- unsigned int index = ModInfo::getIndex(name);
- if (index == UINT_MAX) {
- log::error("can't open mod info, mod '{}' not found", name);
- return;
- }
-
- ModInfo::Ptr modInfo = ModInfo::getByIndex(index);
- if (modInfo) {
- displayModInformation(modInfo, index, ModInfoTabIDs::None);
- }
-}
-
void MainWindow::updateAvailable()
{
ui->actionUpdate->setEnabled(true);
@@ -5615,106 +5131,6 @@ void MainWindow::motdReceived(const QString &motd)
}
}
-void MainWindow::on_dataTree_customContextMenuRequested(const QPoint &pos)
-{
- m_ContextItem = ui->dataTree->itemAt(pos.x(), pos.y());
-
- QMenu menu;
- if ((m_ContextItem != nullptr) && (m_ContextItem->childCount() == 0)
- && (m_ContextItem->data(0, Qt::UserRole + 3).toBool() != true)) {
- QString fileName = m_ContextItem->text(0);
- const auto isArchive = m_ContextItem->data(0, Qt::UserRole + 1).toBool();
- const auto isDirectory = m_ContextItem->data(0, Qt::UserRole + 3).toBool();
-
- QAction* open = nullptr;
- QAction* runHooked = nullptr;
- QAction* preview = nullptr;
-
- if (canRunFile(isArchive, fileName)) {
- open = new QAction(tr("&Execute"), ui->dataTree);
- runHooked = new QAction(tr("Execute with &VFS"), ui->dataTree);
- } else if (canOpenFile(isArchive, fileName)) {
- open = new QAction(tr("&Open"), ui->dataTree);
- runHooked = new QAction(tr("Open with &VFS"), ui->dataTree);
- }
-
- if (m_PluginContainer.previewGenerator().previewSupported(QFileInfo(fileName).suffix())) {
- preview = new QAction(tr("Preview"), ui->dataTree);
- }
-
- if (open) {
- connect(open, &QAction::triggered, [&]{ openDataFile(); });
- }
-
- if (runHooked) {
- connect(runHooked, &QAction::triggered, [&]{ runDataFileHooked(); });
- }
-
- if (preview) {
- connect(preview, &QAction::triggered, [&]{ previewDataFile(); });
- }
-
- if (open && preview) {
- if (m_OrganizerCore.settings().interface().doubleClicksOpenPreviews()) {
- menu.addAction(preview);
- menu.addAction(open);
- } else {
- menu.addAction(open);
- menu.addAction(preview);
- }
- } else {
- if (open) {
- menu.addAction(open);
- }
-
- if (preview) {
- menu.addAction(preview);
- }
- }
-
- if (runHooked) {
- menu.addAction(runHooked);
- }
-
- menu.addAction(tr("&Add as Executable"), this, SLOT(addAsExecutable()));
-
- if (!isArchive && !isDirectory) {
- menu.addAction("Open Origin in Explorer", this, SLOT(openDataOriginExplorer_clicked()));
- }
-
- menu.addAction("Open Mod Info", this, SLOT(openDataModInfo_clicked()));
-
- menu.addSeparator();
-
- // offer to hide/unhide file, but not for files from archives
- if (!isArchive) {
- if (m_ContextItem->text(0).endsWith(ModInfo::s_HiddenExt, Qt::CaseInsensitive)) {
- menu.addAction(tr("Un-Hide"), this, SLOT(unhideFile()));
- } else {
- menu.addAction(tr("Hide"), this, SLOT(hideFile()));
- }
- }
-
- if (open || preview || runHooked) {
- // bold the first option
- auto* top = menu.actions()[0];
- auto f = top->font();
- f.setBold(true);
- top->setFont(f);
- }
- }
-
- menu.addAction(tr("Write To File..."), this, SLOT(writeDataToFile()));
- menu.addAction(tr("Refresh"), this, SLOT(on_btnRefreshData_clicked()));
-
- menu.exec(ui->dataTree->viewport()->mapToGlobal(pos));
-}
-
-void MainWindow::on_conflictsCheckBox_toggled(bool)
-{
- refreshDataTreeKeepExpandedNodes();
-}
-
void MainWindow::on_actionUpdate_triggered()
{
m_OrganizerCore.startMOUpdate();
@@ -6970,17 +6386,3 @@ void MainWindow::sendSelectedModsToSeparator_clicked()
}
}
}
-
-void MainWindow::on_showArchiveDataCheckBox_toggled(const bool checked)
-{
- if (m_OrganizerCore.getArchiveParsing() && checked)
- {
- m_showArchiveData = checked;
- }
- else
- {
- m_showArchiveData = false;
- }
- refreshDataTree();
-}
-
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 2c45049a..d50705e3 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -34,12 +34,11 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "iplugingame.h" //namespace MOBase { class IPluginGame; }
#include <log.h>
-//Note the commented headers here can be replaced with forward references,
-//when I get round to cleaning up main.cpp
class Executable;
class CategoryFactory;
class OrganizerCore;
class FilterList;
+class DataTab;
class PluginListSortProxy;
namespace BSA { class Archive; }
@@ -122,8 +121,6 @@ public:
bool addProfile();
void updateBSAList(const QStringList &defaultArchives, const QStringList &activeArchives);
- void refreshDataTree();
- void refreshDataTreeKeepExpandedNodes();
void refreshSaveList();
void setModListSorting(int index);
@@ -137,10 +134,6 @@ public:
void addPrimaryCategoryCandidates(QMenu *primaryCategoryMenu, ModInfo::Ptr info);
- void updateModInDirectoryStructure(unsigned int index, ModInfo::Ptr modInfo);
-
- QString getOriginDisplayName(int originID);
-
void installTranslator(const QString &name);
virtual void disconnectPlugins();
@@ -219,20 +212,12 @@ private:
QMenu* createPopupMenu() override;
void activateSelectedProfile();
- void startSteam();
-
- void updateTo(QTreeWidgetItem *subTree, const std::wstring &directorySoFar, const MOShared::DirectoryEntry &directoryEntry, bool conflictsOnly, QIcon *fileIcon, QIcon *folderIcon);
bool refreshProfiles(bool selectProfile = true);
void refreshExecutablesList();
void installMod(QString fileName = "");
- QList<MOBase::IOrganizer::FileInfo> findFileInfos(const QString &path, const std::function<bool (const MOBase::IOrganizer::FileInfo &)> &filter) const;
-
bool modifyExecutablesDialog(int selection);
void displayModInformation(int row, ModInfoTabIDs tab=ModInfoTabIDs::None);
- void testExtractBSA(int modIndex);
-
- void writeDataToFile(QFile &file, const QString &directory, const MOShared::DirectoryEntry &directoryEntry);
/**
* Sets category selections from menu; for multiple mods, this will only apply
@@ -267,8 +252,6 @@ private:
void displaySaveGameInfo(QListWidgetItem *newItem);
- HANDLE nextChildProcess();
-
bool errorReported(QString &logFile);
void updateESPLock(bool locked);
@@ -285,8 +268,6 @@ private:
QMenu *openFolderMenu();
- std::set<QString> enabledArchives();
-
void scheduleUpdateButton();
QDir currentSavesDir() const;
@@ -297,7 +278,6 @@ private:
void dropLocalFile(const QUrl &url, const QString &outputDir, bool move);
void sendSelectedModsToPriority(int newPriority);
- void sendSelectedPluginsToPriority(int newPriority);
void toggleMO2EndorseState();
void toggleUpdateAction();
@@ -322,6 +302,7 @@ private:
MOBase::TutorialControl m_Tutorial;
std::unique_ptr<FilterList> m_Filters;
+ std::unique_ptr<DataTab> m_DataTab;
int m_OldProfileIndex;
@@ -364,8 +345,6 @@ private:
QFileSystemWatcher m_SavesWatcher;
- std::vector<QTreeWidgetItem*> m_RemoveWidget;
-
QByteArray m_ArchiveListHash;
bool m_DidUpdateMasterList;
@@ -438,18 +417,6 @@ private slots:
void deleteSavegame_clicked();
void fixMods_clicked(SaveGameInfo::MissingAssets const &missingAssets);
// data-tree context menu
- void writeDataToFile();
- void openDataFile();
- void openDataFile(QTreeWidgetItem* item);
- void runDataFileHooked();
- void runDataFileHooked(QTreeWidgetItem* item);
- void addAsExecutable();
- void previewDataFile();
- void previewDataFile(QTreeWidgetItem* item);
- void hideFile();
- void unhideFile();
- void openDataOriginExplorer_clicked();
- void openDataModInfo_clicked();
// pluginlist context menu
void enableSelectedPlugins_clicked();
@@ -592,10 +559,7 @@ private slots:
void unignoreUpdate();
void refreshSavesIfOpen();
- void expandDataTreeItem(QTreeWidgetItem *item);
- void activateDataTreeItem(QTreeWidgetItem *item, int column);
void about();
- void delayedRemove();
void modListSortIndicatorChanged(int column, Qt::SortOrder order);
void modListSectionResized(int logicalIndex, int oldSize, int newSize);
@@ -634,11 +598,7 @@ private slots: // ui slots
void on_centralWidget_customContextMenuRequested(const QPoint &pos);
void on_bsaList_customContextMenuRequested(const QPoint &pos);
void on_clearFiltersButton_clicked();
- void on_btnRefreshData_clicked();
void on_btnRefreshDownloads_clicked();
- void on_conflictsCheckBox_toggled(bool checked);
- void on_showArchiveDataCheckBox_toggled(bool checked);
- void on_dataTree_customContextMenuRequested(const QPoint &pos);
void on_executablesListBox_currentIndexChanged(int index);
void on_modList_customContextMenuRequested(const QPoint &pos);
void on_modList_doubleClicked(const QModelIndex &index);
diff --git a/src/modinfodialogfwd.h b/src/modinfodialogfwd.h
index 5d949ce9..1086e740 100644
--- a/src/modinfodialogfwd.h
+++ b/src/modinfodialogfwd.h
@@ -2,6 +2,7 @@
#define MODINFODIALOGFWD_H
#include "filerenamer.h"
+#include <QStyledItemDelegate>
class ModInfo;
using ModInfoPtr = QSharedPointer<ModInfo>;