diff options
Diffstat (limited to 'src/mainwindow.cpp')
| -rw-r--r-- | src/mainwindow.cpp | 841 |
1 files changed, 165 insertions, 676 deletions
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index d6ccc905..de1be9fe 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> @@ -86,6 +87,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "localsavegames.h" #include "listdialog.h" #include "envshortcut.h" +#include "browserdialog.h" #include <QAbstractItemDelegate> #include <QAbstractProxyModel> @@ -299,7 +301,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 +363,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))); @@ -396,8 +407,6 @@ MainWindow::MainWindow(Settings &settings connect(&m_OrganizerCore, &OrganizerCore::modInstalled, this, &MainWindow::modInstalled); connect(&m_OrganizerCore, &OrganizerCore::close, this, &QMainWindow::close); - connect(&m_IntegratedBrowser, SIGNAL(requestDownload(QUrl,QNetworkReply*)), &m_OrganizerCore, SLOT(requestDownload(QUrl,QNetworkReply*))); - m_CheckBSATimer.setSingleShot(true); connect(&m_CheckBSATimer, SIGNAL(timeout()), this, SLOT(checkBSAList())); @@ -445,17 +454,17 @@ MainWindow::MainWindow(Settings &settings if (m_OrganizerCore.getArchiveParsing()) { - ui->showArchiveDataCheckBox->setCheckState(Qt::Checked); - ui->showArchiveDataCheckBox->setEnabled(true); - m_showArchiveData = true; + ui->dataTabShowFromArchives->setCheckState(Qt::Checked); + ui->dataTabShowFromArchives->setEnabled(true); } else { - ui->showArchiveDataCheckBox->setCheckState(Qt::Unchecked); - ui->showArchiveDataCheckBox->setEnabled(false); - m_showArchiveData = false; + ui->dataTabShowFromArchives->setCheckState(Qt::Unchecked); + ui->dataTabShowFromArchives->setEnabled(false); } + QApplication::instance()->installEventFilter(this); + refreshExecutablesList(); updatePinnedExecutables(); resetActionIcons(); @@ -622,7 +631,12 @@ MainWindow::~MainWindow() m_PluginContainer.setUserInterface(nullptr, nullptr); m_OrganizerCore.setUserInterface(nullptr); - m_IntegratedBrowser.close(); + + if (m_IntegratedBrowser) { + m_IntegratedBrowser->close(); + m_IntegratedBrowser.reset(); + } + delete ui; } catch (std::exception &e) { QMessageBox::critical(nullptr, tr("Crash on exit"), @@ -1181,7 +1195,7 @@ void MainWindow::downloadFilterChanged(const QString &filter) void MainWindow::expandModList(const QModelIndex &index) { QAbstractItemModel *model = ui->modList->model(); -#pragma message("why is this so complicated? mapping the index doesn't work, probably a bug in QtGroupingProxy?") + for (int i = 0; i < model->rowCount(); ++i) { QModelIndex targetIdx = model->index(i, 0); if (model->data(targetIdx).toString() == index.data().toString()) { @@ -1383,7 +1397,12 @@ bool MainWindow::canExit() void MainWindow::cleanup() { QWebEngineProfile::defaultProfile()->clearAllVisitedLinks(); - m_IntegratedBrowser.close(); + + if (m_IntegratedBrowser) { + m_IntegratedBrowser->close(); + m_IntegratedBrowser = {}; + } + m_SaveMetaTimer.stop(); m_MetaSave.waitForFinished(); } @@ -1461,7 +1480,11 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) if ((object == ui->savegameList) && ((event->type() == QEvent::Leave) || (event->type() == QEvent::WindowDeactivate))) { hideSaveGameInfo(); + } else if (event->type() == QEvent::StatusTip && object != this) { + QMainWindow::event(event); + return true; } + return false; } @@ -1487,8 +1510,17 @@ void MainWindow::modPagePluginInvoke() IPluginModPage *plugin = qobject_cast<IPluginModPage*>(triggeredAction->data().value<QObject*>()); if (plugin != nullptr) { if (plugin->useIntegratedBrowser()) { - m_IntegratedBrowser.setWindowTitle(plugin->displayName()); - m_IntegratedBrowser.openUrl(plugin->pageURL()); + + if (!m_IntegratedBrowser) { + m_IntegratedBrowser.reset(new BrowserDialog); + + connect( + m_IntegratedBrowser.get(), SIGNAL(requestDownload(QUrl,QNetworkReply*)), + &m_OrganizerCore, SLOT(requestDownload(QUrl,QNetworkReply*))); + } + + m_IntegratedBrowser->setWindowTitle(plugin->displayName()); + m_IntegratedBrowser->openUrl(plugin->pageURL()); } else { QDesktopServices::openUrl(QUrl(plugin->pageURL())); } @@ -1657,161 +1689,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 +1770,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 +2142,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 +2149,7 @@ void MainWindow::storeSettings() s.widgets().saveIndex(ui->executablesListBox); m_Filters->saveState(s); + m_DataTab->saveState(s); } QWidget* MainWindow::qtWidget() @@ -2332,11 +2157,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 +2169,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 +2378,10 @@ void MainWindow::directory_refreshed() // now updateProblemsButton(); - //Some better check for the current tab is needed. if (ui->tabWidget->currentIndex() == 2) { - refreshDataTreeKeepExpandedNodes(); + m_DataTab->updateTree(); } - } void MainWindow::esplist_changed() @@ -3368,6 +3186,57 @@ void MainWindow::visitWebPage_clicked() } } +void MainWindow::visitNexusOrWebPage_clicked() { + QItemSelectionModel* selection = ui->modList->selectionModel(); + if (selection->hasSelection() && selection->selectedRows().count() > 1) { + int count = selection->selectedRows().count(); + if (count > 10) { + if (QMessageBox::question(this, tr("Opening Web Pages"), + tr("You are trying to open %1 Web Pages. Are you sure you want to do this?").arg(count), + QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { + return; + } + } + int row_idx; + ModInfo::Ptr info; + QString gameName; + + for (QModelIndex idx : selection->selectedRows()) { + row_idx = idx.data(Qt::UserRole + 1).toInt(); + info = ModInfo::getByIndex(row_idx); + int modID = info->getNexusID(); + gameName = info->getGameName(); + const auto url = info->parseCustomURL(); + if (modID > 0) { + linkClicked(NexusInterface::instance(&m_PluginContainer)->getModURL(modID, gameName)); + } + else if (url.isValid()) { + linkClicked(url.toString()); + } + else { + log::error("mod '{}' has no valid link", info->name()); + } + } + } + else { + int modID = m_OrganizerCore.modList()->data(m_OrganizerCore.modList()->index(m_ContextRow, 0), Qt::UserRole).toInt(); + QString gameName = m_OrganizerCore.modList()->data(m_OrganizerCore.modList()->index(m_ContextRow, 0), Qt::UserRole + 4).toString(); + if (modID > 0) { + linkClicked(NexusInterface::instance(&m_PluginContainer)->getModURL(modID, gameName)); + } + else { + ModInfo::Ptr info = ModInfo::getByIndex(m_ContextRow); + const auto url = info->parseCustomURL(); + if (url.isValid()) { + linkClicked(url.toString()); + } + else { + MessageDialog::showMessage(tr("No valid Web Page for this mod"), this); + } + } + } +} + void MainWindow::openExplorer_clicked() { QItemSelectionModel *selection = ui->modList->selectionModel(); @@ -3926,7 +3795,17 @@ void MainWindow::on_modList_doubleClicked(const QModelIndex &index) reportError(e.what()); } } - else { + else if (modifiers.testFlag(Qt::ShiftModifier)) { + try { + m_ContextRow = m_ModListSortProxy->mapToSource(index).row(); + visitNexusOrWebPage_clicked(); + ui->modList->closePersistentEditor(index); + } + catch (const std::exception & e) { + reportError(e.what()); + } + } + else{ try { m_ContextRow = m_ModListSortProxy->mapToSource(index).row(); sourceIdx.column(); @@ -5147,15 +5026,13 @@ void MainWindow::on_actionSettings_triggered() m_OrganizerCore.setArchiveParsing(state); if (!state) { - ui->showArchiveDataCheckBox->setCheckState(Qt::Unchecked); - ui->showArchiveDataCheckBox->setEnabled(false); - m_showArchiveData = false; + ui->dataTabShowFromArchives->setCheckState(Qt::Unchecked); + ui->dataTabShowFromArchives->setEnabled(false); } else { - ui->showArchiveDataCheckBox->setCheckState(Qt::Checked); - ui->showArchiveDataCheckBox->setEnabled(true); - m_showArchiveData = true; + ui->dataTabShowFromArchives->setCheckState(Qt::Checked); + ui->dataTabShowFromArchives->setEnabled(true); } m_OrganizerCore.refreshModList(); m_OrganizerCore.refreshDirectoryStructure(); @@ -5254,93 +5131,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 +5140,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 +5190,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 +5212,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(); @@ -5990,50 +5487,52 @@ void MainWindow::nxmUpdatesAvailable(QString gameName, int modID, QVariant userD bool foundUpdate = false; bool oldFile = false; QString installedFile = mod->getInstallationFile(); - QVariantMap foundFile; - for (auto file : files) { - QVariantMap fileData = file.toMap(); - if (fileData["file_name"].toString().compare(installedFile, Qt::CaseInsensitive) == 0) { - foundFile = fileData; - mod->setNexusFileStatus(foundFile["category_id"].toInt()); - if (mod->getNexusFileStatus() == 4 || mod->getNexusFileStatus() == 6) - oldFile = true; + if (!installedFile.isEmpty()) { + QVariantMap foundFile; + for (auto file : files) { + QVariantMap fileData = file.toMap(); + if (fileData["file_name"].toString().compare(installedFile, Qt::CaseInsensitive) == 0) { + foundFile = fileData; + mod->setNexusFileStatus(foundFile["category_id"].toInt()); + if (mod->getNexusFileStatus() == 4 || mod->getNexusFileStatus() == 6) + oldFile = true; + } } - } - for (auto update : fileUpdates) { - QVariantMap updateData = update.toMap(); - // Locate the current install file as an update - if (installedFile == updateData["old_file_name"].toString()) { - int currentUpdate = updateData["new_file_id"].toInt(); - bool finalUpdate = false; - // Crawl the updates to make sure we have the latest file version - while (!finalUpdate) { - finalUpdate = true; - for (auto updateScan : fileUpdates) { - QVariantMap updateScanData = updateScan.toMap(); - if (currentUpdate == updateScanData["old_file_id"].toInt()) { - currentUpdate = updateScanData["new_file_id"].toInt(); - finalUpdate = false; - // Apply the version data from the latest file - for (auto file : files) { - QVariantMap fileData = file.toMap(); - if (fileData["file_id"].toInt() == currentUpdate) { - if (fileData["category_id"].toInt() != 6) { - mod->setNewestVersion(fileData["version"].toString()); - foundUpdate = true; + for (auto update : fileUpdates) { + QVariantMap updateData = update.toMap(); + // Locate the current install file as an update + if (installedFile == updateData["old_file_name"].toString()) { + int currentUpdate = updateData["new_file_id"].toInt(); + bool finalUpdate = false; + // Crawl the updates to make sure we have the latest file version + while (!finalUpdate) { + finalUpdate = true; + for (auto updateScan : fileUpdates) { + QVariantMap updateScanData = updateScan.toMap(); + if (currentUpdate == updateScanData["old_file_id"].toInt()) { + currentUpdate = updateScanData["new_file_id"].toInt(); + finalUpdate = false; + // Apply the version data from the latest file + for (auto file : files) { + QVariantMap fileData = file.toMap(); + if (fileData["file_id"].toInt() == currentUpdate) { + if (fileData["category_id"].toInt() != 6) { + mod->setNewestVersion(fileData["version"].toString()); + foundUpdate = true; + } } } + break; } - break; } } - } - break; - } else if (installedFile == updateData["new_file_name"].toString()) { - // This is a safety mechanism if this is the latest update file so we don't use the mod version - if (!foundUpdate && !oldFile) { - foundUpdate = true; - mod->setNewestVersion(foundFile["version"].toString()); + break; + } else if (installedFile == updateData["new_file_name"].toString()) { + // This is a safety mechanism if this is the latest update file so we don't use the mod version + if (!foundUpdate && !oldFile) { + foundUpdate = true; + mod->setNewestVersion(foundFile["version"].toString()); + } } } } @@ -6069,9 +5568,13 @@ void MainWindow::nxmModInfoAvailable(QString gameName, int modID, QVariant userD QDateTime now = QDateTime::currentDateTimeUtc(); QDateTime updateTarget = mod->getExpires(); if (now >= updateTarget) { - mod->setNewestVersion(result["version"].toString()); - mod->setLastNexusUpdate(QDateTime::currentDateTimeUtc()); - foundUpdate = true; + // if file is still listed as optional or miscellaneous don't update the version as often optional files are left + // with an older version than the main mod version. + if (mod->getNexusFileStatus() != 3 && mod->getNexusFileStatus() != 5) { + mod->setNewestVersion(result["version"].toString()); + mod->setLastNexusUpdate(QDateTime::currentDateTimeUtc()); + foundUpdate = true; + } } mod->setNexusDescription(result["description"].toString()); if ((mod->endorsedState() != ModInfo::ENDORSED_NEVER) && (result.contains("endorsement"))) { @@ -6970,17 +6473,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(); -} - |
