diff options
| author | Tannin <devnull@localhost> | 2013-08-17 08:54:53 +0200 |
|---|---|---|
| committer | Tannin <devnull@localhost> | 2013-08-17 08:54:53 +0200 |
| commit | 87f4e2df260e502bce61783a66e062af1b46e789 (patch) | |
| tree | 1110a6af42356fcbfbe6d8dbea0aceab9550f3e7 /src | |
| parent | 92720131035a86bf06a29d35ebccd980c0178e6b (diff) | |
| parent | 78c4178f2a70bb55bd761efc92d58b8ac0e3747b (diff) | |
Merge
Diffstat (limited to 'src')
| -rw-r--r-- | src/mainwindow.cpp | 129 | ||||
| -rw-r--r-- | src/mainwindow.h | 16 | ||||
| -rw-r--r-- | src/mainwindow.ui | 360 | ||||
| -rw-r--r-- | src/modinfo.cpp | 93 | ||||
| -rw-r--r-- | src/modinfo.h | 17 | ||||
| -rw-r--r-- | src/modlist.cpp | 4 | ||||
| -rw-r--r-- | src/modlist.h | 1 | ||||
| -rw-r--r-- | src/shared/directoryentry.cpp | 16 | ||||
| -rw-r--r-- | src/tutorials/tutorial_firststeps_main.js | 4 |
9 files changed, 413 insertions, 227 deletions
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index bf6c89c6..c4842738 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))); @@ -989,12 +991,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()); } } @@ -1002,6 +1006,8 @@ void MainWindow::loadPlugins() } m_DownloadManager.setSupportedExtensions(m_InstallationManager.getSupportedExtensions()); + + m_DiagnosisPlugins.push_back(this); } IGameInfo &MainWindow::gameInfo() const @@ -1651,7 +1657,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); @@ -1661,6 +1668,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)); } @@ -1669,7 +1677,18 @@ void MainWindow::refreshBSAList() std::sort(items.begin(), items.end(), BySortValue); for (std::vector<std::pair<UINT32, QTreeWidgetItem*> >::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<QTreeWidgetItem*> 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(); @@ -1684,27 +1703,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()); + 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 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)) { + 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) { @@ -1916,6 +1943,46 @@ IDownloadManager *MainWindow::downloadManager() return &m_DownloadManager; } +std::vector<unsigned int> MainWindow::activeProblems() const +{ + std::vector<unsigned int> 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:<ul>"); + foreach (const QString &plugin, m_UnloadedPlugins) { + result += "<li>" + plugin + "</li>"; + } + result += "<ul>"; + return result; + } break; + } +} + +bool MainWindow::hasGuidedFix(unsigned int key) const +{ + return false; +} + +void MainWindow::startGuidedFix(unsigned int key) const +{ +} void MainWindow::installMod() { @@ -2075,7 +2142,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<QAction*>(sender()); @@ -3315,6 +3381,7 @@ void MainWindow::fixMods_clicked() QStringList espFilter("*.esp"); espFilter.append("*.esm"); + // search in data { QDir dataDir(m_GamePath + "/data"); QStringList esps = dataDir.entryList(espFilter); @@ -3326,6 +3393,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); @@ -3339,12 +3407,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<QString, std::vector<QString> >::iterator iter = missingPlugins.find(esp); + if (iter != missingPlugins.end()) { + iter->second.push_back("<overwrite>"); + } + } + } + + ActivateModsDialog dialog(missingPlugins, this); if (dialog.exec() == QDialog::Accepted) { // activate the required mods, then enable all esps std::set<QString> modsToActivate = dialog.getModsToActivate(); for (std::set<QString>::iterator iter = modsToActivate.begin(); iter != modsToActivate.end(); ++iter) { - if (*iter != "<data>") { + if ((*iter != "<data>") && (*iter != "<overwrite>")) { unsigned int modIndex = ModInfo::getIndex(*iter); m_CurrentProfile->setModEnabled(modIndex, true); } @@ -3485,7 +3566,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); @@ -3499,6 +3580,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..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<unsigned int> 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(); @@ -236,6 +243,10 @@ private: private: + static const unsigned int PROBLEM_PLUGINSNOTLOADED = 1; + +private: + Ui::MainWindow *ui; MOBase::TutorialControl m_Tutorial; @@ -300,6 +311,7 @@ private: MOBase::IGameInfo *m_GameInfo; std::vector<MOBase::IPluginDiagnose*> m_DiagnosisPlugins; + std::vector<QString> m_UnloadedPlugins; private slots: @@ -362,6 +374,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..14f00336 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -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>
@@ -404,155 +413,157 @@ p, li { white-space: pre-wrap; } <widget class="QWidget" name="layoutWidget_2">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
- <layout class="QHBoxLayout" name="horizontalLayout_5" stretch="1,0">
- <item>
- <widget class="QComboBox" name="executablesListBox">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>0</width>
- <height>40</height>
- </size>
- </property>
- <property name="font">
- <font>
- <pointsize>9</pointsize>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="toolTip">
- <string>Pick a program to run.</string>
- </property>
- <property name="whatsThis">
- <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+ <widget class="QFrame" name="startGroup">
+ <layout class="QHBoxLayout" name="horizontalLayout_5" stretch="1,0">
+ <item>
+ <widget class="QComboBox" name="executablesListBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>40</height>
+ </size>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>9</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="toolTip">
+ <string>Pick a program to run.</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;">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></string>
- </property>
- <property name="iconSize">
- <size>
- <width>32</width>
- <height>32</height>
- </size>
- </property>
- <property name="frame">
- <bool>false</bool>
- </property>
- </widget>
- </item>
- <item>
- <layout class="QVBoxLayout" name="verticalLayout_12" stretch="0,0">
- <item>
- <widget class="QPushButton" name="startButton">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>120</width>
- <height>0</height>
- </size>
- </property>
- <property name="maximumSize">
- <size>
- <width>16777215</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="font">
- <font>
- <pointsize>10</pointsize>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="toolTip">
- <string>Run program</string>
- </property>
- <property name="whatsThis">
- <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>32</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="frame">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_12" stretch="0,0">
+ <item>
+ <widget class="QPushButton" name="startButton">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>120</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>10</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="toolTip">
+ <string>Run program</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;">Run the selected program with ModOrganizer enabled.</span></p></body></html></string>
- </property>
- <property name="locale">
- <locale language="English" country="UnitedStates"/>
- </property>
- <property name="text">
- <string>Run</string>
- </property>
- <property name="icon">
- <iconset resource="resources.qrc">
- <normaloff>:/MO/gui/run</normaloff>:/MO/gui/run</iconset>
- </property>
- <property name="iconSize">
- <size>
- <width>36</width>
- <height>36</height>
- </size>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="linkButton">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>140</width>
- <height>0</height>
- </size>
- </property>
- <property name="maximumSize">
- <size>
- <width>16777215</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="baseSize">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
- <property name="toolTip">
- <string>Create a shortcut in your start menu or on the desktop to the specified program</string>
- </property>
- <property name="whatsThis">
- <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+ </property>
+ <property name="locale">
+ <locale language="English" country="UnitedStates"/>
+ </property>
+ <property name="text">
+ <string>Run</string>
+ </property>
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/run</normaloff>:/MO/gui/run</iconset>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>36</width>
+ <height>36</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="linkButton">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>140</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="baseSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Create a shortcut in your start menu or on the desktop to the specified program</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 creates a start menu shortcut that directly starts the selected program with the MO active.</span></p></body></html></string>
- </property>
- <property name="text">
- <string>Shortcut</string>
- </property>
- <property name="icon">
- <iconset resource="resources.qrc">
- <normaloff>:/MO/gui/link</normaloff>:/MO/gui/link</iconset>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
+ </property>
+ <property name="text">
+ <string>Shortcut</string>
+ </property>
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/link</normaloff>:/MO/gui/link</iconset>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
</item>
<item>
<widget class="QTabWidget" name="tabWidget">
@@ -719,19 +730,18 @@ 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="QLabel" name="label">
- <property name="text">
- <string>IMPORTANT: You can change the order of BSAs here but installation order of mods has priority over the order specified here!</string>
- </property>
- <property name="wordWrap">
- <bool>true</bool>
- </property>
- </widget>
- </item>
<item>
<widget class="QTreeWidget" name="bsaList">
<property name="contextMenuPolicy">
@@ -749,14 +759,17 @@ BSAs checked here are loaded in such a way that your installation order is obeye <property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
+ <property name="showDropIndicator" stdset="0">
+ <bool>false</bool>
+ </property>
<property name="dragEnabled">
- <bool>true</bool>
+ <bool>false</bool>
</property>
<property name="dragDropOverwriteMode">
<bool>false</bool>
</property>
<property name="dragDropMode">
- <enum>QAbstractItemView::InternalMove</enum>
+ <enum>QAbstractItemView::NoDragDrop</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::IgnoreAction</enum>
@@ -768,10 +781,10 @@ BSAs checked here are loaded in such a way that your installation order is obeye <enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="indentation">
- <number>0</number>
+ <number>20</number>
</property>
<property name="itemsExpandable">
- <bool>false</bool>
+ <bool>true</bool>
</property>
<attribute name="headerDefaultSectionSize">
<number>200</number>
@@ -788,6 +801,16 @@ BSAs checked here are loaded in such a way that your installation order is obeye </column>
</widget>
</item>
+ <item>
+ <widget class="QLabel" name="bsaWarning">
+ <property name="text">
+ <string><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></string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
<widget class="QWidget" name="dataTab">
@@ -795,7 +818,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>
@@ -865,7 +897,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>
@@ -894,7 +935,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>
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<FileEntry::Ptr> files = origin.getFiles(); - for (auto iter = files.begin(); iter != files.end() && (!overwrite || !overwritten || !regular); ++iter) { - const std::vector<int> &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<FileEntry::Ptr> files = origin.getFiles(); + for (auto iter = files.begin(); iter != files.end() && (!overwrite || !overwritten || !regular); ++iter) { + const std::vector<int> &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,11 +354,16 @@ 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) */ virtual QString getNexusDescription() const = 0; @@ -670,6 +675,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) */ QString getNexusDescription() const; @@ -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 76912b66..802c3696 100644 --- a/src/shared/directoryentry.cpp +++ b/src/shared/directoryentry.cpp @@ -704,11 +704,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"\\/");
@@ -732,9 +733,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<DirectoryEntry*>::const_iterator iter = m_SubDirectories.begin(); iter != m_SubDirectories.end(); ++iter) {
@@ -752,7 +754,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();
}
}
@@ -833,7 +835,7 @@ FileEntry::Ptr FileRegister::getFile(FileEntry::Index index) if (iter != m_Files.end()) {
return iter->second;
}
- return NULL;
+ return FileEntry::Ptr();
}
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 {
|
