From 7d79e3ad1e8a710e836e1cd44106a610e6d2a049 Mon Sep 17 00:00:00 2001 From: Tannin Date: Thu, 15 Aug 2013 22:13:18 +0200 Subject: - bugfix: nameprefix-flag incorrectly interpreted on oblivion-style bsas - bugfix: optimization for missing inis fixed - bugfix: fixmods didn't search for esps in overwrite - bugfix: configurator didn't work for fallout new vegas because of a missing cast - bugfix: configurator attempted parameter formatting on ini files instead of using the raw data - bugfix: searching for a path in the directory structure could cause a crash when not using the directory output - optimization to findfirstfile for cases where a single file is searched - display of bsas changed. hopefully it is more understandable now - cache for the test whether a mod is in conflict. Should speed ab scrolling in mod list - mod list has now an additional column for the installation time - nmm importer no longer cancels in cases where a data file references an undeclared mod. - integrated improved settings.json for the configurator contributed by "delta534" --- src/mainwindow.cpp | 85 +++++++++++++++++++++++++++++---------- src/mainwindow.h | 2 + src/mainwindow.ui | 86 ++++++++++++++++++++++++++++++--------- src/modinfo.cpp | 93 ++++++++++++++++++++++++------------------- src/modinfo.h | 17 +++++++- src/modlist.cpp | 4 ++ src/modlist.h | 1 + src/shared/directoryentry.cpp | 16 ++++---- 8 files changed, 216 insertions(+), 88 deletions(-) (limited to 'src') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 99b37feb..84e5b094 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -256,6 +256,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->bsaWarning, SIGNAL(linkActivated(QString)), this, SLOT(linkClicked(QString))); + connect(&m_DirectoryRefresher, SIGNAL(refreshed()), this, SLOT(directory_refreshed())); connect(&m_DirectoryRefresher, SIGNAL(progress(int)), this, SLOT(refresher_progress(int))); connect(&m_DirectoryRefresher, SIGNAL(error(QString)), this, SLOT(showError(QString))); @@ -1648,7 +1650,8 @@ void MainWindow::refreshBSAList() QTreeWidgetItem *newItem = new QTreeWidgetItem(strings); newItem->setData(0, Qt::UserRole, index); newItem->setData(1, Qt::UserRole, origin); - newItem->setFlags(newItem->flags() & ~Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable); +// newItem->setFlags(newItem->flags() & ~Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable); + newItem->setFlags(newItem->flags() | Qt::ItemIsUserCheckable); newItem->setCheckState(0, (index != -1) ? Qt::Checked : Qt::Unchecked); if (m_Settings.forceEnableCoreFiles() && m_DefaultArchives.contains(filename)) { newItem->setCheckState(0, Qt::Checked); @@ -1658,6 +1661,7 @@ void MainWindow::refreshBSAList() } if (index < 0) index = 0; + UINT32 sortValue = ((m_DirectoryStructure->getOriginByID(origin).getPriority() & 0xFFFF) << 16) | (index & 0xFFFF); items.push_back(std::make_pair(sortValue, newItem)); } @@ -1666,7 +1670,18 @@ void MainWindow::refreshBSAList() std::sort(items.begin(), items.end(), BySortValue); for (std::vector >::iterator iter = items.begin(); iter != items.end(); ++iter) { - ui->bsaList->addTopLevelItem(iter->second); + int originID = iter->second->data(1, Qt::UserRole).toInt(); + FilesOrigin origin = m_DirectoryStructure->getOriginByID(originID); + QList items = ui->bsaList->findItems(ToQString(origin.getName()), Qt::MatchFixedString); + QTreeWidgetItem *subItem = NULL; + if (items.length() > 0) { + subItem = items.at(0); + } else { + subItem = new QTreeWidgetItem(QStringList(ToQString(origin.getName()))); + ui->bsaList->addTopLevelItem(subItem); + } + subItem->addChild(iter->second); + //ui->bsaList->addTopLevelItem(iter->second); } checkBSAList(); @@ -1681,27 +1696,35 @@ void MainWindow::checkBSAList() bool warning = false; for (int i = 0; i < ui->bsaList->topLevelItemCount(); ++i) { - QTreeWidgetItem *item = ui->bsaList->topLevelItem(i); - QString filename = item->text(0); - item->setIcon(0, QIcon()); - item->setToolTip(0, QString()); - - if (item->checkState(0) == Qt::Unchecked) { - if (m_DefaultArchives.contains(filename)) { - item->setIcon(0, QIcon(":/MO/gui/resources/dialog-warning.png")); - item->setToolTip(0, tr("This bsa is enabled in the ini file so it may be required!")); - warning = true; - } else { - QString espName = filename.mid(0, filename.length() - 3).append("esp").toLower(); - QString esmName = filename.mid(0, filename.length() - 3).append("esm").toLower(); - if (m_PluginList.isEnabled(espName) || m_PluginList.isEnabled(esmName)) { + bool modWarning = false; + QTreeWidgetItem *tlItem = ui->bsaList->topLevelItem(i); + for (int j = 0; j < tlItem->childCount(); ++j) { + QTreeWidgetItem *item = tlItem->child(j); + QString filename = item->text(0); + item->setIcon(0, QIcon()); + item->setToolTip(0, QString()); + + if (item->checkState(0) == Qt::Unchecked) { + if (m_DefaultArchives.contains(filename)) { item->setIcon(0, QIcon(":/MO/gui/resources/dialog-warning.png")); - item->setToolTip(0, tr("This archive will still be loaded since there is a plugin of the same name but " - "its files will not follow installation order!")); - warning = true; + item->setToolTip(0, tr("This bsa is enabled in the ini file so it may be required!")); + modWarning = true; + } else { + QString espName = filename.mid(0, filename.length() - 3).append("esp").toLower(); + QString esmName = filename.mid(0, filename.length() - 3).append("esm").toLower(); + if (m_PluginList.isEnabled(espName) || m_PluginList.isEnabled(esmName)) { + item->setIcon(0, QIcon(":/MO/gui/resources/dialog-warning.png")); + item->setToolTip(0, tr("This archive will still be loaded since there is a plugin of the same name but " + "its files will not follow installation order!")); + modWarning = true; + } } } } + if (modWarning) { + ui->bsaList->expandItem(ui->bsaList->topLevelItem(i)); + warning = true; + } } if (warning) { @@ -2072,7 +2095,6 @@ void MainWindow::issueTriggered() ::ShellExecuteW(NULL, L"open", L"http://issue.tannin.eu/tbg", NULL, NULL, SW_SHOWNORMAL); } - void MainWindow::tutorialTriggered() { QAction *tutorialAction = qobject_cast(sender()); @@ -3312,6 +3334,7 @@ void MainWindow::fixMods_clicked() QStringList espFilter("*.esp"); espFilter.append("*.esm"); + // search in data { QDir dataDir(m_GamePath + "/data"); QStringList esps = dataDir.entryList(espFilter); @@ -3323,6 +3346,7 @@ void MainWindow::fixMods_clicked() } } + // search in mods for (unsigned int i = 0; i < m_CurrentProfile->numRegularMods(); ++i) { int modIndex = m_CurrentProfile->modIndexByPriority(i); ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex); @@ -3336,12 +3360,25 @@ void MainWindow::fixMods_clicked() } } + // search in overwrite + { + QDir overwriteDir(ToQString(GameInfo::instance().getOverwriteDir())); + QStringList esps = overwriteDir.entryList(espFilter); + foreach (const QString &esp, esps) { + std::map >::iterator iter = missingPlugins.find(esp); + if (iter != missingPlugins.end()) { + iter->second.push_back(""); + } + } + } + + ActivateModsDialog dialog(missingPlugins, this); if (dialog.exec() == QDialog::Accepted) { // activate the required mods, then enable all esps std::set modsToActivate = dialog.getModsToActivate(); for (std::set::iterator iter = modsToActivate.begin(); iter != modsToActivate.end(); ++iter) { - if (*iter != "") { + if ((*iter != "") && (*iter != "")) { unsigned int modIndex = ModInfo::getIndex(*iter); m_CurrentProfile->setModEnabled(modIndex, true); } @@ -3496,6 +3533,12 @@ void MainWindow::nexusLinkActivated(const QString &link) } +void MainWindow::linkClicked(const QString &url) +{ + ::ShellExecuteW(NULL, L"open", ToWString(url).c_str(), NULL, NULL, SW_SHOWNORMAL); +} + + void MainWindow::downloadRequestedNXM(const QString &url) { QString username, password; diff --git a/src/mainwindow.h b/src/mainwindow.h index 23d5f0da..d7d0a8e7 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -362,6 +362,8 @@ private slots: void checkModsForUpdates(); void nexusLinkActivated(const QString &link); + void linkClicked(const QString &url); + void loginSuccessful(bool necessary); void loginSuccessfulUpdate(bool necessary); void loginFailed(const QString &message); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index c019ccd9..fcdbd63c 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -31,7 +31,16 @@ 4 - + + 6 + + + 6 + + + 6 + + 6 @@ -719,19 +728,18 @@ p, li { white-space: pre-wrap; } Archives - + + 6 + + + 6 + + + 6 + + 6 - - - - IMPORTANT: You can change the order of BSAs here but installation order of mods has priority over the order specified here! - - - true - - - @@ -749,14 +757,17 @@ BSAs checked here are loaded in such a way that your installation order is obeye QAbstractItemView::NoEditTriggers + + false + - true + false false - QAbstractItemView::InternalMove + QAbstractItemView::NoDragDrop Qt::IgnoreAction @@ -768,10 +779,10 @@ BSAs checked here are loaded in such a way that your installation order is obeye QAbstractItemView::SelectRows - 0 + 20 - false + true 200 @@ -788,6 +799,16 @@ BSAs checked here are loaded in such a way that your installation order is obeye + + + + <html><head/><body><p>Marked Archives (<img src=":/MO/gui/resources/dialog-warning_16.png"/>) are still loaded on Skyrim but the <a href="http://forums.bethsoft.com/topic/1354395-update-bsas-and-you/"><span style=" text-decoration: underline; color:#0000ff;">regular file override</span></a> mechanism will apply: Loose files override BSAs, no matter the mod/plugin priority.</p></body></html> + + + true + + + @@ -795,7 +816,16 @@ BSAs checked here are loaded in such a way that your installation order is obeye Data - + + 6 + + + 6 + + + 6 + + 6 @@ -865,7 +895,16 @@ BSAs checked here are loaded in such a way that your installation order is obeye Saves - + + 6 + + + 6 + + + 6 + + 6 @@ -894,7 +933,16 @@ p, li { white-space: pre-wrap; } Downloads - + + 2 + + + 2 + + + 2 + + 2 diff --git a/src/modinfo.cpp b/src/modinfo.cpp index 1bb2daad..f6043d97 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -298,7 +298,7 @@ ModInfoRegular::ModInfoRegular(const QDir &path, DirectoryEntry **directoryStruc m_EndorsedState(ENDORSED_UNKNOWN), m_DirectoryStructure(directoryStructure) { testValid(); - + m_CreationTime = QFileInfo(path.absolutePath()).created(); // read out the meta-file for information QString metaFileName = path.absoluteFilePath("meta.ini"); QSettings metaFile(metaFileName, QSettings::IniFormat); @@ -645,6 +645,11 @@ QString ModInfoRegular::notes() const return m_Notes; } +QDateTime ModInfoRegular::creationTime() const +{ + return m_CreationTime; +} + QString ModInfoRegular::getNexusDescription() const { return m_NexusDescription; @@ -659,55 +664,63 @@ ModInfoRegular::EEndorsedState ModInfoRegular::endorsedState() const ModInfoRegular::EConflictType ModInfoRegular::isConflicted() const { - bool overwrite = false; - bool overwritten = false; - bool regular = false; + // this is costy so cache the result + QTime now = QTime::currentTime(); + if (abs(m_LastConflictCheck.secsTo(now)) > 10) { + bool overwrite = false; + bool overwritten = false; + bool regular = false; - int dataID = 0; - if ((*m_DirectoryStructure)->originExists(L"data")) { - dataID = (*m_DirectoryStructure)->getOriginByName(L"data").getID(); - } + int dataID = 0; + if ((*m_DirectoryStructure)->originExists(L"data")) { + dataID = (*m_DirectoryStructure)->getOriginByName(L"data").getID(); + } - std::wstring name = ToWString(m_Name); - if ((*m_DirectoryStructure)->originExists(name)) { - FilesOrigin &origin = (*m_DirectoryStructure)->getOriginByName(name); - std::vector files = origin.getFiles(); - for (auto iter = files.begin(); iter != files.end() && (!overwrite || !overwritten || !regular); ++iter) { - const std::vector &alternatives = (*iter)->getAlternatives(); - if (alternatives.size() == 0) { - // no alternatives -> no conflict - regular = true; - } else { - for (auto altIter = alternatives.begin(); altIter != alternatives.end(); ++altIter) { - // don't treat files overwritten in data as "conflict" - if (*altIter != dataID) { - bool ignore = false; - if ((*iter)->getOrigin(ignore) == origin.getID()) { - overwrite = true; - break; - } else { - overwritten = true; - break; + std::wstring name = ToWString(m_Name); + if ((*m_DirectoryStructure)->originExists(name)) { + FilesOrigin &origin = (*m_DirectoryStructure)->getOriginByName(name); + std::vector files = origin.getFiles(); + for (auto iter = files.begin(); iter != files.end() && (!overwrite || !overwritten || !regular); ++iter) { + const std::vector &alternatives = (*iter)->getAlternatives(); + if (alternatives.size() == 0) { + // no alternatives -> no conflict + regular = true; + } else { + for (auto altIter = alternatives.begin(); altIter != alternatives.end(); ++altIter) { + // don't treat files overwritten in data as "conflict" + if (*altIter != dataID) { + bool ignore = false; + if ((*iter)->getOrigin(ignore) == origin.getID()) { + overwrite = true; + break; + } else { + overwritten = true; + break; + } + } else if (alternatives.size() == 1) { + // only alternative is data -> no conflict + regular = true; } - } else if (alternatives.size() == 1) { - // only alternative is data -> no conflict - regular = true; } } } } - } - if (overwrite && overwritten) return CONFLICT_MIXED; - else if (overwrite) return CONFLICT_OVERWRITE; - else if (overwritten) { - if (!regular) { - return CONFLICT_REDUNDANT; - } else { - return CONFLICT_OVERWRITTEN; + m_LastConflictCheck = QTime::currentTime(); + + if (overwrite && overwritten) m_CurrentConflictState = CONFLICT_MIXED; + else if (overwrite) m_CurrentConflictState = CONFLICT_OVERWRITE; + else if (overwritten) { + if (!regular) { + m_CurrentConflictState = CONFLICT_REDUNDANT; + } else { + m_CurrentConflictState = CONFLICT_OVERWRITTEN; + } } + else m_CurrentConflictState = CONFLICT_NONE; } - else return CONFLICT_NONE; + + return m_CurrentConflictState; } diff --git a/src/modinfo.h b/src/modinfo.h index 74a77cd2..e6c6e6ac 100644 --- a/src/modinfo.h +++ b/src/modinfo.h @@ -354,10 +354,15 @@ public: virtual QString getDescription() const = 0; /** - * @return manually set notes for this mod + * @return notes for this mod */ virtual QString notes() const = 0; + /** + * @return creation time of this mod + */ + virtual QDateTime creationTime() const = 0; + /** * @return nexus description of the mod (html) */ @@ -669,6 +674,11 @@ public: */ virtual QString notes() const; + /** + * @return time this mod was created (file time of the directory) + */ + virtual QDateTime creationTime() const; + /** * @return nexus description of the mod (html) */ @@ -729,6 +739,7 @@ private: QString m_Notes; QString m_NexusDescription; + QDateTime m_CreationTime; QDateTime m_LastNexusQuery; int m_NexusID; @@ -742,6 +753,9 @@ private: MOShared::DirectoryEntry **m_DirectoryStructure; + mutable EConflictType m_CurrentConflictState; + mutable QTime m_LastConflictCheck; + }; @@ -797,6 +811,7 @@ public: virtual void endorse(bool) {} virtual QString name() const { return tr("Overwrite"); } virtual QString notes() const { return ""; } + virtual QDateTime creationTime() const { return QDateTime::currentDateTime(); } virtual QString absolutePath() const; virtual MOBase::VersionInfo getNewestVersion() const { return ""; } virtual QString getInstallationFile() const { return ""; } diff --git a/src/modlist.cpp b/src/modlist.cpp index 45bed00a..9c537300 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -178,6 +178,8 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const //return tr("None"); return QVariant(); } + } else if (column == COL_INSTALLTIME) { + return modInfo->creationTime(); } else { return tr("invalid"); } @@ -718,6 +720,7 @@ QString ModList::getColumnName(int column) case COL_PRIORITY: return tr("Priority"); case COL_CATEGORY: return tr("Category"); case COL_MODID: return tr("Nexus ID"); + case COL_INSTALLTIME: return tr("Installation"); default: return tr("unknown"); } } @@ -733,6 +736,7 @@ QString ModList::getColumnToolTip(int column) case COL_CATEGORY: return tr("Category of the mod."); case COL_MODID: return tr("Id of the mod as used on Nexus."); case COL_FLAGS: return tr("Emblemes to highlight things that might require attention."); + case COL_INSTALLTIME: return tr("Time this mod was installed"); default: return tr("unknown"); } } diff --git a/src/modlist.h b/src/modlist.h index 4f1bf85e..069de40b 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -53,6 +53,7 @@ public: COL_CATEGORY, COL_MODID, COL_VERSION, + COL_INSTALLTIME, COL_PRIORITY, COL_LASTCOLUMN = COL_PRIORITY diff --git a/src/shared/directoryentry.cpp b/src/shared/directoryentry.cpp index ceba113d..7897b6aa 100644 --- a/src/shared/directoryentry.cpp +++ b/src/shared/directoryentry.cpp @@ -699,11 +699,12 @@ const FileEntry::Ptr DirectoryEntry::searchFile(const std::wstring &path, const *directory = NULL; } - if ((path.length() == 0) || - (path == L"*")) { + if ((path.length() == 0) || (path == L"*")) { // no file name -> the path ended on a (back-)slash - *directory = this; - return NULL; + if (directory != NULL) { + *directory = this; + } + return FileEntry::Ptr(); } size_t len = path.find_first_of(L"\\/"); @@ -727,9 +728,10 @@ const FileEntry::Ptr DirectoryEntry::searchFile(const std::wstring &path, const return temp->searchFile(path.substr(len + 1), directory); } } - return NULL; + return FileEntry::Ptr(); } + DirectoryEntry *DirectoryEntry::findSubDirectory(const std::wstring &name) const { for (std::vector::const_iterator iter = m_SubDirectories.begin(); iter != m_SubDirectories.end(); ++iter) { @@ -747,7 +749,7 @@ const FileEntry::Ptr DirectoryEntry::findFile(const std::wstring &name) if (iter != m_Files.end()) { return m_FileRegister->getFile(iter->second); } else { - return NULL; + return FileEntry::Ptr(); } } @@ -828,7 +830,7 @@ FileEntry::Ptr FileRegister::getFile(FileEntry::Index index) if (iter != m_Files.end()) { return iter->second; } - return NULL; + return FileEntry::Ptr(); } -- cgit v1.3.1 From 78c4178f2a70bb55bd761efc92d58b8ac0e3747b Mon Sep 17 00:00:00 2001 From: Tannin Date: Sat, 17 Aug 2013 08:49:36 +0200 Subject: - plugins that failed to load are now reported as problems - some wording fixes in the tutorial - updated proxyPython to a modified interface --- src/mainwindow.cpp | 46 ++++- src/mainwindow.h | 14 +- src/mainwindow.ui | 274 +++++++++++++++--------------- src/tutorials/tutorial_firststeps_main.js | 4 +- 4 files changed, 198 insertions(+), 140 deletions(-) (limited to 'src') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 84e5b094..a8f69090 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -988,12 +988,14 @@ void MainWindow::loadPlugins() if (QLibrary::isLibrary(pluginName)) { QPluginLoader pluginLoader(pluginName); if (pluginLoader.instance() == NULL) { + m_UnloadedPlugins.push_back(pluginName); qCritical("failed to load plugin %s: %s", pluginName.toUtf8().constData(), pluginLoader.errorString().toUtf8().constData()); } else { if (registerPlugin(pluginLoader.instance())) { qDebug("loaded plugin \"%s\"", pluginName.toUtf8().constData()); } else { + m_UnloadedPlugins.push_back(pluginName); qWarning("plugin \"%s\" failed to load", pluginName.toUtf8().constData()); } } @@ -1001,6 +1003,8 @@ void MainWindow::loadPlugins() } m_DownloadManager.setSupportedExtensions(m_InstallationManager.getSupportedExtensions()); + + m_DiagnosisPlugins.push_back(this); } IGameInfo &MainWindow::gameInfo() const @@ -1936,6 +1940,46 @@ IDownloadManager *MainWindow::downloadManager() return &m_DownloadManager; } +std::vector MainWindow::activeProblems() const +{ + std::vector problems; + if (m_UnloadedPlugins.size() != 0) { + problems.push_back(PROBLEM_PLUGINSNOTLOADED); + } + return problems; +} + +QString MainWindow::shortDescription(unsigned int key) const +{ + switch (key) { + case PROBLEM_PLUGINSNOTLOADED: { + return tr("Some plugins could not be loaded"); + } break; + } +} + +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:
    "); + foreach (const QString &plugin, m_UnloadedPlugins) { + result += "
  • " + plugin + "
  • "; + } + result += "
      "; + return result; + } break; + } +} + +bool MainWindow::hasGuidedFix(unsigned int key) const +{ + return false; +} + +void MainWindow::startGuidedFix(unsigned int key) const +{ +} void MainWindow::installMod() { @@ -3519,7 +3563,7 @@ void MainWindow::on_actionNexus_triggered() std::wstring nxmPath = ToWString(QApplication::applicationDirPath() + "/nxmhandler.exe"); std::wstring executable = ToWString(QApplication::applicationFilePath()); ::ShellExecuteW(NULL, L"open", nxmPath.c_str(), - (std::wstring(L"reg ") + GameInfo::instance().getGameShortName() + L" " + executable).c_str(), NULL, SW_SHOWNORMAL); + (std::wstring(L"reg ") + GameInfo::instance().getGameShortName() + L" \"" + executable + L"\"").c_str(), NULL, SW_SHOWNORMAL); ::ShellExecuteW(NULL, L"open", GameInfo::instance().getNexusPage().c_str(), NULL, NULL, SW_SHOWNORMAL); ui->tabWidget->setCurrentIndex(4); diff --git a/src/mainwindow.h b/src/mainwindow.h index d7d0a8e7..b70defbe 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -59,9 +59,10 @@ class QToolButton; class ModListSortProxy; class ModListGroupCategoriesProxy; -class MainWindow : public QMainWindow, public MOBase::IOrganizer +class MainWindow : public QMainWindow, public MOBase::IOrganizer, public MOBase::IPluginDiagnose { Q_OBJECT + Q_INTERFACES(MOBase::IPluginDiagnose) public: explicit MainWindow(const QString &exeName, QSettings &initSettings, QWidget *parent = 0); @@ -109,6 +110,12 @@ public: virtual QString resolvePath(const QString &fileName) const; virtual MOBase::IDownloadManager *downloadManager(); + virtual std::vector activeProblems() const; + virtual QString shortDescription(unsigned int key) const; + virtual QString fullDescription(unsigned int key) const; + virtual bool hasGuidedFix(unsigned int key) const; + virtual void startGuidedFix(unsigned int key) const; + void addPrimaryCategoryCandidates(QMenu *primaryCategoryMenu, ModInfo::Ptr info); void saveArchiveList(); @@ -234,6 +241,10 @@ private: static void setupNetworkProxy(bool activate); void activateProxy(bool activate); +private: + + static const unsigned int PROBLEM_PLUGINSNOTLOADED = 1; + private: Ui::MainWindow *ui; @@ -300,6 +311,7 @@ private: MOBase::IGameInfo *m_GameInfo; std::vector m_DiagnosisPlugins; + std::vector m_UnloadedPlugins; private slots: diff --git a/src/mainwindow.ui b/src/mainwindow.ui index fcdbd63c..14f00336 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -413,155 +413,157 @@ p, li { white-space: pre-wrap; } - - - - - - 0 - 0 - - - - - 0 - 40 - - - - - 9 - 75 - true - - - - Pick a program to run. - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + + + + + + + 0 + 0 + + + + + 0 + 40 + + + + + 9 + 75 + true + + + + Pick a program to run. + + + <!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;">Choose the program to run. Once you start using ModOrganizer, you should always run your game and tools from here or through shortcuts created here, otherwise mods installed through MO will not be visible.</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;">You can add new Tools to this list, but I can't promise tools I haven't tested will work.</span></p></body></html> - - - - 32 - 32 - - - - false - - - - - - - - - - 0 - 0 - - - - - 120 - 0 - - - - - 16777215 - 16777215 - - - - - 10 - 75 - true - - - - Run program - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + + + + 32 + 32 + + + + false + + + + + + + + + + 0 + 0 + + + + + 120 + 0 + + + + + 16777215 + 16777215 + + + + + 10 + 75 + true + + + + Run program + + + <!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;">Run the selected program with ModOrganizer enabled.</span></p></body></html> - - - - - - Run - - - - :/MO/gui/run:/MO/gui/run - - - - 36 - 36 - - - - - - - - - 0 - 0 - - - - - 140 - 0 - - - - - 16777215 - 16777215 - - - - - 0 - 0 - - - - Create a shortcut in your start menu or on the desktop to the specified program - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + + + + + + Run + + + + :/MO/gui/run:/MO/gui/run + + + + 36 + 36 + + + + + + + + + 0 + 0 + + + + + 140 + 0 + + + + + 16777215 + 16777215 + + + + + 0 + 0 + + + + Create a shortcut in your start menu or on the desktop to the specified program + + + <!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 creates a start menu shortcut that directly starts the selected program with the MO active.</span></p></body></html> - - - Shortcut - - - - :/MO/gui/link:/MO/gui/link - - - - - - + + + Shortcut + + + + :/MO/gui/link:/MO/gui/link + + + + + + + diff --git a/src/tutorials/tutorial_firststeps_main.js b/src/tutorials/tutorial_firststeps_main.js index 150fde84..e952c95a 100644 --- a/src/tutorials/tutorial_firststeps_main.js +++ b/src/tutorials/tutorial_firststeps_main.js @@ -93,7 +93,7 @@ function getTutorialSteps() function() { tutorial.text = qsTr("...but most contain plugins. These are plugins for the game and are required " +"to add stuff to the game (new weapons, armors, quests, areas, ...). " - +"Please open the \"ESPs\"-tab to get a list of plugins.") + +"Please open the \"Plugins\"-tab to get a list of plugins.") if (tutorialControl.waitForTabOpen("tabWidget", 0)) { highlightItem("tabWidget", true) } else { @@ -118,7 +118,7 @@ function getTutorialSteps() function() { tutorial.text = qsTr("Another special type of files are BSAs. These are bundles of game resources. " - + "Please open the \"BSAs\"-tab.") + + "Please open the \"Archives\"-tab.") if (tutorialControl.waitForTabOpen("tabWidget", 1)) { highlightItem("tabWidget", true) } else { -- cgit v1.3.1