diff options
| author | isanae <14251494+isanae@users.noreply.github.com> | 2019-12-10 10:48:09 -0500 |
|---|---|---|
| committer | isanae <14251494+isanae@users.noreply.github.com> | 2020-02-04 03:33:16 -0500 |
| commit | 7e748d15c9d4fdf42b753f58e033899c5753b899 (patch) | |
| tree | 1dd850ea652acf4cbcc8d43a8dc8d50dbc0bee72 /src | |
| parent | e9da5b4fad488a5e1ff61d68cc6a24b68f0d4440 (diff) | |
split data tab
removed a bunch of undefined functions in MainWindow
Diffstat (limited to 'src')
| -rw-r--r-- | src/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | src/datatab.cpp | 668 | ||||
| -rw-r--r-- | src/datatab.h | 83 | ||||
| -rw-r--r-- | src/mainwindow.cpp | 632 | ||||
| -rw-r--r-- | src/mainwindow.h | 44 | ||||
| -rw-r--r-- | src/modinfodialogfwd.h | 1 |
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>; |
