mirror of
https://github.com/ModOrganizer2/modorganizer.git
synced 2026-07-27 13:58:24 -07:00
Compare commits
17
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db0347212a | ||
|
|
5895a1a92d | ||
|
|
c6101e34e1 | ||
|
|
75475a7984 | ||
|
|
315ed6e41a | ||
|
|
b2d613e9d1 | ||
|
|
f010c22a3b | ||
|
|
d1594798e6 | ||
|
|
09bd3dbead | ||
|
|
8c0b309bde | ||
|
|
bc7c42dbe8 | ||
|
|
9a03783f49 | ||
|
|
d73b1e38c8 | ||
|
|
b47c89661e | ||
|
|
0b84cc3d45 | ||
|
|
1bf3cc585e | ||
|
|
eae275cc84 |
+11
-11
@@ -1,23 +1,23 @@
|
||||
TEMPLATE = subdirs
|
||||
CONFIG += ordered
|
||||
|
||||
|
||||
SUBDIRS = bsatk \
|
||||
shared \
|
||||
uibase \
|
||||
organizer \
|
||||
hookdll \
|
||||
archive \
|
||||
helper \
|
||||
shared \
|
||||
uibase \
|
||||
organizer \
|
||||
hookdll \
|
||||
archive \
|
||||
helper \
|
||||
plugins \
|
||||
proxydll \
|
||||
nxmhandler \
|
||||
BossDummy \
|
||||
pythonRunner \
|
||||
esptk
|
||||
BossDummy \
|
||||
pythonRunner \
|
||||
esptk
|
||||
|
||||
plugins.depends = pythonRunner
|
||||
hookdll.depends = shared
|
||||
organizer.depends = shared, uibase, plugins
|
||||
organizer.depends = shared uibase plugins
|
||||
|
||||
CONFIG(debug, debug|release) {
|
||||
DESTDIR = outputd
|
||||
|
||||
@@ -75,12 +75,14 @@ QVariant DownloadList::data(const QModelIndex &index, int role) const
|
||||
if (role == Qt::DisplayRole) {
|
||||
return index.row();
|
||||
} else if (role == Qt::ToolTipRole) {
|
||||
QString text = m_Manager->getFileName(index.row()) + "\n";
|
||||
if (m_Manager->isInfoIncomplete(index.row())) {
|
||||
return tr("Information missing, please select \"Query Info\" from the context menu to re-retrieve.");
|
||||
text += tr("Information missing, please select \"Query Info\" from the context menu to re-retrieve.");
|
||||
} else {
|
||||
NexusInfo info = m_Manager->getNexusInfo(index.row());
|
||||
return QString("%1 (ID %2) %3").arg(info.m_ModName).arg(m_Manager->getModID(index.row())).arg(info.m_Version);
|
||||
text += QString("%1 (ID %2) %3").arg(info.m_ModName).arg(m_Manager->getModID(index.row())).arg(info.m_Version);
|
||||
}
|
||||
return text;
|
||||
} else {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>315</width>
|
||||
<height>75</height>
|
||||
<height>81</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="contextMenuPolicy">
|
||||
@@ -78,14 +78,14 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="sizeLabel">
|
||||
<property name="text">
|
||||
<string>0</string>
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>KB</string>
|
||||
<string notr="true">KB</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -506,7 +506,6 @@ bool InstallationManager::ensureValidModName(GuessedValue<QString> &name) const
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool InstallationManager::doInstall(GuessedValue<QString> &modName, int modID,
|
||||
const QString &version, const QString &newestVersion, int categoryID)
|
||||
{
|
||||
@@ -528,7 +527,6 @@ bool InstallationManager::doInstall(GuessedValue<QString> &modName, int modID,
|
||||
m_InstallationProgress.setValue(0);
|
||||
m_InstallationProgress.setWindowModality(Qt::WindowModal);
|
||||
m_InstallationProgress.show();
|
||||
|
||||
if (!m_CurrentArchive->extract(ToWString(QDir::toNativeSeparators(targetDirectory)).c_str(),
|
||||
new MethodCallback<InstallationManager, void, float>(this, &InstallationManager::updateProgress),
|
||||
new MethodCallback<InstallationManager, void, LPCWSTR>(this, &InstallationManager::updateProgressFile),
|
||||
@@ -649,7 +647,7 @@ bool InstallationManager::install(const QString &fileName, GuessedValue<QString>
|
||||
}
|
||||
|
||||
m_CurrentFile = fileInfo.absoluteFilePath();
|
||||
if (fileInfo.dir() == QDir(ToQString(GameInfo::instance().getDownloadDir()))) {
|
||||
if (fileInfo.dir() == QDir(m_DownloadsDirectory)) {
|
||||
m_CurrentFile = fileInfo.fileName();
|
||||
}
|
||||
qDebug("using mod name \"%s\" (id %d) -> %s", modName->toUtf8().constData(), modID, qPrintable(m_CurrentFile));
|
||||
|
||||
@@ -64,6 +64,12 @@ public:
|
||||
*/
|
||||
void setModsDirectory(const QString &modsDirectory) { m_ModsDirectory = modsDirectory; }
|
||||
|
||||
/**
|
||||
* @brief update the directory where downloads are stored
|
||||
* @param downloadDirectory the download directory
|
||||
*/
|
||||
void setDownloadDirectory(const QString &downloadDirectory) { m_DownloadsDirectory = downloadDirectory; }
|
||||
|
||||
/**
|
||||
* @brief install a mod from an archive
|
||||
*
|
||||
@@ -191,6 +197,7 @@ private:
|
||||
QWidget *m_ParentWidget;
|
||||
|
||||
QString m_ModsDirectory;
|
||||
QString m_DownloadsDirectory;
|
||||
|
||||
std::vector<MOBase::IPluginInstaller*> m_Installers;
|
||||
std::set<QString, CaseInsensitive> m_SupportedExtensions;
|
||||
|
||||
+23
-2
@@ -60,7 +60,6 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "selectiondialog.h"
|
||||
#include "moapplication.h"
|
||||
#include "tutorialmanager.h"
|
||||
#include <QLibrary>
|
||||
#include <iostream>
|
||||
#include <QMessageBox>
|
||||
#include <QSharedMemory>
|
||||
@@ -140,7 +139,7 @@ bool bootstrap()
|
||||
QObject::tr("The current user account doesn't have the required access rights to run "
|
||||
"Mod Organizer. The neccessary changes can be made automatically (the MO directory "
|
||||
"will be made writable for the current user account). You will be asked to run "
|
||||
"\"helper.exe\" with administrative rights)."),
|
||||
"\"helper.exe\" with administrative rights."),
|
||||
QMessageBox::Yes | QMessageBox::Cancel) == QMessageBox::Yes) {
|
||||
if (!Helper::init(GameInfo::instance().getOrganizerDirectory())) {
|
||||
return false;
|
||||
@@ -156,6 +155,7 @@ bool bootstrap()
|
||||
|
||||
// verify the hook-dll exists
|
||||
QString dllName = qApp->applicationDirPath() + "/" + ToQString(AppConfig::hookDLLName());
|
||||
|
||||
HMODULE dllMod = ::LoadLibraryW(ToWString(dllName).c_str());
|
||||
if (dllMod == NULL) {
|
||||
throw windows_error("hook.dll is missing or invalid");
|
||||
@@ -400,6 +400,27 @@ int main(int argc, char *argv[])
|
||||
settings.setValue("gamePath", gamePath.toUtf8().constData());
|
||||
}
|
||||
|
||||
int edition = 0;
|
||||
if (settings.contains("game_edition")) {
|
||||
edition = settings.value("game_edition").toInt();
|
||||
} else {
|
||||
std::vector<std::wstring> editions = GameInfo::instance().getSteamVariants();
|
||||
if (editions.size() < 2) {
|
||||
edition = 0;
|
||||
} else {
|
||||
SelectionDialog selection(QObject::tr("Please select the game edition you have (MO can't start the game correctly if this is set incorrectly!)"), NULL);
|
||||
int index = 0;
|
||||
for (auto iter = editions.begin(); iter != editions.end(); ++iter) {
|
||||
selection.addChoice(ToQString(*iter), "", index++);
|
||||
}
|
||||
if (selection.exec() == QDialog::Rejected) {
|
||||
return -1;
|
||||
} else {
|
||||
settings.setValue("game_edition", selection.getChoiceData().toInt());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qDebug("managing game at %s", qPrintable(QDir::toNativeSeparators(gamePath)));
|
||||
|
||||
ExecutablesList executablesList;
|
||||
|
||||
+100
-17
@@ -59,14 +59,15 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include <appconfig.h>
|
||||
#include <utility.h>
|
||||
#include <ipluginproxy.h>
|
||||
#include <questionboxmemory.h>
|
||||
#include <map>
|
||||
#include <ctime>
|
||||
#include <QTime>
|
||||
#include <util.h>
|
||||
#include <wchar.h>
|
||||
#include <QTime>
|
||||
#include <QInputDialog>
|
||||
#include <QSettings>
|
||||
#include <QWhatsThis>
|
||||
#include <wchar.h>
|
||||
#include <sstream>
|
||||
#include <QProcess>
|
||||
#include <QMenu>
|
||||
@@ -162,6 +163,8 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget
|
||||
|
||||
ui->actionEndorseMO->setVisible(false);
|
||||
|
||||
MOBase::QuestionBoxMemory::init(initSettings.fileName());
|
||||
|
||||
updateProblemsButton();
|
||||
|
||||
updateToolBar();
|
||||
@@ -185,8 +188,13 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget
|
||||
ui->modList->header()->installEventFilter(&m_ModList);
|
||||
if (initSettings.contains("mod_list_state")) {
|
||||
ui->modList->header()->restoreState(initSettings.value("mod_list_state").toByteArray());
|
||||
} else {
|
||||
// hide these columns by default
|
||||
ui->modList->header()->setSectionHidden(ModList::COL_MODID, true);
|
||||
ui->modList->header()->setSectionHidden(ModList::COL_INSTALLTIME, true);
|
||||
}
|
||||
ui->modList->header()->setSectionHidden(0, false); // prevent the name-column from being hidden
|
||||
|
||||
ui->modList->header()->setSectionHidden(ModList::COL_NAME, false); // prevent the name-column from being hidden
|
||||
ui->modList->installEventFilter(&m_ModList);
|
||||
|
||||
// set up plugin list
|
||||
@@ -202,7 +210,6 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget
|
||||
|
||||
resizeLists(initSettings.contains("mod_list_state"), initSettings.contains("plugin_list_state"));
|
||||
|
||||
|
||||
QMenu *linkMenu = new QMenu(this);
|
||||
linkMenu->addAction(QIcon(":/MO/gui/link"), tr("Toolbar"), this, SLOT(linkToolbar()));
|
||||
linkMenu->addAction(QIcon(":/MO/gui/link"), tr("Desktop"), this, SLOT(linkDesktop()));
|
||||
@@ -216,6 +223,7 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget
|
||||
NexusInterface::instance()->setNMMVersion(m_Settings.getNMMVersion());
|
||||
|
||||
m_InstallationManager.setModsDirectory(m_Settings.getModDirectory());
|
||||
m_InstallationManager.setDownloadDirectory(m_Settings.getDownloadDirectory());
|
||||
|
||||
updateDownloadListDelegate();
|
||||
|
||||
@@ -244,6 +252,8 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget
|
||||
connect(ui->espFilterEdit, SIGNAL(textChanged(QString)), this, SLOT(espFilterChanged(QString)));
|
||||
connect(&m_PluginList, SIGNAL(saveTimer()), this, SLOT(savePluginList()));
|
||||
|
||||
connect(ui->bsaList, SIGNAL(itemsMoved()), this, SLOT(bsaList_itemMoved()));
|
||||
|
||||
connect(ui->bsaWarning, SIGNAL(linkActivated(QString)), this, SLOT(linkClicked(QString)));
|
||||
|
||||
connect(&m_DirectoryRefresher, SIGNAL(refreshed()), this, SLOT(directory_refreshed()));
|
||||
@@ -483,6 +493,7 @@ void MainWindow::updateProblemsButton()
|
||||
ui->actionProblems->setIconText(tr("Problems"));
|
||||
ui->actionProblems->setToolTip(tr("There are potential problems with your setup"));
|
||||
} else {
|
||||
ui->actionProblems->setEnabled(false);
|
||||
ui->actionProblems->setIconText(tr("No Problems"));
|
||||
ui->actionProblems->setToolTip(tr("Everything seems to be in order"));
|
||||
}
|
||||
@@ -678,7 +689,7 @@ bool MainWindow::saveCurrentLists()
|
||||
reportError(tr("failed to save load order: %1").arg(e.what()));
|
||||
}
|
||||
|
||||
// ensure the archive list exists
|
||||
// save only if the file doesn't exist at all, changes made in the ui are saved immediately
|
||||
if (!QFile::exists(m_CurrentProfile->getArchivesFileName())) {
|
||||
saveArchiveList();
|
||||
}
|
||||
@@ -880,8 +891,7 @@ void MainWindow::hideSaveGameInfo()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool MainWindow::eventFilter(QObject* object, QEvent *event)
|
||||
bool MainWindow::eventFilter(QObject *object, QEvent *event)
|
||||
{
|
||||
if ((object == ui->savegameList) &&
|
||||
((event->type() == QEvent::Leave) || (event->type() == QEvent::WindowDeactivate))) {
|
||||
@@ -980,6 +990,7 @@ bool MainWindow::registerPlugin(QObject *plugin)
|
||||
IPluginDiagnose *diagnose = qobject_cast<IPluginDiagnose*>(plugin);
|
||||
if (diagnose != NULL) {
|
||||
m_DiagnosisPlugins.push_back(diagnose);
|
||||
diagnose->onInvalidated([&] () { this->updateProblemsButton(); });
|
||||
}
|
||||
}
|
||||
{ // tool plugins
|
||||
@@ -1264,7 +1275,7 @@ HANDLE MainWindow::spawnBinaryDirect(const QFileInfo &binary, const QString &arg
|
||||
(m_Settings.getLoadMechanism() == LoadMechanism::LOAD_MODORGANIZER)) {
|
||||
if (!testForSteam()) {
|
||||
if (QuestionBoxMemory::query(this->isVisible() ? this : NULL,
|
||||
m_Settings.directInterface(), "steamQuery", tr("Start Steam?"),
|
||||
"steamQuery", tr("Start Steam?"),
|
||||
tr("Steam is required to be running already to correctly start the game. "
|
||||
"Should MO try to start steam now?"),
|
||||
QDialogButtonBox::Yes | QDialogButtonBox::No) == QDialogButtonBox::Yes) {
|
||||
@@ -1359,10 +1370,12 @@ void MainWindow::startExeAction()
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::refreshModList()
|
||||
void MainWindow::refreshModList(bool saveChanges)
|
||||
{
|
||||
// don't lose changes!
|
||||
m_CurrentProfile->writeModlistNow(true);
|
||||
if (saveChanges) {
|
||||
m_CurrentProfile->writeModlistNow(true);
|
||||
}
|
||||
ModInfo::updateFromDisc(m_Settings.getModDirectory(), &m_DirectoryStructure);
|
||||
m_CurrentProfile->refreshModStatus();
|
||||
|
||||
@@ -1423,6 +1436,12 @@ void MainWindow::on_profileBox_currentIndexChanged(int index)
|
||||
saveCurrentLists();
|
||||
}
|
||||
|
||||
// ensure the new index is valid
|
||||
if (index < 0 || index >= ui->profileBox->count()) {
|
||||
qDebug("invalid profile index, using last profile");
|
||||
ui->profileBox->setCurrentIndex(ui->profileBox->count() - 1);
|
||||
}
|
||||
|
||||
if (ui->profileBox->currentIndex() == 0) {
|
||||
ProfilesDialog(m_GamePath).exec();
|
||||
while (!refreshProfiles()) {
|
||||
@@ -1670,7 +1689,7 @@ void MainWindow::refreshSaveList()
|
||||
|
||||
void MainWindow::refreshLists()
|
||||
{
|
||||
if (m_DirectoryStructure->isPopulated()) {
|
||||
if ((m_CurrentProfile != NULL) && m_DirectoryStructure->isPopulated()) {
|
||||
refreshESPList();
|
||||
refreshBSAList();
|
||||
} // no point in refreshing lists if no files have been added to the directory tree
|
||||
@@ -1799,6 +1818,7 @@ void MainWindow::refreshBSAList()
|
||||
subItem = items.at(0);
|
||||
} else {
|
||||
subItem = new QTreeWidgetItem(QStringList(ToQString(origin.getName())));
|
||||
subItem->setFlags(subItem->flags() & ~Qt::ItemIsDragEnabled);
|
||||
ui->bsaList->addTopLevelItem(subItem);
|
||||
}
|
||||
subItem->addChild(iter->second);
|
||||
@@ -2080,7 +2100,7 @@ QStringList MainWindow::findFiles(const QString &path, const std::function<bool(
|
||||
if (dir != NULL) {
|
||||
std::vector<FileEntry::Ptr> files = dir->getFiles();
|
||||
foreach (FileEntry::Ptr file, files) {
|
||||
if (filter(ToQString(file->getName()))) {
|
||||
if (filter(ToQString(file->getFullPath()))) {
|
||||
result.append(ToQString(file->getFullPath()));
|
||||
}
|
||||
}
|
||||
@@ -2090,11 +2110,47 @@ QStringList MainWindow::findFiles(const QString &path, const std::function<bool(
|
||||
return result;
|
||||
}
|
||||
|
||||
QList<IOrganizer::FileInfo> MainWindow::findFileInfos(const QString &path, const std::function<bool (const IOrganizer::FileInfo &)> &filter) const
|
||||
{
|
||||
QList<IOrganizer::FileInfo> result;
|
||||
DirectoryEntry *dir = m_DirectoryStructure->findSubDirectoryRecursive(ToWString(path));
|
||||
if (dir != NULL) {
|
||||
std::vector<FileEntry::Ptr> files = dir->getFiles();
|
||||
foreach (FileEntry::Ptr file, files) {
|
||||
FileInfo info;
|
||||
info.filePath = ToQString(file->getFullPath());
|
||||
bool fromArchive = false;
|
||||
info.origins.append(ToQString(m_DirectoryStructure->getOriginByID(file->getOrigin(fromArchive)).getName()));
|
||||
info.archive = fromArchive ? ToQString(file->getArchive()) : "";
|
||||
foreach (int idx, file->getAlternatives()) {
|
||||
info.origins.append(ToQString(m_DirectoryStructure->getOriginByID(idx).getName()));
|
||||
}
|
||||
|
||||
if (filter(info)) {
|
||||
result.append(info);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qWarning("directory %s not found", qPrintable(path));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
IDownloadManager *MainWindow::downloadManager()
|
||||
{
|
||||
return &m_DownloadManager;
|
||||
}
|
||||
|
||||
IPluginList *MainWindow::pluginList()
|
||||
{
|
||||
return &m_PluginList;
|
||||
}
|
||||
|
||||
IModList *MainWindow::modList()
|
||||
{
|
||||
return &m_ModList;
|
||||
}
|
||||
|
||||
HANDLE MainWindow::startApplication(const QString &executable, const QStringList &args, const QString &cwd, const QString &profile)
|
||||
{
|
||||
QFileInfo binary;
|
||||
@@ -2126,7 +2182,7 @@ HANDLE MainWindow::startApplication(const QString &executable, const QStringList
|
||||
}
|
||||
} catch (const std::runtime_error&) {
|
||||
qWarning("\"%s\" not set up as executable", executable.toUtf8().constData());
|
||||
return INVALID_HANDLE_VALUE;
|
||||
binary = QFileInfo(executable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2145,6 +2201,9 @@ std::vector<unsigned int> MainWindow::activeProblems() const
|
||||
if (m_UnloadedPlugins.size() != 0) {
|
||||
problems.push_back(PROBLEM_PLUGINSNOTLOADED);
|
||||
}
|
||||
if (m_PluginList.enabledCount() > 256) {
|
||||
problems.push_back(PROBLEM_TOOMANYPLUGINS);
|
||||
}
|
||||
return problems;
|
||||
}
|
||||
|
||||
@@ -2154,6 +2213,9 @@ QString MainWindow::shortDescription(unsigned int key) const
|
||||
case PROBLEM_PLUGINSNOTLOADED: {
|
||||
return tr("Some plugins could not be loaded");
|
||||
} break;
|
||||
case PROBLEM_TOOMANYPLUGINS: {
|
||||
return tr("Too many esps and esms enabled");
|
||||
} break;
|
||||
default: {
|
||||
return tr("Description missing");
|
||||
} break;
|
||||
@@ -2164,13 +2226,17 @@ QString MainWindow::fullDescription(unsigned int key) const
|
||||
{
|
||||
switch (key) {
|
||||
case PROBLEM_PLUGINSNOTLOADED: {
|
||||
QString result = tr("The following Plugins could not be loaded. The reason may be missing dependencies (i.e. python) or an outdated version:<ul>");
|
||||
QString result = tr("The following plugins could not be loaded. The reason may be missing dependencies (i.e. python) or an outdated version:") + "<ul>";
|
||||
foreach (const QString &plugin, m_UnloadedPlugins) {
|
||||
result += "<li>" + plugin + "</li>";
|
||||
}
|
||||
result += "<ul>";
|
||||
return result;
|
||||
} break;
|
||||
case PROBLEM_TOOMANYPLUGINS: {
|
||||
return tr("The game doesn't allow more than 256 active plugins (including the official ones) to be loaded. You have to disable some unused plugins or "
|
||||
"merge some plugins into one. You can find a guide here: <a href=\"http://wiki.step-project.com/Guide:Merging_Plugins\">http://wiki.step-project.com/Guide:Merging_Plugins</a>");
|
||||
} break;
|
||||
default: {
|
||||
return tr("Description missing");
|
||||
} break;
|
||||
@@ -2493,6 +2559,11 @@ void MainWindow::directory_refreshed()
|
||||
// some problem-reports may rely on the virtual directory tree so they need to be updated
|
||||
// now
|
||||
updateProblemsButton();
|
||||
|
||||
for (int i = 0; i < m_ModList.rowCount(); ++i) {
|
||||
ModInfo::Ptr modInfo = ModInfo::getByIndex(i);
|
||||
modInfo->clearCaches();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2966,8 +3037,9 @@ void MainWindow::unendorse_clicked()
|
||||
|
||||
void MainWindow::overwriteClosed(int)
|
||||
{
|
||||
QDialog *dialog = this->findChild<QDialog*>("__overwriteDialog");
|
||||
OverwriteInfoDialog *dialog = this->findChild<OverwriteInfoDialog*>("__overwriteDialog");
|
||||
if (dialog != NULL) {
|
||||
m_ModList.modInfoChanged(dialog->modInfo());
|
||||
dialog->deleteLater();
|
||||
}
|
||||
}
|
||||
@@ -2975,6 +3047,7 @@ void MainWindow::overwriteClosed(int)
|
||||
|
||||
void MainWindow::displayModInformation(ModInfo::Ptr modInfo, unsigned int index, int tab)
|
||||
{
|
||||
m_ModList.modInfoAboutToChange(modInfo);
|
||||
std::vector<ModInfo::EFlag> flags = modInfo->getFlags();
|
||||
if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end()) {
|
||||
QDialog *dialog = this->findChild<QDialog*>("__overwriteDialog");
|
||||
@@ -3000,6 +3073,7 @@ void MainWindow::displayModInformation(ModInfo::Ptr modInfo, unsigned int index,
|
||||
dialog.exec();
|
||||
modInfo->saveMeta();
|
||||
emit modInfoDisplayed();
|
||||
m_ModList.modInfoChanged(modInfo);
|
||||
}
|
||||
|
||||
if (m_CurrentProfile->modEnabled(index)) {
|
||||
@@ -3084,7 +3158,7 @@ void MainWindow::testExtractBSA(int modIndex)
|
||||
|
||||
QFileInfoList archives = dir.entryInfoList(QStringList("*.bsa"));
|
||||
if (archives.length() != 0 &&
|
||||
(QuestionBoxMemory::query(this, m_Settings.directInterface(), "unpackBSA", tr("Extract BSA"),
|
||||
(QuestionBoxMemory::query(this, "unpackBSA", tr("Extract BSA"),
|
||||
tr("This mod contains at least one BSA. Do you want to unpack it?\n"
|
||||
"(This removes the BSA after completion. If you don't know about BSAs, just select no)"),
|
||||
QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::No) == QMessageBox::Yes)) {
|
||||
@@ -3171,6 +3245,7 @@ void MainWindow::syncOverwrite()
|
||||
modInfo->testValid();
|
||||
refreshDirectoryStructure();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::createModFromOverwrite()
|
||||
@@ -3841,6 +3916,7 @@ void MainWindow::on_actionSettings_triggered()
|
||||
bool proxy = m_Settings.useProxy();
|
||||
m_Settings.query(this);
|
||||
m_InstallationManager.setModsDirectory(m_Settings.getModDirectory());
|
||||
m_InstallationManager.setDownloadDirectory(m_Settings.getDownloadDirectory());
|
||||
fixCategories();
|
||||
refreshFilters();
|
||||
if (QDir::fromNativeSeparators(m_DownloadManager.getOutputDirectory()) != QDir::fromNativeSeparators(m_Settings.getDownloadDirectory())) {
|
||||
@@ -4636,13 +4712,19 @@ void MainWindow::on_bsaList_customContextMenuRequested(const QPoint &pos)
|
||||
menu.exec(ui->bsaList->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
void MainWindow::on_bsaList_itemChanged(QTreeWidgetItem*, int)
|
||||
void MainWindow::bsaList_itemMoved()
|
||||
{
|
||||
saveArchiveList();
|
||||
m_CheckBSATimer.start(500);
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::on_bsaList_itemChanged(QTreeWidgetItem*, int)
|
||||
{
|
||||
saveArchiveList();
|
||||
m_CheckBSATimer.start(500);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionProblems_triggered()
|
||||
{
|
||||
// QString problemDescription;
|
||||
@@ -4822,3 +4904,4 @@ void MainWindow::on_showHiddenBox_toggled(bool checked)
|
||||
{
|
||||
m_DownloadManager.setShowHidden(checked);
|
||||
}
|
||||
|
||||
|
||||
+9
-5
@@ -60,6 +60,7 @@ class QToolButton;
|
||||
class ModListSortProxy;
|
||||
class ModListGroupCategoriesProxy;
|
||||
|
||||
|
||||
class MainWindow : public QMainWindow, public MOBase::IOrganizer, public MOBase::IPluginDiagnose
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -83,8 +84,6 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
typedef boost::signals2::signal<bool (const QString&), SignalCombinerAnd> SignalAboutToRunApplication;
|
||||
|
||||
public:
|
||||
@@ -99,7 +98,6 @@ public:
|
||||
void refreshBSAList();
|
||||
void refreshDataTree();
|
||||
void refreshSaveList();
|
||||
void refreshModList();
|
||||
|
||||
void setExecutablesList(const ExecutablesList &executablesList);
|
||||
|
||||
@@ -136,9 +134,14 @@ public:
|
||||
virtual QString resolvePath(const QString &fileName) const;
|
||||
virtual QStringList listDirectories(const QString &directoryName) const;
|
||||
virtual QStringList findFiles(const QString &path, const std::function<bool(const QString &)> &filter) const;
|
||||
virtual QList<FileInfo> findFileInfos(const QString &path, const std::function<bool(const FileInfo&)> &filter) const;
|
||||
|
||||
virtual MOBase::IDownloadManager *downloadManager();
|
||||
virtual MOBase::IPluginList *pluginList();
|
||||
virtual MOBase::IModList *modList();
|
||||
virtual HANDLE startApplication(const QString &executable, const QStringList &args = QStringList(), const QString &cwd = "", const QString &profile = "");
|
||||
virtual bool onAboutToRun(const std::function<bool(const QString&)> &func);
|
||||
virtual void refreshModList(bool saveChanges = true);
|
||||
|
||||
virtual std::vector<unsigned int> activeProblems() const;
|
||||
virtual QString shortDescription(unsigned int key) const;
|
||||
@@ -180,7 +183,6 @@ signals:
|
||||
void styleChanged(const QString &styleFile);
|
||||
|
||||
|
||||
|
||||
void modListDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
|
||||
|
||||
protected:
|
||||
@@ -274,6 +276,7 @@ private:
|
||||
private:
|
||||
|
||||
static const unsigned int PROBLEM_PLUGINSNOTLOADED = 1;
|
||||
static const unsigned int PROBLEM_TOOMANYPLUGINS = 2;
|
||||
|
||||
private:
|
||||
|
||||
@@ -511,7 +514,7 @@ private slots: // ui slots
|
||||
void on_actionEndorseMO_triggered();
|
||||
|
||||
void on_bsaList_customContextMenuRequested(const QPoint &pos);
|
||||
void on_bsaList_itemChanged(QTreeWidgetItem *item, int column);
|
||||
void bsaList_itemMoved();
|
||||
void on_btnRefreshData_clicked();
|
||||
void on_categoriesList_customContextMenuRequested(const QPoint &pos);
|
||||
void on_compactBox_toggled(bool checked);
|
||||
@@ -532,6 +535,7 @@ private slots: // ui slots
|
||||
void on_categoriesList_itemSelectionChanged();
|
||||
void on_linkButton_pressed();
|
||||
void on_showHiddenBox_toggled(bool checked);
|
||||
void on_bsaList_itemChanged(QTreeWidgetItem *item, int column);
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
||||
+65
-14
@@ -31,7 +31,16 @@
|
||||
<property name="spacing">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
@@ -721,11 +730,20 @@ p, li { white-space: pre-wrap; }
|
||||
<string notr="true">Archives</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_9">
|
||||
<property name="margin">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="bsaList">
|
||||
<widget class="MOBase::SortableTreeWidget" name="bsaList">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
@@ -742,7 +760,7 @@ BSAs checked here are loaded in such a way that your installation order is obeye
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="showDropIndicator" stdset="0">
|
||||
<bool>false</bool>
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dragEnabled">
|
||||
<bool>false</bool>
|
||||
@@ -751,10 +769,10 @@ BSAs checked here are loaded in such a way that your installation order is obeye
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::NoDragDrop</enum>
|
||||
<enum>QAbstractItemView::DragDrop</enum>
|
||||
</property>
|
||||
<property name="defaultDropAction">
|
||||
<enum>Qt::IgnoreAction</enum>
|
||||
<enum>Qt::MoveAction</enum>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
@@ -768,6 +786,12 @@ BSAs checked here are loaded in such a way that your installation order is obeye
|
||||
<property name="itemsExpandable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="columnCount">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<attribute name="headerVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="headerDefaultSectionSize">
|
||||
<number>200</number>
|
||||
</attribute>
|
||||
@@ -776,11 +800,6 @@ BSAs checked here are loaded in such a way that your installation order is obeye
|
||||
<string>File</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Mod</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@@ -800,7 +819,16 @@ BSAs checked here are loaded in such a way that your installation order is obeye
|
||||
<string>Data</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<property name="margin">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
@@ -870,7 +898,16 @@ BSAs checked here are loaded in such a way that your installation order is obeye
|
||||
<string>Saves</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="margin">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
@@ -899,7 +936,16 @@ p, li { white-space: pre-wrap; }
|
||||
<string>Downloads</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
<property name="margin">
|
||||
<property name="leftMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
@@ -1224,6 +1270,11 @@ Right now this has very limited functionality</string>
|
||||
<extends>QTreeView</extends>
|
||||
<header>modlistview.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>MOBase::SortableTreeWidget</class>
|
||||
<extends>QTreeWidget</extends>
|
||||
<header>sortabletreewidget.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="resources.qrc"/>
|
||||
|
||||
+21
-10
@@ -19,16 +19,19 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "moapplication.h"
|
||||
#include "report.h"
|
||||
#include "utility.h"
|
||||
#include <utility.h>
|
||||
#include <appconfig.h>
|
||||
#include <QFile>
|
||||
#include <QStringList>
|
||||
#include <QPlastiqueStyle>
|
||||
#include <QCleanlooksStyle>
|
||||
|
||||
|
||||
MOApplication::MOApplication(int argc, char **argv)
|
||||
: QApplication(argc, argv)
|
||||
{
|
||||
connect(&m_StyleWatcher, SIGNAL(fileChanged(QString)), SLOT(updateStyle(QString)));
|
||||
m_DefaultStyle = style()->objectName();
|
||||
}
|
||||
|
||||
|
||||
@@ -42,11 +45,12 @@ bool MOApplication::setStyleFile(const QString &styleName)
|
||||
// set new stylesheet or clear it
|
||||
if (styleName.length() != 0) {
|
||||
QString styleSheetName = applicationDirPath() + "/" + MOBase::ToQString(AppConfig::stylesheetsPath()) + "/" + styleName;
|
||||
if (!QFile::exists(styleSheetName)) {
|
||||
return false;
|
||||
if (QFile::exists(styleSheetName)) {
|
||||
m_StyleWatcher.addPath(styleSheetName);
|
||||
updateStyle(styleSheetName);
|
||||
} else {
|
||||
updateStyle(styleName);
|
||||
}
|
||||
m_StyleWatcher.addPath(styleSheetName);
|
||||
updateStyle(styleSheetName);
|
||||
} else {
|
||||
setStyleSheet("");
|
||||
}
|
||||
@@ -74,11 +78,18 @@ bool MOApplication::notify(QObject *receiver, QEvent *event)
|
||||
|
||||
void MOApplication::updateStyle(const QString &fileName)
|
||||
{
|
||||
QFile file(fileName);
|
||||
if (file.open(QFile::ReadOnly)) {
|
||||
setStyleSheet(file.readAll());
|
||||
if (fileName == "Plastique") {
|
||||
setStyle(new QPlastiqueStyle);
|
||||
setStyleSheet("");
|
||||
} else if (fileName == "Cleanlooks") {
|
||||
setStyle(new QCleanlooksStyle);
|
||||
setStyleSheet("");
|
||||
} else {
|
||||
qDebug("no stylesheet");
|
||||
setStyle(m_DefaultStyle);
|
||||
if (QFile::exists(fileName)) {
|
||||
setStyleSheet(QString("file:///%1").arg(fileName));
|
||||
} else {
|
||||
qWarning("invalid stylesheet: %s", qPrintable(fileName));
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
@@ -43,6 +43,8 @@ private slots:
|
||||
private:
|
||||
|
||||
QFileSystemWatcher m_StyleWatcher;
|
||||
QString m_DefaultStyle;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
+20
-1
@@ -324,6 +324,7 @@ ModInfoRegular::ModInfoRegular(const QDir &path, DirectoryEntry **directoryStruc
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QString categoriesString = metaFile.value("category", "").toString();
|
||||
|
||||
QStringList categories = categoriesString.split(',', QString::SkipEmptyParts);
|
||||
@@ -554,6 +555,10 @@ void ModInfoRegular::setNexusDescription(const QString &description)
|
||||
m_MetaInfoChanged = true;
|
||||
}
|
||||
|
||||
void ModInfoRegular::addNexusCategory(int categoryID)
|
||||
{
|
||||
m_Categories.insert(CategoryFactory::instance().resolveNexusID(categoryID));
|
||||
}
|
||||
|
||||
void ModInfoRegular::setIsEndorsed(bool endorsed)
|
||||
{
|
||||
@@ -584,6 +589,11 @@ void ModInfoRegular::endorse(bool doEndorse)
|
||||
}
|
||||
}
|
||||
|
||||
void ModInfoRegular::clearCaches()
|
||||
{
|
||||
m_LastConflictCheck = QTime();
|
||||
}
|
||||
|
||||
|
||||
QString ModInfoRegular::absolutePath() const
|
||||
{
|
||||
@@ -685,7 +695,7 @@ ModInfoRegular::EConflictType ModInfoRegular::isConflicted() const
|
||||
{
|
||||
// this is costy so cache the result
|
||||
QTime now = QTime::currentTime();
|
||||
if (abs(m_LastConflictCheck.secsTo(now)) > 10) {
|
||||
if (m_LastConflictCheck.isNull() || (m_LastConflictCheck.secsTo(now) > 10)) {
|
||||
bool overwrite = false;
|
||||
bool overwritten = false;
|
||||
bool regular = false;
|
||||
@@ -817,6 +827,15 @@ ModInfoOverwrite::ModInfoOverwrite()
|
||||
}
|
||||
|
||||
|
||||
bool ModInfoOverwrite::isEmpty() const
|
||||
{
|
||||
QDirIterator iter(absolutePath(), QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs);
|
||||
if (!iter.hasNext()) return true;
|
||||
iter.next();
|
||||
if ((iter.fileName() == "meta.ini") && !iter.hasNext()) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
QString ModInfoOverwrite::absolutePath() const
|
||||
{
|
||||
return QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOverwriteDir()));
|
||||
|
||||
+26
-17
@@ -80,23 +80,6 @@ public:
|
||||
ENDORSED_UNKNOWN,
|
||||
ENDORSED_NEVER
|
||||
};
|
||||
/*
|
||||
struct NexusFileInfo {
|
||||
NexusFileInfo(const QString &data);
|
||||
NexusFileInfo(int id, const QString &name, const QString &url, const QString &version,
|
||||
const QString &description, int category, int size)
|
||||
: id(id), name(name), url(url), version(version), description(description),
|
||||
category(category), size(size) {}
|
||||
int id;
|
||||
QString name;
|
||||
QString url;
|
||||
QString version;
|
||||
QString description;
|
||||
int category;
|
||||
int size;
|
||||
|
||||
QString toString() const;
|
||||
};*/
|
||||
|
||||
public:
|
||||
|
||||
@@ -267,6 +250,13 @@ public:
|
||||
*/
|
||||
virtual void setNexusDescription(const QString &description) = 0;
|
||||
|
||||
/**
|
||||
* @brief sets the category id from a nexus category id. Conversion to MO id happens internally
|
||||
* @param categoryID the nexus category id
|
||||
* @note if a mapping is not possible, the category is set to the default value
|
||||
*/
|
||||
virtual void addNexusCategory(int categoryID) = 0;
|
||||
|
||||
/**
|
||||
* update the endorsement state for the mod. This only changes the
|
||||
* buffered state, it does not sync with Nexus
|
||||
@@ -292,6 +282,11 @@ public:
|
||||
*/
|
||||
virtual void endorse(bool doEndorse) = 0;
|
||||
|
||||
/**
|
||||
* @brief clear all caches held for this mod
|
||||
*/
|
||||
virtual void clearCaches() {}
|
||||
|
||||
/**
|
||||
* @brief getter for the mod name
|
||||
*
|
||||
@@ -605,6 +600,13 @@ public:
|
||||
*/
|
||||
virtual void setNexusDescription(const QString &description);
|
||||
|
||||
/**
|
||||
* @brief sets the category id from a nexus category id. Conversion to MO id happens internally
|
||||
* @param categoryID the nexus category id
|
||||
* @note if a mapping is not possible, the category is set to the default value
|
||||
*/
|
||||
virtual void addNexusCategory(int categoryID);
|
||||
|
||||
/**
|
||||
* @brief sets the new primary category of the mod
|
||||
* @param categoryID the category to set
|
||||
@@ -636,6 +638,11 @@ public:
|
||||
*/
|
||||
virtual void endorse(bool doEndorse);
|
||||
|
||||
/**
|
||||
* @brief clear all caches held for this mod
|
||||
*/
|
||||
virtual void clearCaches();
|
||||
|
||||
/**
|
||||
* @brief getter for the mod name
|
||||
*
|
||||
@@ -854,10 +861,12 @@ public:
|
||||
virtual void setNewestVersion(const MOBase::VersionInfo&) {}
|
||||
virtual void ignoreUpdate(bool) {}
|
||||
virtual void setNexusDescription(const QString&) {}
|
||||
virtual void addNexusCategory(int) {}
|
||||
virtual void setIsEndorsed(bool) {}
|
||||
virtual void setNeverEndorse() {}
|
||||
virtual bool remove() { return false; }
|
||||
virtual void endorse(bool) {}
|
||||
virtual bool isEmpty() const;
|
||||
virtual QString name() const { return "Overwrite"; }
|
||||
virtual QString notes() const { return ""; }
|
||||
virtual QDateTime creationTime() const { return m_StartupTime; }
|
||||
|
||||
+22
-14
@@ -254,17 +254,19 @@ void ModInfoDialog::refreshLists()
|
||||
} else if ((fileName.endsWith(".png", Qt::CaseInsensitive)) ||
|
||||
(fileName.endsWith(".jpg", Qt::CaseInsensitive))) {
|
||||
QImage image = QImage(fileName);
|
||||
if (static_cast<float>(image.width()) / static_cast<float>(image.height()) > 1.34) {
|
||||
image = image.scaledToWidth(128);
|
||||
} else {
|
||||
image = image.scaledToHeight(96);
|
||||
}
|
||||
if (!image.isNull()) {
|
||||
if (static_cast<float>(image.width()) / static_cast<float>(image.height()) > 1.34) {
|
||||
image = image.scaledToWidth(128);
|
||||
} else {
|
||||
image = image.scaledToHeight(96);
|
||||
}
|
||||
|
||||
QPushButton *thumbnailButton = new QPushButton(QPixmap::fromImage(image), "");
|
||||
thumbnailButton->setIconSize(QSize(image.width(), image.height()));
|
||||
connect(thumbnailButton, SIGNAL(clicked()), &m_ThumbnailMapper, SLOT(map()));
|
||||
m_ThumbnailMapper.setMapping(thumbnailButton, fileName);
|
||||
ui->thumbnailArea->addWidget(thumbnailButton);
|
||||
QPushButton *thumbnailButton = new QPushButton(QPixmap::fromImage(image), "");
|
||||
thumbnailButton->setIconSize(QSize(image.width(), image.height()));
|
||||
connect(thumbnailButton, SIGNAL(clicked()), &m_ThumbnailMapper, SLOT(map()));
|
||||
m_ThumbnailMapper.setMapping(thumbnailButton, fileName);
|
||||
ui->thumbnailArea->addWidget(thumbnailButton);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,7 +402,13 @@ void ModInfoDialog::openTextFile(const QString &fileName)
|
||||
textFile.open(QIODevice::ReadOnly);
|
||||
QByteArray buffer = textFile.readAll();
|
||||
QTextCodec *codec = QTextCodec::codecForUtfText(buffer, m_UTF8Codec);
|
||||
ui->textFileView->setText(codec->toUnicode(buffer));
|
||||
QString text = codec->toUnicode(buffer);
|
||||
if (codec->fromUnicode(text) != buffer) {
|
||||
qDebug("conversion failed assuming local encoding");
|
||||
codec = QTextCodec::codecForLocale();
|
||||
text = codec->toUnicode(buffer);
|
||||
}
|
||||
ui->textFileView->setText(text);
|
||||
ui->textFileView->setProperty("currentFile", fileName);
|
||||
ui->textFileView->setProperty("encoding", codec->name());
|
||||
ui->saveTXTButton->setEnabled(false);
|
||||
@@ -1169,10 +1177,10 @@ void ModInfoDialog::on_prevButton_clicked()
|
||||
void ModInfoDialog::createTweak()
|
||||
{
|
||||
QString name = QInputDialog::getText(this, tr("Name"), tr("Please enter a name"));
|
||||
if (!fixDirectoryName(name)) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Invalid name. Must be a valid file name"));
|
||||
if (name.isNull()) {
|
||||
return;
|
||||
} else if (name.isEmpty()) {
|
||||
} else if (!fixDirectoryName(name)) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Invalid name. Must be a valid file name"));
|
||||
return;
|
||||
} else if (ui->iniTweaksList->findItems(name, Qt::MatchFixedString).count() != 0) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("A tweak by that name exists"));
|
||||
|
||||
+13
-23
@@ -217,11 +217,7 @@
|
||||
<string>Images located in the mod.</string>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This lists all the images (.jpg and .png) in the mod directory, like screenshots and such. Click one to get a larger view.</span></p></body></html></string>
|
||||
<string>This lists all the images (.jpg and .png) in the mod directory, like screenshots and such. Click one to get a larger view.</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
@@ -254,14 +250,10 @@ p, li { white-space: pre-wrap; }
|
||||
<string>List of esps and esms that can not be loaded by the game.</string>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">List of esps and esms contained in this plugin that currently can not be loaded by the game. They will not even appear in the esp-list in the main MO-window.</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">They usually contain optional functionality, see the readme.</span></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Most mods do not have optional esps, so chances are good you are looking at an empty list.</span></p></body></html></string>
|
||||
<string>List of esps and esms contained in this plugin that currently can not be loaded by the game. They will not even appear in the esp-list in the main MO-window.
|
||||
They usually contain optional functionality, see the readme.
|
||||
|
||||
Most mods do not have optional esps, so chances are good you are looking at an empty list.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -292,7 +284,7 @@ p, li { white-space: pre-wrap; }
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="resources.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/MO/gui/resources/go-up.png</normaloff>:/MO/gui/resources/go-up.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
@@ -321,7 +313,7 @@ p, li { white-space: pre-wrap; }
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="resources.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/MO/gui/resources/go-down.png</normaloff>:/MO/gui/resources/go-down.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
@@ -524,9 +516,9 @@ p, li { white-space: pre-wrap; }
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_12">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_9">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Primary Category</string>
|
||||
</property>
|
||||
@@ -541,7 +533,7 @@ p, li { white-space: pre-wrap; }
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabNexus_2">
|
||||
<attribute name="icon">
|
||||
<iconset resource="resources.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/MO/gui/resources/internet-web-browser.png</normaloff>:/MO/gui/resources/internet-web-browser.png</iconset>
|
||||
</attribute>
|
||||
<attribute name="title">
|
||||
@@ -633,7 +625,7 @@ p, li { white-space: pre-wrap; }
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="resources.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/MO/gui/refresh</normaloff>:/MO/gui/refresh</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -695,7 +687,7 @@ p, li { white-space: pre-wrap; }
|
||||
<string>Endorse</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="resources.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/MO/gui/icon_favorite</normaloff>:/MO/gui/icon_favorite</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -790,8 +782,6 @@ p, li { white-space: pre-wrap; }
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="resources.qrc"/>
|
||||
</resources>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
||||
+109
-13
@@ -169,10 +169,16 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
|
||||
int category = modInfo->getPrimaryCategory();
|
||||
if (category != -1) {
|
||||
CategoryFactory &categoryFactory = CategoryFactory::instance();
|
||||
try {
|
||||
return categoryFactory.getCategoryName(categoryFactory.getCategoryIndex(category));
|
||||
} catch (const std::exception &e) {
|
||||
qCritical("failed to retrieve category name: %s", e.what());
|
||||
if (categoryFactory.categoryExists(category)) {
|
||||
try {
|
||||
return categoryFactory.getCategoryName(categoryFactory.getCategoryIndex(category));
|
||||
} catch (const std::exception &e) {
|
||||
qCritical("failed to retrieve category name: %s", e.what());
|
||||
return QString();
|
||||
}
|
||||
} else {
|
||||
qWarning("category %d doesn't exist (may have been removed)", category);
|
||||
modInfo->setCategory(category, false);
|
||||
return QString();
|
||||
}
|
||||
} else {
|
||||
@@ -180,7 +186,12 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
|
||||
return QVariant();
|
||||
}
|
||||
} else if (column == COL_INSTALLTIME) {
|
||||
return modInfo->creationTime();
|
||||
// display installation time for mods that can be updated
|
||||
if (modInfo->canBeUpdated()) {
|
||||
return modInfo->creationTime();
|
||||
} else {
|
||||
return QVariant();
|
||||
}
|
||||
} else {
|
||||
return tr("invalid");
|
||||
}
|
||||
@@ -373,9 +384,10 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
}
|
||||
return true;
|
||||
} else if (role == Qt::EditRole) {
|
||||
bool res = false;
|
||||
switch (index.column()) {
|
||||
case COL_NAME: {
|
||||
return renameMod(modID, value.toString());
|
||||
res = renameMod(modID, value.toString());
|
||||
} break;
|
||||
case COL_PRIORITY: {
|
||||
bool ok = false;
|
||||
@@ -384,9 +396,9 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
m_Profile->setModPriority(modID, newPriority);
|
||||
|
||||
emit modlist_changed(index, role);
|
||||
return true;
|
||||
res = true;
|
||||
} else {
|
||||
return false;
|
||||
res = false;
|
||||
}
|
||||
} break;
|
||||
case COL_MODID: {
|
||||
@@ -396,9 +408,9 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
if (ok) {
|
||||
info->setNexusID(newID);
|
||||
emit modlist_changed(index, role);
|
||||
return true;
|
||||
res = true;
|
||||
} else {
|
||||
return false;
|
||||
res = false;
|
||||
}
|
||||
} break;
|
||||
case COL_VERSION: {
|
||||
@@ -407,17 +419,21 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
VersionInfo version(value.toString(), scheme);
|
||||
if (version.isValid()) {
|
||||
info->setVersion(version);
|
||||
return true;
|
||||
res = true;
|
||||
} else {
|
||||
return false;
|
||||
res = false;
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
qWarning("edit on column \"%s\" not supported",
|
||||
getColumnName(index.column()).toUtf8().constData());
|
||||
return false;
|
||||
res = false;
|
||||
} break;
|
||||
}
|
||||
if (res) {
|
||||
emit dataChanged(index, index);
|
||||
}
|
||||
return res;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -540,6 +556,86 @@ void ModList::changeModPriority(int sourceIndex, int newPriority)
|
||||
emit modorder_changed();
|
||||
}
|
||||
|
||||
void ModList::modInfoAboutToChange(ModInfo::Ptr info)
|
||||
{
|
||||
m_ChangeInfo.name = info->name();
|
||||
m_ChangeInfo.state = state(info->name());
|
||||
}
|
||||
|
||||
void ModList::modInfoChanged(ModInfo::Ptr info)
|
||||
{
|
||||
if (info->name() == m_ChangeInfo.name) {
|
||||
IModList::ModStates newState = state(info->name());
|
||||
if (m_ChangeInfo.state != newState) {
|
||||
m_ModStateChanged(info->name(), newState);
|
||||
}
|
||||
int row = ModInfo::getIndex(info->name());
|
||||
info->testValid();
|
||||
emit dataChanged(index(row, 0), index(row, columnCount()));
|
||||
} else {
|
||||
qCritical("modInfoChanged not called after modInfoAboutToChange");
|
||||
}
|
||||
}
|
||||
|
||||
IModList::ModStates ModList::state(const QString &name) const
|
||||
{
|
||||
ModStates result;
|
||||
unsigned int modIndex = ModInfo::getIndex(name);
|
||||
if (modIndex != UINT_MAX) {
|
||||
result |= IModList::STATE_EXISTS;
|
||||
ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex);
|
||||
if (modInfo->isEmpty()) {
|
||||
result |= IModList::STATE_EMPTY;
|
||||
}
|
||||
if (modInfo->endorsedState() == ModInfo::ENDORSED_TRUE) {
|
||||
result |= IModList::STATE_ENDORSED;
|
||||
}
|
||||
if (modInfo->isValid()) {
|
||||
result |= IModList::STATE_VALID;
|
||||
}
|
||||
if (modInfo->canBeEnabled()) {
|
||||
if (m_Profile->modEnabled(modIndex)) {
|
||||
result |= IModList::STATE_ACTIVE;
|
||||
}
|
||||
} else {
|
||||
result |= IModList::STATE_ESSENTIAL;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int ModList::priority(const QString &name) const
|
||||
{
|
||||
unsigned int modIndex = ModInfo::getIndex(name);
|
||||
if (modIndex == UINT_MAX) {
|
||||
return -1;
|
||||
} else {
|
||||
return m_Profile->getModPriority(modIndex);
|
||||
}
|
||||
}
|
||||
|
||||
bool ModList::setPriority(const QString &name, int newPriority)
|
||||
{
|
||||
if ((newPriority < 0) || (newPriority >= static_cast<int>(m_Profile->numRegularMods()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int modIndex = ModInfo::getIndex(name);
|
||||
if (modIndex == UINT_MAX) {
|
||||
return false;
|
||||
} else {
|
||||
m_Profile->setModPriority(modIndex, newPriority);
|
||||
notifyChange(modIndex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ModList::onModStateChanged(const std::function<void (const QString &, IModList::ModStates)> &func)
|
||||
{
|
||||
auto conn = m_ModStateChanged.connect(func);
|
||||
return conn.connected();
|
||||
}
|
||||
|
||||
bool ModList::dropURLs(const QMimeData *mimeData, int row, const QModelIndex &parent)
|
||||
{
|
||||
|
||||
+36
-2
@@ -26,11 +26,13 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "modinfo.h"
|
||||
#include "profile.h"
|
||||
|
||||
#include <imodlist.h>
|
||||
|
||||
#include <QFile>
|
||||
#include <QListWidget>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
#include <boost/signals2.hpp>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <QVector>
|
||||
@@ -41,7 +43,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
* This is used in a view in the main window of MO. It combines general information about
|
||||
* the mods from ModInfo with status information from the Profile
|
||||
**/
|
||||
class ModList : public QAbstractItemModel
|
||||
class ModList : public QAbstractItemModel, public MOBase::IModList
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -59,6 +61,8 @@ public:
|
||||
COL_LASTCOLUMN = COL_PRIORITY
|
||||
};
|
||||
|
||||
typedef boost::signals2::signal<void (const QString &, ModStates)> SignalModStateChanged;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
@@ -92,6 +96,23 @@ public:
|
||||
|
||||
void changeModPriority(int sourceIndex, int newPriority);
|
||||
|
||||
void modInfoAboutToChange(ModInfo::Ptr info);
|
||||
void modInfoChanged(ModInfo::Ptr info);
|
||||
|
||||
public:
|
||||
|
||||
/// \copydoc MOBase::IModList::state
|
||||
virtual ModStates state(const QString &name) const;
|
||||
|
||||
/// \copydoc MOBase::IModList::priority
|
||||
virtual int priority(const QString &name) const;
|
||||
|
||||
/// \copydoc MOBase::IModList::setPriority
|
||||
virtual bool setPriority(const QString &name, int newPriority);
|
||||
|
||||
/// \copydoc MOBase::IModList::onModStateChanged
|
||||
virtual bool onModStateChanged(const std::function<void (const QString &, ModStates)> &func);
|
||||
|
||||
public: // implementation of virtual functions of QAbstractItemModel
|
||||
|
||||
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
@@ -232,6 +253,11 @@ private:
|
||||
unsigned int categoryOrder;
|
||||
};
|
||||
|
||||
struct TModInfoChange {
|
||||
QString name;
|
||||
QFlags<IModList::ModStates> state;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Profile *m_Profile;
|
||||
@@ -245,6 +271,14 @@ private:
|
||||
|
||||
bool m_DropOnItems;
|
||||
|
||||
TModInfoChange m_ChangeInfo;
|
||||
|
||||
SignalModStateChanged m_ModStateChanged;
|
||||
|
||||
|
||||
// QAbstractItemModel interface
|
||||
|
||||
// IModList interface
|
||||
};
|
||||
|
||||
#endif // MODLIST_H
|
||||
|
||||
+38
-13
@@ -137,10 +137,30 @@ bool ModListSortProxy::lessThan(const QModelIndex &left,
|
||||
ModInfo::Ptr rightMod = ModInfo::getByIndex(rightIndex);
|
||||
|
||||
bool lt = false;
|
||||
|
||||
{
|
||||
QModelIndex leftPrioIdx = left.sibling(left.row(), ModList::COL_PRIORITY);
|
||||
QVariant leftPrio = leftPrioIdx.data();
|
||||
if (!leftPrio.isValid()) leftPrio = left.data(Qt::UserRole);
|
||||
QModelIndex rightPrioIdx = right.sibling(right.row(), ModList::COL_PRIORITY);
|
||||
QVariant rightPrio = rightPrioIdx.data();
|
||||
if (!rightPrio.isValid()) rightPrio = right.data(Qt::UserRole);
|
||||
|
||||
lt = leftPrio.toInt() < rightPrio.toInt();
|
||||
}
|
||||
|
||||
switch (left.column()) {
|
||||
case ModList::COL_FLAGS: lt = leftMod->getFlags().size() < rightMod->getFlags().size(); break;
|
||||
case ModList::COL_NAME: lt = QString::compare(leftMod->name(), rightMod->name(), Qt::CaseInsensitive) < 0; break;
|
||||
case ModList::COL_FLAGS: {
|
||||
if (leftMod->getFlags().size() != rightMod->getFlags().size())
|
||||
lt = leftMod->getFlags().size() < rightMod->getFlags().size();
|
||||
} break;
|
||||
case ModList::COL_NAME: {
|
||||
int comp = QString::compare(leftMod->name(), rightMod->name(), Qt::CaseInsensitive);
|
||||
if (comp != 0)
|
||||
lt = comp < 0;
|
||||
} break;
|
||||
case ModList::COL_CATEGORY: {
|
||||
if (leftMod->getPrimaryCategory() != rightMod->getPrimaryCategory()) {
|
||||
if (leftMod->getPrimaryCategory() < 0) lt = false;
|
||||
else if (rightMod->getPrimaryCategory() < 0) lt = true;
|
||||
else {
|
||||
@@ -153,19 +173,24 @@ bool ModListSortProxy::lessThan(const QModelIndex &left,
|
||||
qCritical("failed to compare categories: %s", e.what());
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case ModList::COL_MODID: lt = leftMod->getNexusID() < rightMod->getNexusID(); break;
|
||||
case ModList::COL_VERSION: lt = leftMod->getVersion() < rightMod->getVersion(); break;
|
||||
case ModList::COL_PRIORITY: {
|
||||
QVariant leftPrio = left.data();
|
||||
if (!leftPrio.isValid()) leftPrio = left.data(Qt::UserRole);
|
||||
QVariant rightPrio = right.data();
|
||||
if (!rightPrio.isValid()) rightPrio = right.data(Qt::UserRole);
|
||||
|
||||
return leftPrio.toInt() < rightPrio.toInt();
|
||||
}
|
||||
} break;
|
||||
case ModList::COL_MODID: {
|
||||
if (leftMod->getNexusID() != rightMod->getNexusID())
|
||||
lt = leftMod->getNexusID() < rightMod->getNexusID();
|
||||
} break;
|
||||
case ModList::COL_VERSION: {
|
||||
if (leftMod->getVersion() != rightMod->getVersion())
|
||||
lt = leftMod->getVersion() < rightMod->getVersion();
|
||||
} break;
|
||||
case ModList::COL_INSTALLTIME: {
|
||||
return left.data().toDateTime() < right.data().toDateTime();
|
||||
QDateTime leftTime = left.data().toDateTime();
|
||||
QDateTime rightTime = right.data().toDateTime();
|
||||
if (leftTime != rightTime)
|
||||
return leftTime < rightTime;
|
||||
} break;
|
||||
case ModList::COL_PRIORITY: {
|
||||
// nop, already compared by priority
|
||||
} break;
|
||||
}
|
||||
return lt;
|
||||
|
||||
+13
-2
@@ -22,8 +22,10 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "utility.h"
|
||||
#include "json.h"
|
||||
#include "selectiondialog.h"
|
||||
#include <QApplication>
|
||||
#include <utility.h>
|
||||
#include <regex>
|
||||
#include <util.h>
|
||||
|
||||
using QtJson::Json;
|
||||
|
||||
@@ -148,6 +150,13 @@ NexusInterface::NexusInterface()
|
||||
|
||||
m_DiskCache = new QNetworkDiskCache(this);
|
||||
connect(m_AccessManager, SIGNAL(requestNXMDownload(QString)), this, SLOT(downloadRequestedNXM(QString)));
|
||||
|
||||
|
||||
VS_FIXEDFILEINFO version = GetFileVersion(ToWString(QApplication::applicationFilePath()));
|
||||
|
||||
m_MOVersion = VersionInfo(version.dwFileVersionMS >> 16,
|
||||
version.dwFileVersionMS & 0xFFFF,
|
||||
version.dwFileVersionLS >> 16);
|
||||
}
|
||||
|
||||
|
||||
@@ -396,8 +405,10 @@ void NexusInterface::nextRequest()
|
||||
|
||||
QNetworkRequest request(url);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/xml");
|
||||
#pragma message("automatically insert the correct version number")
|
||||
request.setRawHeader("User-Agent", QString("Mod Organizer v1.0.5 (compatible to Nexus Client v%1)").arg(m_NMMVersion).toUtf8());
|
||||
request.setRawHeader("User-Agent",
|
||||
QString("Mod Organizer v%1 (compatible to Nexus Client v%2)")
|
||||
.arg(m_MOVersion.displayString())
|
||||
.arg(m_NMMVersion).toUtf8());
|
||||
|
||||
info.m_Reply = m_AccessManager->get(request);
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "nxmaccessmanager.h"
|
||||
|
||||
#include "utility.h"
|
||||
#include <utility.h>
|
||||
#include <gameinfo.h>
|
||||
#include <versioninfo.h>
|
||||
#include <imodrepositorybridge.h>
|
||||
@@ -307,6 +307,7 @@ private:
|
||||
std::list<NXMRequestInfo> m_ActiveRequest;
|
||||
QQueue<NXMRequestInfo> m_RequestQueue;
|
||||
|
||||
MOBase::VersionInfo m_MOVersion;
|
||||
QString m_NMMVersion;
|
||||
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user