diff options
| author | Brian Munro <brian.alexander.munro@gmail.com> | 2018-08-02 09:15:12 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-08-02 09:15:12 +0200 |
| commit | 9a3a15b1f6339589be97e2546b7d532d30abc292 (patch) | |
| tree | 2776d6834b92fdc95b5b26ab43e9e743e10c1128 /src | |
| parent | 886fb10288baf4f52af2ad812a1c2121e138a16e (diff) | |
| parent | 1ea43586d8eb304d8e91bf7f1480d7e4db5ef05f (diff) | |
Merge pull request #454 from Modorganizer2/Develop
Release 2.1.4
Diffstat (limited to 'src')
42 files changed, 2211 insertions, 1206 deletions
diff --git a/src/downloadlist.cpp b/src/downloadlist.cpp index f13cdef1..1e31973d 100644 --- a/src/downloadlist.cpp +++ b/src/downloadlist.cpp @@ -40,7 +40,7 @@ int DownloadList::rowCount(const QModelIndex&) const int DownloadList::columnCount(const QModelIndex&) const
{
- return 3;
+ return 4;
}
@@ -63,6 +63,7 @@ QVariant DownloadList::headerData(int section, Qt::Orientation orientation, int switch (section) {
case COL_NAME: return tr("Name");
case COL_FILETIME: return tr("Filetime");
+ case COL_SIZE: return tr("Size");
default: return tr("Done");
}
} else {
diff --git a/src/downloadlist.h b/src/downloadlist.h index 2316dddc..e8833f0f 100644 --- a/src/downloadlist.h +++ b/src/downloadlist.h @@ -39,7 +39,8 @@ public: enum EColumn {
COL_NAME = 0,
COL_FILETIME,
- COL_STATUS
+ COL_STATUS,
+ COL_SIZE
};
public:
diff --git a/src/downloadlistsortproxy.cpp b/src/downloadlistsortproxy.cpp index 2780f973..f791617a 100644 --- a/src/downloadlistsortproxy.cpp +++ b/src/downloadlistsortproxy.cpp @@ -47,6 +47,8 @@ bool DownloadListSortProxy::lessThan(const QModelIndex &left, return m_Manager->getFileTime(leftIndex) < m_Manager->getFileTime(rightIndex);
} else if (left.column() == DownloadList::COL_STATUS) {
return m_Manager->getState(leftIndex) < m_Manager->getState(rightIndex);
+ } else if(left.column() == DownloadList::COL_SIZE){
+ return m_Manager->getFileSize(leftIndex) < m_Manager->getFileSize(rightIndex);
} else {
return leftIndex < rightIndex;
}
diff --git a/src/downloadlistwidget.cpp b/src/downloadlistwidget.cpp index 2af74cc2..ad694107 100644 --- a/src/downloadlistwidget.cpp +++ b/src/downloadlistwidget.cpp @@ -82,11 +82,30 @@ void DownloadListWidgetDelegate::drawCache(QPainter *painter, const QStyleOption {
QRect rect = option.rect;
rect.setLeft(0);
- rect.setWidth(m_View->columnWidth(0) + m_View->columnWidth(1) + m_View->columnWidth(2));
+ rect.setWidth(m_View->columnWidth(0) + m_View->columnWidth(1) + m_View->columnWidth(2) + m_View->columnWidth(3));
painter->drawPixmap(rect, cache);
}
+QString DownloadListWidgetDelegate::sizeFormat(quint64 size) const
+{
+ qreal calc = size;
+ QStringList list;
+ list << "KB" << "MB" << "GB" << "TB";
+
+ QStringListIterator i(list);
+ QString unit("byte(s)");
+
+ while (calc >= 1024.0 && i.hasNext())
+ {
+ unit = i.next();
+ calc /= 1024.0;
+ }
+
+ return QString().setNum(calc, 'f', 2) + " " + unit;
+}
+
+
void DownloadListWidgetDelegate::paintPendingDownload(int downloadIndex) const
{
std::tuple<QString, int, int> nexusids = m_Manager->getPendingDownload(downloadIndex);
@@ -106,9 +125,9 @@ void DownloadListWidgetDelegate::paintRegularDownload(int downloadIndex) const name.append("...");
}
m_NameLabel->setText(name);
- m_SizeLabel->setText(QString::number(m_Manager->getFileSize(downloadIndex) / 1024));
+ m_SizeLabel->setText(sizeFormat(m_Manager->getFileSize(downloadIndex) ));
DownloadManager::DownloadState state = m_Manager->getState(downloadIndex);
- if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR)) {
+ if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR) || (state == DownloadManager::STATE_PAUSING)) {
QPalette labelPalette;
m_InstallLabel->setVisible(true);
m_Progress->setVisible(false);
@@ -174,7 +193,7 @@ void DownloadListWidgetDelegate::paint(QPainter *painter, const QStyleOptionView return;
}
- m_ItemWidget->resize(QSize(m_View->columnWidth(0) + m_View->columnWidth(1) + m_View->columnWidth(2), option.rect.height()));
+ m_ItemWidget->resize(QSize(m_View->columnWidth(0) + m_View->columnWidth(1) + m_View->columnWidth(2) + m_View->columnWidth(3), option.rect.height()));
int downloadIndex = index.data().toInt();
@@ -226,7 +245,11 @@ void DownloadListWidgetDelegate::issueQueryInfo() void DownloadListWidgetDelegate::issueDelete()
{
- emit removeDownload(m_ContextRow, true);
+ if (QMessageBox::question(nullptr, tr("Delete Files?"),
+ tr("This will permanently delete the selected download."),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ emit removeDownload(m_ContextRow, true);
+ }
}
void DownloadListWidgetDelegate::issueRemoveFromView()
@@ -236,7 +259,22 @@ void DownloadListWidgetDelegate::issueRemoveFromView() void DownloadListWidgetDelegate::issueRestoreToView()
{
- emit restoreDownload(m_ContextRow);
+ emit restoreDownload(m_ContextRow);
+}
+
+void DownloadListWidgetDelegate::issueRestoreToViewAll()
+{
+ emit restoreDownload(-1);
+}
+
+void DownloadListWidgetDelegate::issueVisitOnNexus()
+{
+ emit visitOnNexus(m_ContextRow);
+}
+
+void DownloadListWidgetDelegate::issueOpenInDownloadsFolder()
+{
+ emit openInDownloadsFolder(m_ContextRow);
}
void DownloadListWidgetDelegate::issueCancel()
@@ -256,7 +294,7 @@ void DownloadListWidgetDelegate::issueResume() void DownloadListWidgetDelegate::issueDeleteAll()
{
- if (QMessageBox::question(nullptr, tr("Are you sure?"),
+ if (QMessageBox::question(nullptr, tr("Delete Files?"),
tr("This will remove all finished downloads from this list and from disk."),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
emit removeDownload(-1, true);
@@ -265,13 +303,22 @@ void DownloadListWidgetDelegate::issueDeleteAll() void DownloadListWidgetDelegate::issueDeleteCompleted()
{
- if (QMessageBox::question(nullptr, tr("Are you sure?"),
+ if (QMessageBox::question(nullptr, tr("Delete Files?"),
tr("This will remove all installed downloads from this list and from disk."),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
emit removeDownload(-2, true);
}
}
+void DownloadListWidgetDelegate::issueDeleteUninstalled()
+{
+ if (QMessageBox::question(nullptr, tr("Delete Files?"),
+ tr("This will remove all uninstalled downloads from this list and from disk."),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ emit removeDownload(-3, true);
+ }
+}
+
void DownloadListWidgetDelegate::issueRemoveFromViewAll()
{
if (QMessageBox::question(nullptr, tr("Are you sure?"),
@@ -290,6 +337,15 @@ void DownloadListWidgetDelegate::issueRemoveFromViewCompleted() }
}
+void DownloadListWidgetDelegate::issueRemoveFromViewUninstalled()
+{
+ if (QMessageBox::question(nullptr, tr("Are you sure?"),
+ tr("This will remove all uninstalled downloads from this list (but NOT from disk)."),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ emit removeDownload(-3, false);
+ }
+}
+
bool DownloadListWidgetDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
const QStyleOptionViewItem &option, const QModelIndex &index)
{
@@ -298,7 +354,7 @@ bool DownloadListWidgetDelegate::editorEvent(QEvent *event, QAbstractItemModel * QModelIndex sourceIndex = qobject_cast<QSortFilterProxyModel*>(model)->mapToSource(index);
if (m_Manager->getState(sourceIndex.row()) >= DownloadManager::STATE_READY) {
emit installDownload(sourceIndex.row());
- } else if (m_Manager->getState(sourceIndex.row()) >= DownloadManager::STATE_PAUSED) {
+ } else if ((m_Manager->getState(sourceIndex.row()) >= DownloadManager::STATE_PAUSED) || (m_Manager->getState(sourceIndex.row()) == DownloadManager::STATE_PAUSING)) {
emit resumeDownload(sourceIndex.row());
}
return true;
@@ -315,7 +371,14 @@ bool DownloadListWidgetDelegate::editorEvent(QEvent *event, QAbstractItemModel * menu.addAction(tr("Install"), this, SLOT(issueInstall()));
if (m_Manager->isInfoIncomplete(m_ContextRow)) {
menu.addAction(tr("Query Info"), this, SLOT(issueQueryInfo()));
+ }else {
+ menu.addAction(tr("Visit on Nexus"), this,SLOT(issueVisitOnNexus()));
}
+
+ menu.addAction(tr("Show in Folder"), this, SLOT(issueOpenInDownloadsFolder()));
+
+ menu.addSeparator();
+
menu.addAction(tr("Delete"), this, SLOT(issueDelete()));
if (hidden) {
menu.addAction(tr("Un-Hide"), this, SLOT(issueRestoreToView()));
@@ -325,20 +388,30 @@ bool DownloadListWidgetDelegate::editorEvent(QEvent *event, QAbstractItemModel * } else if (state == DownloadManager::STATE_DOWNLOADING){
menu.addAction(tr("Cancel"), this, SLOT(issueCancel()));
menu.addAction(tr("Pause"), this, SLOT(issuePause()));
- } else if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR)) {
- menu.addAction(tr("Remove"), this, SLOT(issueDelete()));
+ menu.addAction(tr("Show in Folder"), this, SLOT(issueOpenInDownloadsFolder()));
+ } else if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR) || (state == DownloadManager::STATE_PAUSING)) {
+ menu.addAction(tr("Delete"), this, SLOT(issueDelete()));
menu.addAction(tr("Resume"), this, SLOT(issueResume()));
+ menu.addAction(tr("Show in Folder"), this, SLOT(issueOpenInDownloadsFolder()));
}
menu.addSeparator();
}
menu.addAction(tr("Delete Installed..."), this, SLOT(issueDeleteCompleted()));
+ menu.addAction(tr("Delete Uninstalled..."), this, SLOT(issueDeleteUninstalled()));
menu.addAction(tr("Delete All..."), this, SLOT(issueDeleteAll()));
- if (!hidden) {
- menu.addSeparator();
- menu.addAction(tr("Hide Installed..."), this, SLOT(issueRemoveFromViewCompleted()));
- menu.addAction(tr("Hide All..."), this, SLOT(issueRemoveFromViewAll()));
- }
+
+ if (!hidden) {
+ menu.addSeparator();
+ menu.addAction(tr("Hide Installed..."), this, SLOT(issueRemoveFromViewCompleted()));
+ menu.addAction(tr("Hide Uninstalled..."), this, SLOT(issueRemoveFromViewUninstalled()));
+ menu.addAction(tr("Hide All..."), this, SLOT(issueRemoveFromViewAll()));
+ }
+ if (hidden) {
+ menu.addSeparator();
+ menu.addAction(tr("Un-Hide All..."), this, SLOT(issueRestoreToViewAll()));
+ }
+
menu.exec(mouseEvent->globalPos());
event->accept();
diff --git a/src/downloadlistwidget.h b/src/downloadlistwidget.h index c1dfe4cd..2dd73e73 100644 --- a/src/downloadlistwidget.h +++ b/src/downloadlistwidget.h @@ -71,14 +71,18 @@ signals: void cancelDownload(int index);
void pauseDownload(int index);
void resumeDownload(int index);
+ void visitOnNexus(int index);
+ void openInDownloadsFolder(int index);
protected:
+ QString sizeFormat(quint64 size) const;
bool editorEvent(QEvent *event, QAbstractItemModel *model,
const QStyleOptionViewItem &option, const QModelIndex &index);
private:
+
void drawCache(QPainter *painter, const QStyleOptionViewItem &option, const QPixmap &cache) const;
private slots:
@@ -87,13 +91,18 @@ private slots: void issueDelete();
void issueRemoveFromView();
void issueRestoreToView();
+ void issueRestoreToViewAll();
+ void issueVisitOnNexus();
+ void issueOpenInDownloadsFolder();
void issueCancel();
void issuePause();
void issueResume();
void issueDeleteAll();
void issueDeleteCompleted();
+ void issueDeleteUninstalled();
void issueRemoveFromViewAll();
void issueRemoveFromViewCompleted();
+ void issueRemoveFromViewUninstalled();
void issueQueryInfo();
void stateChanged(int row, DownloadManager::DownloadState);
diff --git a/src/downloadlistwidget.ui b/src/downloadlistwidget.ui index 7a6ce8ba..9e238509 100644 --- a/src/downloadlistwidget.ui +++ b/src/downloadlistwidget.ui @@ -87,6 +87,9 @@ <property name="text">
<string notr="true">KB</string>
</property>
+ <property name="visible">
+ <bool>false</bool>
+ </property>
</widget>
</item>
</layout>
diff --git a/src/downloadlistwidgetcompact.cpp b/src/downloadlistwidgetcompact.cpp index 898d400a..663a224e 100644 --- a/src/downloadlistwidgetcompact.cpp +++ b/src/downloadlistwidgetcompact.cpp @@ -81,18 +81,35 @@ void DownloadListWidgetCompactDelegate::drawCache(QPainter *painter, const QStyl {
QRect rect = option.rect;
rect.setLeft(0);
- rect.setWidth(m_View->columnWidth(0) + m_View->columnWidth(1) + m_View->columnWidth(2));
+ rect.setWidth(m_View->columnWidth(0) + m_View->columnWidth(1) + m_View->columnWidth(2) + m_View->columnWidth(3));
painter->drawPixmap(rect, cache);
}
+QString DownloadListWidgetCompactDelegate::sizeFormat(quint64 size) const
+{
+ qreal calc = size;
+ QStringList list;
+ list << "KB" << "MB" << "GB" << "TB";
+
+ QStringListIterator i(list);
+ QString unit("byte(s)");
+
+ while (calc >= 1024.0 && i.hasNext())
+ {
+ unit = i.next();
+ calc /= 1024.0;
+ }
+
+ return QString().setNum(calc, 'f', 2) + " " + unit;
+}
void DownloadListWidgetCompactDelegate::paintPendingDownload(int downloadIndex) const
{
std::tuple<QString, int, int> nexusids = m_Manager->getPendingDownload(downloadIndex);
m_NameLabel->setText(tr("< game %1 mod %2 file %3 >").arg(std::get<0>(nexusids)).arg(std::get<1>(nexusids)).arg(std::get<2>(nexusids)));
- if (m_SizeLabel != nullptr) {
- m_SizeLabel->setText("???");
- }
+ //if (m_SizeLabel != nullptr) {
+ // m_SizeLabel->setText("???");
+ //}
m_DoneLabel->setVisible(true);
m_DoneLabel->setText(tr("Pending"));
m_Progress->setVisible(false);
@@ -110,11 +127,15 @@ void DownloadListWidgetCompactDelegate::paintRegularDownload(int downloadIndex) DownloadManager::DownloadState state = m_Manager->getState(downloadIndex);
- if ((m_SizeLabel != nullptr) && (state >= DownloadManager::STATE_READY)) {
- m_SizeLabel->setText(QString::number(m_Manager->getFileSize(downloadIndex) / 1048576));
+ if (m_SizeLabel != nullptr) {
+ m_SizeLabel->setText(sizeFormat(m_Manager->getFileSize(downloadIndex)) + " ");
+ m_SizeLabel->setVisible(true);
}
+ //else {
+ // m_SizeLabel->setVisible(false);
+ //}
- if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR)) {
+ if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR) || (state == DownloadManager::STATE_PAUSING)) {
m_DoneLabel->setVisible(true);
m_Progress->setVisible(false);
m_DoneLabel->setText(QString("%1<img src=\":/MO/gui/inactive\">").arg(tr("Paused")));
@@ -153,7 +174,7 @@ void DownloadListWidgetCompactDelegate::paint(QPainter *painter, const QStyleOpt return;
}
- m_ItemWidget->resize(QSize(m_View->columnWidth(0) + m_View->columnWidth(1) + m_View->columnWidth(2), option.rect.height()));
+ m_ItemWidget->resize(QSize(m_View->columnWidth(0) + m_View->columnWidth(1) + m_View->columnWidth(2) + m_View->columnWidth(3), option.rect.height()));
if (index.row() % 2 == 1) {
m_ItemWidget->setBackgroundRole(QPalette::AlternateBase);
} else {
@@ -209,7 +230,11 @@ void DownloadListWidgetCompactDelegate::issueQueryInfo() void DownloadListWidgetCompactDelegate::issueDelete()
{
- emit removeDownload(m_ContextIndex.row(), true);
+ if (QMessageBox::question(nullptr, tr("Are you sure?"),
+ tr("This will permanently delete the selected download."),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ emit removeDownload(m_ContextIndex.row(), true);
+ }
}
void DownloadListWidgetCompactDelegate::issueRemoveFromView()
@@ -217,11 +242,27 @@ void DownloadListWidgetCompactDelegate::issueRemoveFromView() emit removeDownload(m_ContextIndex.row(), false);
}
+void DownloadListWidgetCompactDelegate::issueVisitOnNexus()
+{
+ emit visitOnNexus(m_ContextIndex.row());
+}
+
+void DownloadListWidgetCompactDelegate::issueOpenInDownloadsFolder()
+{
+ emit openInDownloadsFolder(m_ContextIndex.row());
+}
+
void DownloadListWidgetCompactDelegate::issueRestoreToView()
{
- emit restoreDownload(m_ContextIndex.row());
+ emit restoreDownload(m_ContextIndex.row());
}
+void DownloadListWidgetCompactDelegate::issueRestoreToViewAll()
+{
+ emit restoreDownload(-1);
+}
+
+
void DownloadListWidgetCompactDelegate::issueCancel()
{
emit cancelDownload(m_ContextIndex.row());
@@ -255,6 +296,15 @@ void DownloadListWidgetCompactDelegate::issueDeleteCompleted() }
}
+void DownloadListWidgetCompactDelegate::issueDeleteUninstalled()
+{
+ if (QMessageBox::question(nullptr, tr("Are you sure?"),
+ tr("This will remove all uninstalled downloads from this list and from disk."),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ emit removeDownload(-3, true);
+ }
+}
+
void DownloadListWidgetCompactDelegate::issueRemoveFromViewAll()
{
if (QMessageBox::question(nullptr, tr("Are you sure?"),
@@ -273,6 +323,15 @@ void DownloadListWidgetCompactDelegate::issueRemoveFromViewCompleted() }
}
+void DownloadListWidgetCompactDelegate::issueRemoveFromViewUninstalled()
+{
+ if (QMessageBox::question(nullptr, tr("Are you sure?"),
+ tr("This will permanently remove all uninstalled downloads from this list (but NOT from disk)."),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ emit removeDownload(-3, false);
+ }
+}
+
bool DownloadListWidgetCompactDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
const QStyleOptionViewItem &option, const QModelIndex &index)
@@ -282,7 +341,7 @@ bool DownloadListWidgetCompactDelegate::editorEvent(QEvent *event, QAbstractItem QModelIndex sourceIndex = qobject_cast<QSortFilterProxyModel*>(model)->mapToSource(index);
if (m_Manager->getState(sourceIndex.row()) >= DownloadManager::STATE_READY) {
emit installDownload(sourceIndex.row());
- } else if (m_Manager->getState(sourceIndex.row()) >= DownloadManager::STATE_PAUSED) {
+ } else if ((m_Manager->getState(sourceIndex.row()) >= DownloadManager::STATE_PAUSED) || (m_Manager->getState(sourceIndex.row()) == DownloadManager::STATE_PAUSING)) {
emit resumeDownload(sourceIndex.row());
}
return true;
@@ -299,7 +358,11 @@ bool DownloadListWidgetCompactDelegate::editorEvent(QEvent *event, QAbstractItem menu.addAction(tr("Install"), this, SLOT(issueInstall()));
if (m_Manager->isInfoIncomplete(m_ContextIndex.row())) {
menu.addAction(tr("Query Info"), this, SLOT(issueQueryInfo()));
+ }else {
+ menu.addAction(tr("Visit on Nexus"), this, SLOT(issueVisitOnNexus()));
}
+ menu.addAction(tr("Show in Folder"), this, SLOT(issueOpenInDownloadsFolder()));
+ menu.addSeparator();
menu.addAction(tr("Delete"), this, SLOT(issueDelete()));
if (hidden) {
menu.addAction(tr("Un-Hide"), this, SLOT(issueRestoreToView()));
@@ -309,20 +372,27 @@ bool DownloadListWidgetCompactDelegate::editorEvent(QEvent *event, QAbstractItem } else if (state == DownloadManager::STATE_DOWNLOADING){
menu.addAction(tr("Cancel"), this, SLOT(issueCancel()));
menu.addAction(tr("Pause"), this, SLOT(issuePause()));
- } else if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR)) {
+ menu.addAction(tr("Show in Folder"), this, SLOT(issueOpenInDownloadsFolder()));
+ } else if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR) || (state == DownloadManager::STATE_PAUSING)) {
menu.addAction(tr("Remove"), this, SLOT(issueDelete()));
menu.addAction(tr("Resume"), this, SLOT(issueResume()));
+ menu.addAction(tr("Show in Folder"), this, SLOT(issueOpenInDownloadsFolder()));
}
-
menu.addSeparator();
}
menu.addAction(tr("Delete Installed..."), this, SLOT(issueDeleteCompleted()));
+ menu.addAction(tr("Delete Uninstalled..."), this, SLOT(issueDeleteUninstalled()));
menu.addAction(tr("Delete All..."), this, SLOT(issueDeleteAll()));
if (!hidden) {
menu.addSeparator();
menu.addAction(tr("Hide Installed..."), this, SLOT(issueRemoveFromViewCompleted()));
+ menu.addAction(tr("Hide Uninstalled..."), this, SLOT(issueRemoveFromViewUninstalled()));
menu.addAction(tr("Hide All..."), this, SLOT(issueRemoveFromViewAll()));
}
+ if (hidden) {
+ menu.addSeparator();
+ menu.addAction(tr("Un-Hide All..."), this, SLOT(issueRestoreToViewAll()));
+ }
menu.exec(mouseEvent->globalPos());
event->accept();
@@ -335,4 +405,3 @@ bool DownloadListWidgetCompactDelegate::editorEvent(QEvent *event, QAbstractItem return QItemDelegate::editorEvent(event, model, option, index);
}
-
diff --git a/src/downloadlistwidgetcompact.h b/src/downloadlistwidgetcompact.h index bf855d5f..b1b3c617 100644 --- a/src/downloadlistwidgetcompact.h +++ b/src/downloadlistwidgetcompact.h @@ -35,7 +35,7 @@ class DownloadListWidgetCompact; class DownloadListWidgetCompact : public QWidget
{
Q_OBJECT
-
+
public:
explicit DownloadListWidgetCompact(QWidget *parent = 0);
~DownloadListWidgetCompact();
@@ -69,9 +69,12 @@ signals: void cancelDownload(int index);
void pauseDownload(int index);
void resumeDownload(int index);
+ void visitOnNexus(int index);
+ void openInDownloadsFolder(int index);
protected:
+ QString sizeFormat(quint64 size) const;
bool editorEvent(QEvent *event, QAbstractItemModel *model,
const QStyleOptionViewItem &option, const QModelIndex &index);
@@ -87,13 +90,18 @@ private slots: void issueDelete();
void issueRemoveFromView();
void issueRestoreToView();
+ void issueRestoreToViewAll();
+ void issueVisitOnNexus();
+ void issueOpenInDownloadsFolder();
void issueCancel();
void issuePause();
void issueResume();
void issueDeleteAll();
void issueDeleteCompleted();
+ void issueDeleteUninstalled();
void issueRemoveFromViewAll();
void issueRemoveFromViewCompleted();
+ void issueRemoveFromViewUninstalled();
void issueQueryInfo();
void stateChanged(int row, DownloadManager::DownloadState);
@@ -119,4 +127,3 @@ private: };
#endif // DOWNLOADLISTWIDGETCOMPACT_H
-
diff --git a/src/downloadlistwidgetcompact.ui b/src/downloadlistwidgetcompact.ui index b43f1fb3..a3fa958c 100644 --- a/src/downloadlistwidgetcompact.ui +++ b/src/downloadlistwidgetcompact.ui @@ -19,7 +19,7 @@ <property name="autoFillBackground">
<bool>true</bool>
</property>
- <layout class="QHBoxLayout" name="horizontalLayout">
+ <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0,0,0">
<property name="spacing">
<number>2</number>
</property>
@@ -58,19 +58,26 @@ </widget>
</item>
<item>
- <spacer name="horizontalSpacer">
+ <spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
- <width>40</width>
+ <width>10</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
+ <widget class="QLabel" name="sizeLabel">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QLabel" name="doneLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index bfc4de3e..33899f46 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -36,6 +36,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QFileInfo>
#include <QRegExp>
#include <QDirIterator>
+#include <QDesktopServices>
#include <QInputDialog>
#include <QMessageBox>
#include <QCoreApplication>
@@ -54,6 +55,7 @@ using namespace MOBase; static const char UNFINISHED[] = ".unfinished";
unsigned int DownloadManager::DownloadInfo::s_NextDownloadID = 1U;
+int DownloadManager::m_DirWatcherDisabler = 0;
DownloadManager::DownloadInfo *DownloadManager::DownloadInfo::createNew(const ModRepositoryFileInfo *fileInfo, const QStringList &URLs)
@@ -62,7 +64,7 @@ DownloadManager::DownloadInfo *DownloadManager::DownloadInfo::createNew(const Mo info->m_DownloadID = s_NextDownloadID++;
info->m_StartTime.start();
info->m_PreResumeSize = 0LL;
- info->m_Progress = std::make_pair<int, QString>(0, "0 bytes/sec");
+ info->m_Progress = std::make_pair<int, QString>(0, " 0.0 Bytes/s ");
info->m_ResumePos = 0;
info->m_FileInfo = new ModRepositoryFileInfo(*fileInfo);
info->m_Urls = URLs;
@@ -70,6 +72,7 @@ DownloadManager::DownloadInfo *DownloadManager::DownloadInfo::createNew(const Mo info->m_Tries = AUTOMATIC_RETRIES;
info->m_State = STATE_STARTED;
info->m_TaskProgressId = TaskProgressManager::instance().getId();
+ info->m_Reply = nullptr;
return info;
}
@@ -136,10 +139,30 @@ DownloadManager::DownloadInfo *DownloadManager::DownloadInfo::createFromMeta(con info->m_FileInfo->fileCategory = metaFile.value("fileCategory", 0).toInt();
info->m_FileInfo->repository = metaFile.value("repository", "Nexus").toString();
info->m_FileInfo->userData = metaFile.value("userData").toMap();
+ info->m_Reply = nullptr;
return info;
}
+void DownloadManager::startDisableDirWatcher()
+{
+ DownloadManager::m_DirWatcherDisabler++;
+}
+
+
+void DownloadManager::endDisableDirWatcher()
+{
+ if (DownloadManager::m_DirWatcherDisabler > 0)
+ {
+ if (DownloadManager::m_DirWatcherDisabler == 1)
+ QCoreApplication::processEvents();
+ DownloadManager::m_DirWatcherDisabler--;
+ }
+ else {
+ DownloadManager::m_DirWatcherDisabler = 0;
+ }
+}
+
void DownloadManager::DownloadInfo::setName(QString newName, bool renameFile)
{
QString oldMetaFileName = QString("%1.meta").arg(m_FileName);
@@ -182,6 +205,9 @@ DownloadManager::DownloadManager(NexusInterface *nexusInterface, QObject *parent m_DateExpression("/Date\\((\\d+)\\)/")
{
connect(&m_DirWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(directoryChanged(QString)));
+ m_TimeoutTimer.setSingleShot(false);
+ //connect(&m_TimeoutTimer, SIGNAL(timeout()), this, SLOT(checkDownloadTimeout()));
+ m_TimeoutTimer.start(5 * 1000);
}
@@ -204,8 +230,20 @@ bool DownloadManager::downloadsInProgress() return false;
}
+bool DownloadManager::downloadsInProgressNoPause()
+{
+ for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); iter != m_ActiveDownloads.end(); ++iter) {
+ if ((*iter)->m_State < STATE_READY && (*iter)->m_State != STATE_PAUSED) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
void DownloadManager::pauseAll()
{
+
// first loop: pause all downloads
for (int i = 0; i < m_ActiveDownloads.count(); ++i) {
if (m_ActiveDownloads[i]->m_State < STATE_READY) {
@@ -233,6 +271,7 @@ void DownloadManager::pauseAll() ::Sleep(100);
}
}
+
}
@@ -271,9 +310,17 @@ void DownloadManager::setPluginContainer(PluginContainer *pluginContainer) m_NexusInterface->setPluginContainer(pluginContainer);
}
+
+
+
+
+
void DownloadManager::refreshList()
{
try {
+ //avoid triggering other refreshes
+ startDisableDirWatcher();
+
int downloadsBefore = m_ActiveDownloads.size();
// remove finished downloads
@@ -330,10 +377,14 @@ void DownloadManager::refreshList() }
}
- if (m_ActiveDownloads.size() != downloadsBefore) {
+ //if (m_ActiveDownloads.size() != downloadsBefore) {
qDebug("downloads after refresh: %d", m_ActiveDownloads.size());
- }
+ //}
emit update(-1);
+
+ //let watcher trigger refreshes again
+ endDisableDirWatcher();
+
} catch (const std::bad_alloc&) {
reportError(tr("Memory allocation error (in refreshing directory)."));
}
@@ -351,6 +402,7 @@ bool DownloadManager::addDownload(const QStringList &URLs, QString gameName, QUrl preferredUrl = QUrl::fromEncoded(URLs.first().toLocal8Bit());
qDebug("selected download url: %s", qPrintable(preferredUrl.toString()));
QNetworkRequest request(preferredUrl);
+ request.setHeader(QNetworkRequest::UserAgentHeader, m_NexusInterface->getAccessManager()->userAgent());
return addDownload(m_NexusInterface->getAccessManager()->get(request), URLs, fileName, gameName, modID, fileID, fileInfo);
}
@@ -382,7 +434,10 @@ bool DownloadManager::addDownload(QNetworkReply *reply, const QStringList &URLs, baseName = dispoName;
}
}
+
+ startDisableDirWatcher();
newDownload->setName(getDownloadFileName(baseName), false);
+ endDisableDirWatcher();
startDownload(reply, newDownload, false);
// emit update(-1);
@@ -452,7 +507,9 @@ void DownloadManager::startDownload(QNetworkReply *reply, DownloadInfo *newDownl else
setState(newDownload, STATE_CANCELING);
} else {
+ startDisableDirWatcher();
newDownload->setName(getDownloadFileName(newDownload->m_FileName, true), true);
+ endDisableDirWatcher();
if (newDownload->m_State == STATE_PAUSED)
resumeDownload(indexByName(newDownload->m_FileName));
else
@@ -524,6 +581,9 @@ void DownloadManager::addNXMDownload(const QString &url) void DownloadManager::removeFile(int index, bool deleteFile)
{
+ //Avoid triggering refreshes from DirWatcher
+ startDisableDirWatcher();
+
if (index >= m_ActiveDownloads.size()) {
throw MyException(tr("remove: invalid download index %1").arg(index));
}
@@ -534,6 +594,7 @@ void DownloadManager::removeFile(int index, bool deleteFile) (download->m_State == STATE_DOWNLOADING)) {
// shouldn't have been possible
qCritical("tried to remove active download");
+ endDisableDirWatcher();
return;
}
@@ -544,6 +605,7 @@ void DownloadManager::removeFile(int index, bool deleteFile) if (deleteFile) {
if (!shellDelete(QStringList(filePath), true)) {
reportError(tr("failed to delete %1").arg(filePath));
+ endDisableDirWatcher();
return;
}
@@ -553,8 +615,11 @@ void DownloadManager::removeFile(int index, bool deleteFile) }
} else {
QSettings metaSettings(filePath.append(".meta"), QSettings::IniFormat);
- metaSettings.setValue("removed", true);
+ if(!download->m_Hidden)
+ metaSettings.setValue("removed", true);
}
+
+ endDisableDirWatcher();
}
class LessThanWrapper
@@ -591,34 +656,64 @@ void DownloadManager::refreshAlphabeticalTranslation() void DownloadManager::restoreDownload(int index)
{
- if ((index < 0) || (index >= m_ActiveDownloads.size())) {
- throw MyException(tr("restore: invalid download index: %1").arg(index));
- }
- DownloadInfo *download = m_ActiveDownloads.at(index);
- download->m_Hidden = false;
+ if (index < 0) {
+ DownloadState minState = STATE_READY ;
+ index = 0;
- QString filePath = m_OutputDirectory + "/" + download->m_FileName;
+ for (QVector<DownloadInfo*>::const_iterator iter = m_ActiveDownloads.begin(); iter != m_ActiveDownloads.end(); ++iter ) {
- QSettings metaSettings(filePath.append(".meta"), QSettings::IniFormat);
- metaSettings.setValue("removed", false);
+ if ((*iter)->m_State >= minState) {
+ restoreDownload(index);
+ }
+ index++;
+ }
+ }
+ else {
+ if (index >= m_ActiveDownloads.size()) {
+ throw MyException(tr("restore: invalid download index: %1").arg(index));
+ }
+
+ DownloadInfo *download = m_ActiveDownloads.at(index);
+ if (download->m_Hidden) {
+ download->m_Hidden = false;
+
+ QString filePath = m_OutputDirectory + "/" + download->m_FileName;
+
+ //avoid dirWatcher triggering refreshes
+ startDisableDirWatcher();
+ QSettings metaSettings(filePath.append(".meta"), QSettings::IniFormat);
+ metaSettings.setValue("removed", false);
+
+ endDisableDirWatcher();
+ }
+ }
}
void DownloadManager::removeDownload(int index, bool deleteFile)
{
try {
+ //avoid dirWatcher triggering refreshes
+ startDisableDirWatcher();
+
emit aboutToUpdate();
if (index < 0) {
- DownloadState minState = index == -1 ? STATE_READY : STATE_INSTALLED;
+ DownloadState minState;
+ if (index == -3) {
+ minState = STATE_UNINSTALLED;
+ }
+ else
+ minState = index == -1 ? STATE_READY : STATE_INSTALLED;
+
index = 0;
for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); iter != m_ActiveDownloads.end();) {
if ((*iter)->m_State >= minState) {
removeFile(index, deleteFile);
delete *iter;
iter = m_ActiveDownloads.erase(iter);
- QCoreApplication::processEvents();
+ //QCoreApplication::processEvents();
}
else {
++iter;
@@ -628,6 +723,8 @@ void DownloadManager::removeDownload(int index, bool deleteFile) } else {
if (index >= m_ActiveDownloads.size()) {
reportError(tr("remove: invalid download index %1").arg(index));
+ //emit update(-1);
+ endDisableDirWatcher();
return;
}
@@ -636,9 +733,11 @@ void DownloadManager::removeDownload(int index, bool deleteFile) m_ActiveDownloads.erase(m_ActiveDownloads.begin() + index);
}
emit update(-1);
+ endDisableDirWatcher();
} catch (const std::exception &e) {
qCritical("failed to remove download: %s", e.what());
}
+ refreshList();
}
@@ -695,13 +794,20 @@ void DownloadManager::resumeDownloadInt(int index) DownloadInfo *info = m_ActiveDownloads[index];
// Check for finished download;
- if (info->m_TotalSize <= info->m_Output.size()) {
+ if (info->m_TotalSize <= info->m_Output.size() && info->m_Reply != nullptr
+ && info->m_Reply->isOpen() && info->m_Reply->isFinished() && info->m_State != STATE_ERROR) {
setState(info, STATE_DOWNLOADING);
downloadFinished(index);
return;
}
- if (info->isPausedState()) {
+ if (info->isPausedState() || info->m_State == STATE_PAUSING) {
+ if (info->m_State == STATE_PAUSING) {
+ if (info->m_Output.isOpen()) {
+ info->m_Output.write(info->m_Reply->readAll());
+ setState(info, STATE_PAUSED);
+ }
+ }
if ((info->m_Urls.size() == 0)
|| ((info->m_Urls.size() == 1) && (info->m_Urls[0].size() == 0))) {
emit showMessage(tr("No known download urls. Sorry, this download can't be resumed."));
@@ -712,15 +818,18 @@ void DownloadManager::resumeDownloadInt(int index) }
qDebug("request resume from url %s", qPrintable(info->currentURL()));
QNetworkRequest request(QUrl::fromEncoded(info->currentURL().toLocal8Bit()));
- info->m_ResumePos = info->m_Output.size();
+ request.setHeader(QNetworkRequest::UserAgentHeader, m_NexusInterface->getAccessManager()->userAgent());
+ if (info->m_State != STATE_ERROR) {
+ info->m_ResumePos = info->m_Output.size();
+ QByteArray rangeHeader = "bytes=" + QByteArray::number(info->m_ResumePos) + "-";
+ request.setRawHeader("Range", rangeHeader);
+ }
std::get<0>(info->m_SpeedDiff) = 0;
std::get<1>(info->m_SpeedDiff) = 0;
std::get<2>(info->m_SpeedDiff) = 0;
std::get<3>(info->m_SpeedDiff) = 0;
std::get<4>(info->m_SpeedDiff) = 0;
qDebug("resume at %lld bytes", info->m_ResumePos);
- QByteArray rangeHeader = "bytes=" + QByteArray::number(info->m_ResumePos) + "-";
- request.setRawHeader("Range", rangeHeader);
startDownload(m_NexusInterface->getAccessManager()->get(request), info, true);
}
emit update(index);
@@ -790,6 +899,59 @@ void DownloadManager::queryInfo(int index) setState(info, STATE_FETCHINGMODINFO);
}
+void DownloadManager::visitOnNexus(int index)
+{
+ if ((index < 0) || (index >= m_ActiveDownloads.size())) {
+ reportError(tr("VisitNexus: invalid download index %1").arg(index));
+ return;
+ }
+ DownloadInfo *info = m_ActiveDownloads[index];
+
+ if (info->m_FileInfo->repository != "Nexus") {
+ qWarning("Visiting mod page is currently only possible with Nexus");
+ return;
+ }
+
+ if (info->m_State < DownloadManager::STATE_READY) {
+ // UI shouldn't allow this
+ return;
+ }
+ int modID = info->m_FileInfo->modID;
+
+ QString gameName = info->m_FileInfo->gameName;
+ if (modID > 0) {
+ QDesktopServices::openUrl(QUrl(m_NexusInterface->getModURL(modID, gameName)));
+ }
+ else {
+ emit showMessage(tr("Nexus ID for this Mod is unknown"));
+ }
+}
+
+void DownloadManager::openInDownloadsFolder(int index)
+{
+ if ((index < 0) || (index >= m_ActiveDownloads.size())) {
+ reportError(tr("VisitNexus: invalid download index %1").arg(index));
+ return;
+ }
+ QString params = "/select,\"";
+ QDir path = QDir(m_OutputDirectory);
+ if (path.exists(getFileName(index))) {
+ params = params + QDir::toNativeSeparators(getFilePath(index)) + "\"";
+
+ ::ShellExecuteW(nullptr, nullptr, L"explorer", ToWString(params).c_str(), nullptr, SW_SHOWNORMAL);
+ return;
+ }
+ else if (path.exists(getFileName(index) + ".unfinished")) {
+ params = params + QDir::toNativeSeparators(getFilePath(index)+".unfinished") + "\"";
+
+ ::ShellExecuteW(nullptr, nullptr, L"explorer", ToWString(params).c_str(), nullptr, SW_SHOWNORMAL);
+ return;
+ }
+
+ ::ShellExecuteW(nullptr, L"explore", ToWString(QDir::toNativeSeparators(m_OutputDirectory)).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ return;
+}
+
int DownloadManager::numTotalDownloads() const
{
@@ -960,11 +1122,16 @@ void DownloadManager::markInstalled(int index) throw MyException(tr("mark installed: invalid download index %1").arg(index));
}
+ //Avoid triggering refreshes from DirWatcher
+ startDisableDirWatcher();
+
DownloadInfo *info = m_ActiveDownloads.at(index);
QSettings metaFile(info->m_Output.fileName() + ".meta", QSettings::IniFormat);
metaFile.setValue("installed", true);
metaFile.setValue("uninstalled", false);
+ endDisableDirWatcher();
+
setState(m_ActiveDownloads.at(index), STATE_INSTALLED);
}
@@ -976,10 +1143,15 @@ void DownloadManager::markInstalled(QString fileName) } else {
DownloadInfo *info = getDownloadInfo(fileName);
if (info != nullptr) {
+ //Avoid triggering refreshes from DirWatcher
+ startDisableDirWatcher();
+
QSettings metaFile(info->m_Output.fileName() + ".meta", QSettings::IniFormat);
metaFile.setValue("installed", true);
metaFile.setValue("uninstalled", false);
delete info;
+
+ endDisableDirWatcher();
}
}
}
@@ -995,10 +1167,15 @@ void DownloadManager::markUninstalled(int index) throw MyException(tr("mark uninstalled: invalid download index %1").arg(index));
}
+ //Avoid triggering refreshes from DirWatcher
+ startDisableDirWatcher();
+
DownloadInfo *info = m_ActiveDownloads.at(index);
QSettings metaFile(info->m_Output.fileName() + ".meta", QSettings::IniFormat);
metaFile.setValue("uninstalled", true);
+ endDisableDirWatcher();
+
setState(m_ActiveDownloads.at(index), STATE_UNINSTALLED);
}
@@ -1012,9 +1189,15 @@ void DownloadManager::markUninstalled(QString fileName) QString filePath = QDir::fromNativeSeparators(m_OutputDirectory) + "/" + fileName;
DownloadInfo *info = getDownloadInfo(filePath);
if (info != nullptr) {
+
+ //Avoid triggering refreshes from DirWatcher
+ startDisableDirWatcher();
+
QSettings metaFile(info->m_Output.fileName() + ".meta", QSettings::IniFormat);
metaFile.setValue("uninstalled", true);
delete info;
+
+ endDisableDirWatcher();
}
}
}
@@ -1109,6 +1292,7 @@ void DownloadManager::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) try {
DownloadInfo *info = findDownload(this->sender(), &index);
if (info != nullptr) {
+ info->m_HasData = true;
if (info->m_State == STATE_CANCELING) {
setState(info, STATE_CANCELED);
} else if (info->m_State == STATE_PAUSING) {
@@ -1134,19 +1318,19 @@ void DownloadManager::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) double speed = (std::get<4>(info->m_SpeedDiff) * 1000.0) / (5 * 1000);
QString unit;
- if (speed < 1024) {
- unit = "bytes/sec";
+ if (speed < 1000) {
+ unit = "Bytes/s";
}
- else if (speed < 1024 * 1024) {
+ else if (speed < 1000*1024) {
speed /= 1024;
- unit = "kB/s";
+ unit = "KB/s";
}
else {
speed /= 1024 * 1024;
unit = "MB/s";
}
- info->m_Progress.second = QString::fromLatin1("%1% - %2 %3").arg(info->m_Progress.first).arg(speed, 3, 'f', 1).arg(unit);
+ info->m_Progress.second = QString::fromLatin1("%1% - %2 %3").arg(info->m_Progress.first).arg(speed, 8, 'f', 1,' ').arg(unit, -8, ' ');
TaskProgressManager::instance().updateProgress(info->m_TaskProgressId, bytesReceived, bytesTotal);
emit update(index);
@@ -1173,6 +1357,9 @@ void DownloadManager::downloadReadyRead() void DownloadManager::createMetaFile(DownloadInfo *info)
{
+ //Avoid triggering refreshes from DirWatcher
+ startDisableDirWatcher();
+
QSettings metaFile(QString("%1.meta").arg(info->m_Output.fileName()), QSettings::IniFormat);
metaFile.setValue("gameName", info->m_FileInfo->gameName);
metaFile.setValue("modID", info->m_FileInfo->modID);
@@ -1194,6 +1381,7 @@ void DownloadManager::createMetaFile(DownloadInfo *info) (info->m_State == DownloadManager::STATE_ERROR));
metaFile.setValue("removed", info->m_Hidden);
+ endDisableDirWatcher();
// slightly hackish...
for (int i = 0; i < m_ActiveDownloads.size(); ++i) {
if (m_ActiveDownloads[i] == info) {
@@ -1491,7 +1679,7 @@ void DownloadManager::downloadFinished(int index) if (info != nullptr) {
QNetworkReply *reply = info->m_Reply;
QByteArray data;
- if (reply->isOpen()) {
+ if (reply->isOpen() && info->m_HasData) {
data = reply->readAll();
info->m_Output.write(data);
}
@@ -1506,39 +1694,35 @@ void DownloadManager::downloadFinished(int index) emit showMessage(tr("Warning: Content type is: %1").arg(reply->header(QNetworkRequest::ContentTypeHeader).toString()));
if ((info->m_Output.size() == 0) ||
((reply->error() != QNetworkReply::NoError)
- && (reply->error() != QNetworkReply::OperationCanceledError)
- && (reply->error() == QNetworkReply::UnknownContentError && (info->m_Output.size() != reply->header(QNetworkRequest::ContentLengthHeader).toLongLong())))) {
+ && (reply->error() != QNetworkReply::OperationCanceledError))) {
if (reply->error() == QNetworkReply::UnknownContentError)
emit showMessage(tr("Download header content length: %1 downloaded file size: %2").arg(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong()).arg(info->m_Output.size()));
if (info->m_Tries == 0) {
emit showMessage(tr("Download failed: %1 (%2)").arg(reply->errorString()).arg(reply->error()));
}
error = true;
- setState(info, STATE_PAUSING);
+ setState(info, STATE_ERROR);
}
}
if (info->m_State == STATE_CANCELING) {
setState(info, STATE_CANCELED);
} else if (info->m_State == STATE_PAUSING) {
- if (info->m_Output.isOpen()) {
+ if (info->m_Output.isOpen() && info->m_HasData) {
info->m_Output.write(info->m_Reply->readAll());
}
-
- if (error) {
- setState(info, STATE_ERROR);
- } else {
- setState(info, STATE_PAUSED);
- }
+ setState(info, STATE_PAUSED);
}
- if (info->m_State == STATE_CANCELED) {
+ if (info->m_State == STATE_CANCELED || (info->m_Tries == 0 && error)) {
emit aboutToUpdate();
info->m_Output.remove();
delete info;
m_ActiveDownloads.erase(m_ActiveDownloads.begin() + index);
+ if (error)
+ emit showMessage(tr("We were unable to download the file due to errors after four retries. There may be an issue with the Nexus servers."));
emit update(-1);
- } else if (info->isPausedState()) {
+ } else if (info->isPausedState() || info->m_State == STATE_PAUSING) {
info->m_Output.close();
createMetaFile(info);
emit update(index);
@@ -1567,11 +1751,14 @@ void DownloadManager::downloadFinished(int index) QString newName = getFileNameFromNetworkReply(reply);
QString oldName = QFileInfo(info->m_Output).fileName();
+
+ startDisableDirWatcher();
if (!newName.isEmpty() && (oldName.isEmpty())) {
info->setName(getDownloadFileName(newName), true);
} else {
info->setName(m_OutputDirectory + "/" + info->m_FileName, true); // don't rename but remove the ".unfinished" extension
}
+ endDisableDirWatcher();
if (!isNexus) {
setState(info, STATE_READY);
@@ -1611,7 +1798,9 @@ void DownloadManager::metaDataChanged() if (info != nullptr) {
QString newName = getFileNameFromNetworkReply(info->m_Reply);
if (!newName.isEmpty() && (info->m_FileName.isEmpty())) {
+ startDisableDirWatcher();
info->setName(getDownloadFileName(newName), true);
+ endDisableDirWatcher();
refreshAlphabeticalTranslation();
if (!info->m_Output.isOpen() && !info->m_Output.open(QIODevice::WriteOnly | QIODevice::Append)) {
reportError(tr("failed to re-open %1").arg(info->m_FileName));
@@ -1625,10 +1814,24 @@ void DownloadManager::metaDataChanged() void DownloadManager::directoryChanged(const QString&)
{
- refreshList();
+ if(DownloadManager::m_DirWatcherDisabler==0)
+ refreshList();
}
void DownloadManager::managedGameChanged(MOBase::IPluginGame const *managedGame)
{
m_ManagedGame = managedGame;
}
+
+void DownloadManager::checkDownloadTimeout()
+{
+ for (int i = 0; i < m_ActiveDownloads.size(); ++i) {
+ if (m_ActiveDownloads[i]->m_StartTime.elapsed() - std::get<3>(m_ActiveDownloads[i]->m_SpeedDiff) > 5 * 1000 &&
+ m_ActiveDownloads[i]->m_State == STATE_DOWNLOADING && m_ActiveDownloads[i]->m_Reply != nullptr &&
+ m_ActiveDownloads[i]->m_Reply->isOpen()) {
+ pauseDownload(i);
+ downloadFinished(i);
+ resumeDownload(i);
+ }
+ }
+}
diff --git a/src/downloadmanager.h b/src/downloadmanager.h index 98f5e468..136ecf2a 100644 --- a/src/downloadmanager.h +++ b/src/downloadmanager.h @@ -29,6 +29,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QFile>
#include <QNetworkReply>
#include <QTime>
+#include <QTimer>
#include <QVector>
#include <QMap>
#include <QStringList>
@@ -77,6 +78,7 @@ private: qint64 m_PreResumeSize;
std::pair<int, QString> m_Progress;
std::tuple<int, int, int, int, int> m_SpeedDiff;
+ bool m_HasData;
DownloadState m_State;
int m_CurrentUrl;
QStringList m_Urls;
@@ -114,7 +116,7 @@ private: private:
static unsigned int s_NextDownloadID;
private:
- DownloadInfo() : m_TotalSize(0), m_ReQueried(false), m_Hidden(false), m_SpeedDiff(std::tuple<int,int,int,int,int>(0,0,0,0,0)) {}
+ DownloadInfo() : m_TotalSize(0), m_ReQueried(false), m_Hidden(false), m_SpeedDiff(std::tuple<int,int,int,int,int>(0,0,0,0,0)), m_HasData(false) {}
};
public:
@@ -137,12 +139,30 @@ public: bool downloadsInProgress();
/**
+ * @brief determine if a download is currently in progress, does not count paused ones.
+ *
+ * @return true if there is currently a download in progress (that is not paused already).
+ **/
+ bool downloadsInProgressNoPause();
+
+ /**
* @brief set the output directory to write to
*
* @param outputDirectory the new output directory
**/
void setOutputDirectory(const QString &outputDirectory);
+ /**
+ * @brief disables feedback from the downlods fileSystemWhatcher untill disableDownloadsWatcherEnd() is called
+ *
+ **/
+ static void startDisableDirWatcher();
+
+ /**
+ * @brief re-enables feedback from the downlods fileSystemWhatcher after disableDownloadsWatcherStart() was called
+ **/
+ static void endDisableDirWatcher();
+
/**
* @return current download directory
**/
@@ -423,6 +443,10 @@ public slots: void queryInfo(int index);
+ void visitOnNexus(int index);
+
+ void openInDownloadsFolder(int index);
+
void nxmDescriptionAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID);
void nxmFilesAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID);
@@ -443,6 +467,7 @@ private slots: void downloadError(QNetworkReply::NetworkError error);
void metaDataChanged();
void directoryChanged(const QString &dirctory);
+ void checkDownloadTimeout();
private:
@@ -517,6 +542,12 @@ private: QFileSystemWatcher m_DirWatcher;
+ //The dirWatcher is actually triggering off normal Mo operations such as deleting downloads or editing .meta files
+ //so it needs to be disabled during operations that are known to cause the creation or deletion of files in the Downloads folder.
+ //Notably using QSettings to edit a file creates a temporarily .lock file that causes the Watcher to trigger multiple listRefreshes freezing the ui.
+ static int m_DirWatcherDisabler;
+
+
std::map<QString, int> m_DownloadFails;
bool m_ShowHidden;
@@ -524,6 +555,8 @@ private: QRegExp m_DateExpression;
MOBase::IPluginGame const *m_ManagedGame;
+
+ QTimer m_TimeoutTimer;
};
diff --git a/src/instancemanager.cpp b/src/instancemanager.cpp index 43ae152b..1c6542e8 100644 --- a/src/instancemanager.cpp +++ b/src/instancemanager.cpp @@ -131,11 +131,12 @@ QString InstanceManager::manageInstances(const QStringList &instanceList) const QString InstanceManager::queryInstanceName(const QStringList &instanceList) const { QString instanceId; + QString dialogText; while (instanceId.isEmpty()) { QInputDialog dialog; - dialog.setWindowTitle(QObject::tr("Enter a Name for the new Instance")); - dialog.setLabelText(QObject::tr("Enter a new name or select one from the sugested list (only letters and numbers allowed):")); + dialog.setWindowTitle(QObject::tr("Enter a Name for the new Instance")); + dialog.setLabelText(QObject::tr("Enter a new name or select one from the suggested list:")); // would be neat if we could take the names from the game plugins but // the required initialization order requires the ini file to be // available *before* we load plugins @@ -146,7 +147,17 @@ QString InstanceManager::queryInstanceName(const QStringList &instanceList) cons if (dialog.exec() == QDialog::Rejected) { throw MOBase::MyException(QObject::tr("Canceled")); } - instanceId = dialog.textValue().replace(QRegExp("[^0-9a-zA-Z ]"), ""); + dialogText = dialog.textValue(); + instanceId = sanitizeInstanceName(dialogText); + if (instanceId != dialogText) { + if (QMessageBox::question( nullptr, + QObject::tr("Invalid instance name"), + QObject::tr("The instance name \"%1\" is invalid. Use the name \"%2\" instead?").arg(dialogText,instanceId), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) { + instanceId=""; + continue; + } + } bool alreadyExists=false; for (const QString &instance : instanceList) { @@ -296,3 +307,21 @@ QString InstanceManager::determineDataPath() } } + +QString InstanceManager::sanitizeInstanceName(const QString &name) const +{ + QString new_name = name; + + // Restrict the allowed characters + new_name = new_name.remove(QRegExp("[^A-Za-z0-9 _=+;!@#$%^'\\-\\.\\[\\]\\{\\}\\(\\)]")); + + // Don't end in spaces and periods + new_name = new_name.remove(QRegExp("\\.*$")); + new_name = new_name.remove(QRegExp(" *$")); + + // Recurse until stuff stops changing + if (new_name != name) { + return sanitizeInstanceName(new_name); + } + return new_name; +}
\ No newline at end of file diff --git a/src/instancemanager.h b/src/instancemanager.h index adedd78f..4efa6f03 100644 --- a/src/instancemanager.h +++ b/src/instancemanager.h @@ -50,6 +50,7 @@ private: QString manageInstances(const QStringList &instanceList) const; + QString sanitizeInstanceName(const QString &name) const; void setCurrentInstance(const QString &name); QString queryInstanceName(const QStringList &instanceList) const; diff --git a/src/main.cpp b/src/main.cpp index 9c30a1c6..bfc3b926 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -446,11 +446,7 @@ static void preloadSsl() static QString getVersionDisplayString()
{
- VS_FIXEDFILEINFO version = GetFileVersion(ToWString(QApplication::applicationFilePath()));
- return VersionInfo(version.dwFileVersionMS >> 16,
- version.dwFileVersionMS & 0xFFFF,
- version.dwFileVersionLS >> 16,
- version.dwFileVersionLS & 0xFFFF).displayString();
+ return createVersionInfo().displayString();
}
int runApplication(MOApplication &application, SingleInstance &instance,
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 2830c776..f6cfbfbd 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -242,7 +242,28 @@ MainWindow::MainWindow(QSettings &initSettings updateProblemsButton();
- updateToolBar();
+ // Setup toolbar
+ QWidget *spacer = new QWidget(ui->toolBar);
+ spacer->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
+ QWidget *widget = ui->toolBar->widgetForAction(ui->actionTool);
+ QToolButton *toolBtn = qobject_cast<QToolButton*>(widget);
+
+ if (toolBtn->menu() == nullptr) {
+ actionToToolButton(ui->actionTool);
+ }
+
+ actionToToolButton(ui->actionHelp);
+ createHelpWidget();
+
+ for (QAction *action : ui->toolBar->actions()) {
+ if (action->isSeparator()) {
+ // insert spacers
+ ui->toolBar->insertWidget(action, spacer);
+ m_Sep = action;
+ // m_Sep would only use the last seperator anyway, and we only have the one anyway?
+ break;
+ }
+ }
TaskProgressManager::instance().tryCreateTaskbar();
@@ -379,7 +400,7 @@ MainWindow::MainWindow(QSettings &initSettings new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Enter), this, SLOT(openExplorer_activated()));
new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return), this, SLOT(openExplorer_activated()));
-
+
new QShortcut(QKeySequence::Refresh, this, SLOT(refreshProfile_activated()));
@@ -560,41 +581,22 @@ void MainWindow::updateToolBar() for (QAction *action : ui->toolBar->actions()) {
if (action->objectName().startsWith("custom__")) {
ui->toolBar->removeAction(action);
+ action->deleteLater();
}
}
- QWidget *spacer = new QWidget(ui->toolBar);
- spacer->setObjectName("custom__spacer");
- spacer->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
- QWidget *widget = ui->toolBar->widgetForAction(ui->actionTool);
- QToolButton *toolBtn = qobject_cast<QToolButton*>(widget);
-
- if (toolBtn->menu() == nullptr) {
- actionToToolButton(ui->actionTool);
- }
-
- actionToToolButton(ui->actionHelp);
- createHelpWidget();
-
- for (QAction *action : ui->toolBar->actions()) {
- if (action->isSeparator()) {
- // insert spacers
- ui->toolBar->insertWidget(action, spacer);
-
- std::vector<Executable>::iterator begin, end;
- m_OrganizerCore.executablesList()->getExecutables(begin, end);
- for (auto iter = begin; iter != end; ++iter) {
- if (iter->isShownOnToolbar()) {
- QAction *exeAction = new QAction(iconForExecutable(iter->m_BinaryInfo.filePath()),
- iter->m_Title,
- ui->toolBar);
- exeAction->setObjectName(QString("custom__") + iter->m_Title);
- if (!connect(exeAction, SIGNAL(triggered()), this, SLOT(startExeAction()))) {
- qDebug("failed to connect trigger?");
- }
- ui->toolBar->insertAction(action, exeAction);
- }
+ std::vector<Executable>::iterator begin, end;
+ m_OrganizerCore.executablesList()->getExecutables(begin, end);
+ for (auto iter = begin; iter != end; ++iter) {
+ if (iter->isShownOnToolbar()) {
+ QAction *exeAction = new QAction(iconForExecutable(iter->m_BinaryInfo.filePath()),
+ iter->m_Title,
+ ui->toolBar);
+ exeAction->setObjectName(QString("custom__") + iter->m_Title);
+ if (!connect(exeAction, SIGNAL(triggered()), this, SLOT(startExeAction()))) {
+ qDebug("failed to connect trigger?");
}
+ ui->toolBar->insertAction(m_Sep, exeAction);
}
}
}
@@ -881,7 +883,7 @@ void MainWindow::closeEvent(QCloseEvent* event) {
m_closing = true;
- if (m_OrganizerCore.downloadManager()->downloadsInProgress()) {
+ if (m_OrganizerCore.downloadManager()->downloadsInProgressNoPause()) {
if (QMessageBox::question(this, tr("Downloads in progress"),
tr("There are still downloads in progress, do you really want to quit?"),
QMessageBox::Yes | QMessageBox::Cancel) == QMessageBox::Cancel) {
@@ -2334,9 +2336,11 @@ void MainWindow::removeMod_clicked() tr("Remove the following mods?<br><ul>%1</ul>").arg(mods),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
// use mod names instead of indexes because those become invalid during the removal
+ DownloadManager::startDisableDirWatcher();
for (QString name : modNames) {
m_OrganizerCore.modList()->removeRowForce(ModInfo::getIndex(name), QModelIndex());
}
+ DownloadManager::endDisableDirWatcher();
}
} else {
m_OrganizerCore.modList()->removeRow(m_ContextRow, QModelIndex());
@@ -2498,7 +2502,7 @@ void MainWindow::displayModInformation(ModInfo::Ptr modInfo, unsigned int index, connect(&dialog, SIGNAL(modOpenPrev(int)), this, SLOT(modOpenPrev(int)), Qt::QueuedConnection);
connect(&dialog, SIGNAL(originModified(int)), this, SLOT(originModified(int)));
connect(&dialog, SIGNAL(endorseMod(ModInfo::Ptr)), this, SLOT(endorseMod(ModInfo::Ptr)));
-
+
//Open the tab first if we want to use the standard indexes of the tabs.
if (tab != -1) {
dialog.openTab(tab);
@@ -2615,20 +2619,44 @@ void MainWindow::displayModInformation(int row, int tab) void MainWindow::ignoreMissingData_clicked()
{
- ModInfo::Ptr info = ModInfo::getByIndex(m_ContextRow);
- QDir(info->absolutePath()).mkdir("textures");
- info->testValid();
- connect(this, SIGNAL(modListDataChanged(QModelIndex,QModelIndex)), m_OrganizerCore.modList(), SIGNAL(dataChanged(QModelIndex,QModelIndex)));
+ QItemSelectionModel *selection = ui->modList->selectionModel();
+ if (selection->hasSelection() && selection->selectedRows().count() > 1) {
+ for (QModelIndex idx : selection->selectedRows()) {
+ int row_idx = idx.data(Qt::UserRole + 1).toInt();
+ ModInfo::Ptr info = ModInfo::getByIndex(row_idx);
+ QDir(info->absolutePath()).mkdir("textures");
+ info->testValid();
+ connect(this, SIGNAL(modListDataChanged(QModelIndex, QModelIndex)), m_OrganizerCore.modList(), SIGNAL(dataChanged(QModelIndex, QModelIndex)));
+
+ emit modListDataChanged(m_OrganizerCore.modList()->index(row_idx, 0), m_OrganizerCore.modList()->index(row_idx, m_OrganizerCore.modList()->columnCount() - 1));
+ }
+ } else {
+ ModInfo::Ptr info = ModInfo::getByIndex(m_ContextRow);
+ QDir(info->absolutePath()).mkdir("textures");
+ info->testValid();
+ connect(this, SIGNAL(modListDataChanged(QModelIndex, QModelIndex)), m_OrganizerCore.modList(), SIGNAL(dataChanged(QModelIndex, QModelIndex)));
- emit modListDataChanged(m_OrganizerCore.modList()->index(m_ContextRow, 0), m_OrganizerCore.modList()->index(m_ContextRow, m_OrganizerCore.modList()->columnCount() - 1));
+ emit modListDataChanged(m_OrganizerCore.modList()->index(m_ContextRow, 0), m_OrganizerCore.modList()->index(m_ContextRow, m_OrganizerCore.modList()->columnCount() - 1));
+ }
}
void MainWindow::markConverted_clicked()
{
- ModInfo::Ptr info = ModInfo::getByIndex(m_ContextRow);
- info->markConverted(true);
- connect(this, SIGNAL(modListDataChanged(QModelIndex, QModelIndex)), m_OrganizerCore.modList(), SIGNAL(dataChanged(QModelIndex, QModelIndex)));
- emit modListDataChanged(m_OrganizerCore.modList()->index(m_ContextRow, 0), m_OrganizerCore.modList()->index(m_ContextRow, m_OrganizerCore.modList()->columnCount() - 1));
+ QItemSelectionModel *selection = ui->modList->selectionModel();
+ if (selection->hasSelection() && selection->selectedRows().count() > 1) {
+ for (QModelIndex idx : selection->selectedRows()) {
+ int row_idx = idx.data(Qt::UserRole + 1).toInt();
+ ModInfo::Ptr info = ModInfo::getByIndex(row_idx);
+ info->markConverted(true);
+ connect(this, SIGNAL(modListDataChanged(QModelIndex, QModelIndex)), m_OrganizerCore.modList(), SIGNAL(dataChanged(QModelIndex, QModelIndex)));
+ emit modListDataChanged(m_OrganizerCore.modList()->index(row_idx, 0), m_OrganizerCore.modList()->index(row_idx, m_OrganizerCore.modList()->columnCount() - 1));
+ }
+ } else {
+ ModInfo::Ptr info = ModInfo::getByIndex(m_ContextRow);
+ info->markConverted(true);
+ connect(this, SIGNAL(modListDataChanged(QModelIndex, QModelIndex)), m_OrganizerCore.modList(), SIGNAL(dataChanged(QModelIndex, QModelIndex)));
+ emit modListDataChanged(m_OrganizerCore.modList()->index(m_ContextRow, 0), m_OrganizerCore.modList()->index(m_ContextRow, m_OrganizerCore.modList()->columnCount() - 1));
+ }
}
@@ -2655,9 +2683,17 @@ void MainWindow::visitWebPage_clicked() void MainWindow::openExplorer_clicked()
{
- ModInfo::Ptr modInfo = ModInfo::getByIndex(m_ContextRow);
-
- ::ShellExecuteW(nullptr, L"explore", ToWString(modInfo->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ QItemSelectionModel *selection = ui->modList->selectionModel();
+ if (selection->hasSelection() && selection->selectedRows().count() > 1) {
+ for (QModelIndex idx : selection->selectedRows()) {
+ ModInfo::Ptr info = ModInfo::getByIndex(idx.data(Qt::UserRole + 1).toInt());
+ ::ShellExecuteW(nullptr, L"explore", ToWString(info->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ }
+ }
+ else {
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(m_ContextRow);
+ ::ShellExecuteW(nullptr, L"explore", ToWString(modInfo->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ }
}
void MainWindow::openExplorer_activated()
@@ -2685,7 +2721,7 @@ void MainWindow::openExplorer_activated() QModelIndex idx = selection->currentIndex();
QString fileName = idx.data().toString();
-
+
ModInfo::Ptr modInfo = ModInfo::getByIndex(ModInfo::getIndex(m_OrganizerCore.pluginList()->origin(fileName)));
std::vector<ModInfo::EFlag> flags = modInfo->getFlags();
@@ -2825,13 +2861,83 @@ void MainWindow::on_modList_doubleClicked(const QModelIndex &index) return;
}
+ Qt::KeyboardModifiers modifiers = QApplication::queryKeyboardModifiers();
+ if (modifiers.testFlag(Qt::ControlModifier)) {
+ try {
+ m_ContextRow = m_ModListSortProxy->mapToSource(index).row();
+ openExplorer_clicked();
+ // workaround to cancel the editor that might have opened because of
+ // selection-click
+ ui->modList->closePersistentEditor(index);
+ }
+ catch (const std::exception &e) {
+ reportError(e.what());
+ }
+ }
+ else {
+ try {
+ m_ContextRow = m_ModListSortProxy->mapToSource(index).row();
+ displayModInformation(sourceIdx.row());
+ // workaround to cancel the editor that might have opened because of
+ // selection-click
+ ui->modList->closePersistentEditor(index);
+ }
+ catch (const std::exception &e) {
+ reportError(e.what());
+ }
+ }
+}
+
+void MainWindow::on_espList_doubleClicked(const QModelIndex &index)
+{
+ if (!index.isValid()) {
+ return;
+ }
+
+ if (m_OrganizerCore.pluginList()->timeElapsedSinceLastChecked() <= QApplication::doubleClickInterval()) {
+ // don't interpret double click if we only just checked a plugin
+ return;
+ }
+
+ QModelIndex sourceIdx = mapToModel(m_OrganizerCore.pluginList(), index);
+ if (!sourceIdx.isValid()) {
+ return;
+ }
try {
- m_ContextRow = m_ModListSortProxy->mapToSource(index).row();
- displayModInformation(sourceIdx.row());
- // workaround to cancel the editor that might have opened because of
- // selection-click
- ui->modList->closePersistentEditor(index);
- } catch (const std::exception &e) {
+
+ QItemSelectionModel *selection = ui->espList->selectionModel();
+
+ if (selection->hasSelection() && selection->selectedRows().count() == 1) {
+
+ QModelIndex idx = selection->currentIndex();
+ QString fileName = idx.data().toString();
+
+ if (ModInfo::getIndex(m_OrganizerCore.pluginList()->origin(fileName)) == UINT_MAX)
+ return;
+
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(ModInfo::getIndex(m_OrganizerCore.pluginList()->origin(fileName)));
+ std::vector<ModInfo::EFlag> flags = modInfo->getFlags();
+
+ if (modInfo->isRegular() || (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end())) {
+
+ Qt::KeyboardModifiers modifiers = QApplication::queryKeyboardModifiers();
+ if (modifiers.testFlag(Qt::ControlModifier)) {
+ openExplorer_activated();
+ // workaround to cancel the editor that might have opened because of
+ // selection-click
+ ui->espList->closePersistentEditor(index);
+ }
+ else {
+
+ displayModInformation(ModInfo::getIndex(m_OrganizerCore.pluginList()->origin(fileName)));
+ // workaround to cancel the editor that might have opened because of
+ // selection-click
+ ui->espList->closePersistentEditor(index);
+ }
+ }
+ }
+ }
+ catch (const std::exception &e) {
reportError(e.what());
}
}
@@ -3072,14 +3178,32 @@ void MainWindow::changeVersioningScheme() { }
void MainWindow::ignoreUpdate() {
- ModInfo::Ptr info = ModInfo::getByIndex(m_ContextRow);
- info->ignoreUpdate(true);
+ QItemSelectionModel *selection = ui->modList->selectionModel();
+ if (selection->hasSelection() && selection->selectedRows().count() > 1) {
+ for (QModelIndex idx : selection->selectedRows()) {
+ ModInfo::Ptr info = ModInfo::getByIndex(idx.data(Qt::UserRole + 1).toInt());
+ info->ignoreUpdate(true);
+ }
+ }
+ else {
+ ModInfo::Ptr info = ModInfo::getByIndex(m_ContextRow);
+ info->ignoreUpdate(true);
+ }
}
void MainWindow::unignoreUpdate()
{
- ModInfo::Ptr info = ModInfo::getByIndex(m_ContextRow);
- info->ignoreUpdate(false);
+ QItemSelectionModel *selection = ui->modList->selectionModel();
+ if (selection->hasSelection() && selection->selectedRows().count() > 1) {
+ for (QModelIndex idx : selection->selectedRows()) {
+ ModInfo::Ptr info = ModInfo::getByIndex(idx.data(Qt::UserRole + 1).toInt());
+ info->ignoreUpdate(false);
+ }
+ }
+ else {
+ ModInfo::Ptr info = ModInfo::getByIndex(m_ContextRow);
+ info->ignoreUpdate(false);
+ }
}
void MainWindow::addPrimaryCategoryCandidates(QMenu *primaryCategoryMenu,
@@ -3153,6 +3277,13 @@ void MainWindow::openInstallFolder() ::ShellExecuteW(nullptr, L"explore", ToWString(qApp->applicationDirPath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
}
+void MainWindow::openPluginsFolder()
+{
+ QString pluginsPath = QCoreApplication::applicationDirPath() + "/" + ToQString(AppConfig::pluginPath());
+ ::ShellExecuteW(nullptr, L"explore", ToWString(pluginsPath).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+}
+
+
void MainWindow::openProfileFolder()
{
::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.currentProfile()->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
@@ -3163,6 +3294,11 @@ void MainWindow::openDownloadsFolder() ::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.settings().getDownloadDirectory()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
}
+void MainWindow::openModsFolder()
+{
+ ::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.settings().getModDirectory()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+}
+
void MainWindow::openGameFolder()
{
::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.managedGame()->gameDirectory().absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
@@ -3356,6 +3492,8 @@ QMenu *MainWindow::openFolderMenu() FolderMenu->addAction(tr("Open Instance folder"), this, SLOT(openInstanceFolder()));
+ FolderMenu->addAction(tr("Open Mods folder"), this, SLOT(openModsFolder()));
+
FolderMenu->addAction(tr("Open Profile folder"), this, SLOT(openProfileFolder()));
FolderMenu->addAction(tr("Open Downloads folder"), this, SLOT(openDownloadsFolder()));
@@ -3364,15 +3502,9 @@ QMenu *MainWindow::openFolderMenu() FolderMenu->addAction(tr("Open MO2 Install folder"), this, SLOT(openInstallFolder()));
- FolderMenu->addAction(tr("Open MO2 Logs folder"), this, SLOT(openLogsFolder()));
-
-
-
-
-
-
-
+ FolderMenu->addAction(tr("Open MO2 Plugins folder"), this, SLOT(openPluginsFolder()));
+ FolderMenu->addAction(tr("Open MO2 Logs folder"), this, SLOT(openLogsFolder()));
return FolderMenu;
@@ -4199,12 +4331,16 @@ void MainWindow::on_actionUpdate_triggered() void MainWindow::on_actionEndorseMO_triggered()
{
+ // Normally this would be the managed game but MO2 is only uploaded to the Skyrim SE site right now
+ IPluginGame * game = m_OrganizerCore.getGame("skyrimse");
+ if (!game) return;
+
if (QMessageBox::question(this, tr("Endorse Mod Organizer"),
tr("Do you want to endorse Mod Organizer on %1 now?").arg(
- NexusInterface::instance(&m_PluginContainer)->getGameURL(m_OrganizerCore.managedGame()->gameShortName())),
+ NexusInterface::instance(&m_PluginContainer)->getGameURL(game->gameShortName())),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
NexusInterface::instance(&m_PluginContainer)->requestToggleEndorsement(
- m_OrganizerCore.managedGame()->gameShortName(), m_OrganizerCore.managedGame()->nexusModOrganizerID(), true, this, QVariant(), QString());
+ game->gameShortName(), game->nexusModOrganizerID(), true, this, QVariant(), QString());
}
}
@@ -4231,11 +4367,13 @@ void MainWindow::updateDownloadListDelegate() connect(ui->downloadFilterEdit, SIGNAL(textChanged(QString)), this, SLOT(downloadFilterChanged(QString)));
ui->downloadView->setModel(sortProxy);
- ui->downloadView->sortByColumn(1, Qt::DescendingOrder);
- ui->downloadView->header()->resizeSections(QHeaderView::Fixed);
+ //ui->downloadView->sortByColumn(1, Qt::DescendingOrder);
+ ui->downloadView->header()->resizeSections(QHeaderView::Stretch);
connect(ui->downloadView->itemDelegate(), SIGNAL(installDownload(int)), &m_OrganizerCore, SLOT(installDownload(int)));
connect(ui->downloadView->itemDelegate(), SIGNAL(queryInfo(int)), m_OrganizerCore.downloadManager(), SLOT(queryInfo(int)));
+ connect(ui->downloadView->itemDelegate(), SIGNAL(visitOnNexus(int)), m_OrganizerCore.downloadManager(), SLOT(visitOnNexus(int)));
+ connect(ui->downloadView->itemDelegate(), SIGNAL(openInDownloadsFolder(int)), m_OrganizerCore.downloadManager(), SLOT(openInDownloadsFolder(int)));
connect(ui->downloadView->itemDelegate(), SIGNAL(removeDownload(int, bool)), m_OrganizerCore.downloadManager(), SLOT(removeDownload(int, bool)));
connect(ui->downloadView->itemDelegate(), SIGNAL(restoreDownload(int)), m_OrganizerCore.downloadManager(), SLOT(restoreDownload(int)));
connect(ui->downloadView->itemDelegate(), SIGNAL(cancelDownload(int)), m_OrganizerCore.downloadManager(), SLOT(cancelDownload(int)));
@@ -4267,9 +4405,13 @@ void MainWindow::nxmUpdatesAvailable(const std::vector<int> &modIDs, QVariant us QVariantList resultList = resultData.toList();
for (auto iter = resultList.begin(); iter != resultList.end(); ++iter) {
QVariantMap result = iter->toMap();
- if (result["id"].toInt() == m_OrganizerCore.managedGame()->nexusModOrganizerID()
- && result["game_id"].toInt() == m_OrganizerCore.managedGame()->nexusGameID()) {
- if (!result["voted_by_user"].toBool()) {
+ // Normally this would be the managed game but MO2 is only uploaded to the Skyrim SE site right now
+ IPluginGame * game = m_OrganizerCore.getGame("skyrimse");
+ if (game
+ && result["id"].toInt() == game->nexusModOrganizerID()
+ && result["game_id"].toInt() == game->nexusGameID()) {
+ if (result["voted_by_user"].type() != QVariant::Invalid &&
+ !result["voted_by_user"].toBool()) {
ui->actionEndorseMO->setVisible(true);
}
} else {
@@ -4293,7 +4435,8 @@ void MainWindow::nxmUpdatesAvailable(const std::vector<int> &modIDs, QVariant us (*iter)->setNewestVersion(result["version"].toString());
(*iter)->setNexusDescription(result["description"].toString());
if (NexusInterface::instance(&m_PluginContainer)->getAccessManager()->loggedIn() &&
- result.contains("voted_by_user")) {
+ result.contains("voted_by_user") &&
+ result["voted_by_user"].type() != QVariant::Invalid) {
// don't use endorsement info if we're not logged in or if the response doesn't contain it
(*iter)->setIsEndorsed(result["voted_by_user"].toBool());
}
@@ -4319,7 +4462,7 @@ void MainWindow::nxmEndorsementToggled(QString, int, QVariant, QVariant resultDa {
if (resultData.toBool()) {
ui->actionEndorseMO->setVisible(false);
- QMessageBox::question(this, tr("Thank you!"), tr("Thank you for your endorsement!"));
+ QMessageBox::information(this, tr("Thank you!"), tr("Thank you for your endorsement!"));
}
if (!disconnect(sender(), SIGNAL(nxmEndorsementToggled(QString, int, QVariant, QVariant, int)),
@@ -4637,7 +4780,7 @@ void MainWindow::on_espList_customContextMenuRequested(const QPoint &pos) menu.addAction(tr("Unlock load order"), this, SLOT(unlockESPIndex()));
}
if (hasUnlocked) {
- menu.addAction(tr("Lock load order"), this, SLOT(f()));
+ menu.addAction(tr("Lock load order"), this, SLOT(lockESPIndex()));
}
try {
@@ -4965,7 +5108,7 @@ bool MainWindow::createBackup(const QString &filePath, const QDateTime &time) QString outPath = filePath + "." + time.toString(PATTERN_BACKUP_DATE);
if (shellCopy(QStringList(filePath), QStringList(outPath), this)) {
QFileInfo fileInfo(filePath);
- removeOldFiles(fileInfo.absolutePath(), fileInfo.fileName() + PATTERN_BACKUP_GLOB, 3, QDir::Name);
+ removeOldFiles(fileInfo.absolutePath(), fileInfo.fileName() + PATTERN_BACKUP_GLOB, 10, QDir::Name);
return true;
} else {
return false;
diff --git a/src/mainwindow.h b/src/mainwindow.h index bbff0d93..6cf83301 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -304,6 +304,8 @@ private: Ui::MainWindow *ui;
+ QAction *m_Sep; // Executable Shortcuts are added after this. Non owning.
+
bool m_WasVisible;
MOBase::TutorialControl m_Tutorial;
@@ -498,7 +500,9 @@ private slots: void openInstanceFolder();
void openLogsFolder();
void openInstallFolder();
+ void openPluginsFolder();
void openDownloadsFolder();
+ void openModsFolder();
void openProfileFolder();
void openGameFolder();
void openMyGamesFolder();
@@ -571,6 +575,7 @@ private slots: // ui slots void on_executablesListBox_currentIndexChanged(int index);
void on_modList_customContextMenuRequested(const QPoint &pos);
void on_modList_doubleClicked(const QModelIndex &index);
+ void on_espList_doubleClicked(const QModelIndex &index);
void on_profileBox_currentIndexChanged(int index);
void on_savegameList_customContextMenuRequested(const QPoint &pos);
void on_startButton_clicked();
diff --git a/src/mainwindow.ui b/src/mainwindow.ui index e0aa6f36..cf0f2aa4 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -96,9 +96,9 @@ </item>
<item>
<widget class="QPushButton" name="clickBlankButton">
- <property name="enabled">
- <bool>false</bool>
- </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Maximum">
<horstretch>0</horstretch>
@@ -194,7 +194,7 @@ </widget>
</item>
<item>
- <widget class="QComboBox" name="profileBox">
+ <widget class="QComboBox" name="profileBox">
<property name="toolTip">
<string>Pick a module collection</string>
</property>
@@ -248,7 +248,7 @@ p, li { white-space: pre-wrap; } <height>16</height>
</size>
</property>
- </widget>
+ </widget>
</item>
<item>
<widget class="QPushButton" name="openFolderMenu">
@@ -265,16 +265,6 @@ p, li { white-space: pre-wrap; } </widget>
</item>
<item>
-
-
-
-
-
-
-
-
-
-
<widget class="QPushButton" name="restoreModsButton">
<property name="toolTip">
<string>Restore Backup...</string>
@@ -509,7 +499,7 @@ p, li { white-space: pre-wrap; } </property>
</widget>
</item>
- <item>
+ <item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -521,7 +511,7 @@ p, li { white-space: pre-wrap; } </size>
</property>
</spacer>
- </item>
+ </item>
<item alignment="Qt::AlignLeft">
<widget class="QPushButton" name="clearFiltersButton">
<property name="sizePolicy">
@@ -536,12 +526,12 @@ p, li { white-space: pre-wrap; } <height>22</height>
</size>
</property>
- <property name="baseSize">
+ <property name="baseSize">
<size>
<width>95</width>
<height>0</height>
</size>
- </property>
+ </property>
<property name="visible">
<bool>false</bool>
</property>
@@ -567,7 +557,7 @@ p, li { white-space: pre-wrap; } </widget>
</item>
<item>
- <spacer name="horizontalSpacer_4">
+ <spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@@ -579,14 +569,14 @@ p, li { white-space: pre-wrap; } </property>
</spacer>
</item>
- <item>
- <widget class="QComboBox" name="groupCombo">
- <property name="baseSize">
+ <item>
+ <widget class="QComboBox" name="groupCombo">
+ <property name="baseSize">
<size>
<width>220</width>
<height>0</height>
</size>
- </property>
+ </property>
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
@@ -608,13 +598,13 @@ p, li { white-space: pre-wrap; } </widget>
</item>
<item>
- <widget class="MOBase::LineEditClear" name="modFilterEdit">
- <property name="baseSize">
+ <widget class="MOBase::LineEditClear" name="modFilterEdit">
+ <property name="baseSize">
<size>
<width>220</width>
<height>0</height>
</size>
- </property>
+ </property>
<property name="placeholderText">
<string>Namefilter</string>
</property>
@@ -835,12 +825,12 @@ p, li { white-space: pre-wrap; } <layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QPushButton" name="bossButton">
- <property name="visible">
- <bool>true</bool>
- </property>
+ <property name="visible">
+ <bool>true</bool>
+ </property>
<property name="text">
<string>Sort</string>
- </property>
+ </property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/MO/gui/sort</normaloff>:/MO/gui/sort</iconset>
@@ -954,6 +944,9 @@ 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 list contains the esps, esms, and esls contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html></string>
</property>
+ <property name="editTriggers">
+ <set>QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked</set>
+ </property>
<property name="dragEnabled">
<bool>true</bool>
</property>
@@ -987,6 +980,9 @@ p, li { white-space: pre-wrap; } <property name="sortingEnabled">
<bool>true</bool>
</property>
+ <property name="expandsOnDoubleClick">
+ <bool>false</bool>
+ </property>
<attribute name="headerStretchLastSection">
<bool>false</bool>
</attribute>
@@ -1009,15 +1005,12 @@ p, li { white-space: pre-wrap; } </layout>
</widget>
<widget class="QWidget" name="bsaTab">
-
-
-
+ <property name="visible">
+ <bool>false</bool>
+ </property>
<attribute name="title">
<string>Archives</string>
</attribute>
- <property name="visible">
- <bool>true</bool>
- </property>
<layout class="QVBoxLayout" name="verticalLayout_9">
<property name="leftMargin">
<number>6</number>
@@ -1032,17 +1025,7 @@ p, li { white-space: pre-wrap; } <number>6</number>
</property>
<item>
- <layout class="QHBoxLayout" name="horizontalLayout_9" stretch="0,1">
- <!--<item>-->
- <!--<widget class="QCheckBox" name="manageArchivesBox">-->
- <!--<property name="text">-->
- <!--<string/>-->
- <!--</property>-->
- <!--<property name="checked">-->
- <!--<bool>true</bool>-->
- <!--</property>-->
- <!--</widget>-->
- <!--</item>-->
+ <layout class="QHBoxLayout" name="horizontalLayout_9" stretch="0">
<item>
<widget class="QLabel" name="managedArchiveLabel">
<property name="toolTip">
@@ -1072,50 +1055,24 @@ p, li { white-space: pre-wrap; } BSAs checked here are loaded in such a way that your installation order is obeyed properly.</string>
</property>
- <property name="editTriggers">
- <set>QAbstractItemView::NoEditTriggers</set>
- </property>
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
- <property name="dragEnabled">
+ <property name="dragEnabled" stdset="0">
<bool>false</bool>
</property>
- <property name="dragDropOverwriteMode">
+ <property name="dragDropOverwriteMode" stdset="0">
<bool>false</bool>
</property>
- <property name="dragDropMode">
- <enum>QAbstractItemView::NoDragDrop</enum>
- </property>
- <property name="defaultDropAction">
- <enum>Qt::IgnoreAction</enum>
- </property>
- <property name="selectionMode">
- <enum>QAbstractItemView::SingleSelection</enum>
- </property>
- <property name="selectionBehavior">
- <enum>QAbstractItemView::SelectRows</enum>
- </property>
- <property name="indentation">
+ <property name="indentation" stdset="0">
<number>20</number>
</property>
- <property name="itemsExpandable">
+ <property name="itemsExpandable" stdset="0">
<bool>true</bool>
</property>
- <property name="columnCount">
+ <property name="columnCount" stdset="0">
<number>1</number>
</property>
- <attribute name="headerVisible">
- <bool>false</bool>
- </attribute>
- <attribute name="headerDefaultSectionSize">
- <number>200</number>
- </attribute>
- <column>
- <property name="text">
- <string>File</string>
- </property>
- </column>
</widget>
</item>
</layout>
@@ -1286,7 +1243,7 @@ p, li { white-space: pre-wrap; } <enum>Qt::ScrollBarAlwaysOn</enum>
</property>
<property name="horizontalScrollBarPolicy">
- <enum>Qt::ScrollBarAlwaysOff</enum>
+ <enum>Qt::ScrollBarAsNeeded</enum>
</property>
<property name="dragEnabled">
<bool>true</bool>
@@ -1319,7 +1276,10 @@ p, li { white-space: pre-wrap; } <bool>true</bool>
</property>
<attribute name="headerDefaultSectionSize">
- <number>100</number>
+ <number>50</number>
+ </attribute>
+ <attribute name="headerMinimumSectionSize">
+ <number>15</number>
</attribute>
<attribute name="headerStretchLastSection">
<bool>true</bool>
@@ -1601,9 +1561,6 @@ Right now this has very limited functionality</string> <property name="text">
<string>Copy Log to Clipboard</string>
</property>
- <property name="shortcut">
- <string>Ctrl+C</string>
- </property>
</action>
<action name="actionChange_Game">
<property name="icon">
diff --git a/src/modinfo.cpp b/src/modinfo.cpp index bd4c1254..91f3c1a1 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -102,6 +102,7 @@ QString ModInfo::getContentTypeName(int contentType) case CONTENT_SKSE: return tr("Script Extender"); case CONTENT_SKYPROC: return tr("SkyProc Tools"); case CONTENT_MCM: return tr("MCM Data"); + case CONTENT_INI: return tr("INI files"); default: throw MyException(tr("invalid content type %1").arg(contentType)); } } @@ -286,9 +287,9 @@ int ModInfo::checkAllForUpdate(PluginContainer *pluginContainer, QObject *receiv int result = 0; std::vector<int> modIDs; - //I ought to store this, it's used elsewhere - IPluginGame const *game = qApp->property("managed_game").value<IPluginGame *>(); - if (game->nexusModOrganizerID()) { + // Normally this would be the managed game but MO2 is only uploaded to the Skyrim SE site right now + IPluginGame const *game = pluginContainer->managedGame("Skyrim Special Edition"); + if (game && game->nexusModOrganizerID()) { modIDs.push_back(game->nexusModOrganizerID()); checkChunkForUpdate(pluginContainer, modIDs, receiver, game->gameShortName()); modIDs.clear(); diff --git a/src/modinfo.h b/src/modinfo.h index 001a78dc..4cdd7bcf 100644 --- a/src/modinfo.h +++ b/src/modinfo.h @@ -84,10 +84,11 @@ public: CONTENT_SCRIPT,
CONTENT_SKSE,
CONTENT_SKYPROC,
- CONTENT_MCM
+ CONTENT_MCM,
+ CONTENT_INI
};
- static const int NUM_CONTENT_TYPES = CONTENT_MCM + 1;
+ static const int NUM_CONTENT_TYPES = CONTENT_INI + 1;
enum EHighlight {
HIGHLIGHT_NONE = 0,
diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index c19294f1..5b6ddcda 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -466,6 +466,10 @@ std::vector<ModInfo::EContent> ModInfoRegular::getContents() const if (dir.entryList(QStringList() << "*.bsa" << "*.ba2").size() > 0) { m_CachedContent.push_back(CONTENT_BSA); } + //use >1 for ini files since there is meta.ini in all mods already. + if (dir.entryList(QStringList() << "*.ini").size() > 1) { + m_CachedContent.push_back(CONTENT_INI); + } ScriptExtender *extender = qApp->property("managed_game") .value<IPluginGame *>() diff --git a/src/modlist.cpp b/src/modlist.cpp index 2d58081d..0d084c22 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -73,6 +73,7 @@ ModList::ModList(PluginContainer *pluginContainer, QObject *parent) m_ContentIcons[ModInfo::CONTENT_SOUND] = std::make_tuple(":/MO/gui/content/sound", tr("Sound or Music"));
m_ContentIcons[ModInfo::CONTENT_TEXTURE] = std::make_tuple(":/MO/gui/content/texture", tr("Textures"));
m_ContentIcons[ModInfo::CONTENT_MCM] = std::make_tuple(":/MO/gui/content/menu", tr("MCM Configuration"));
+ m_ContentIcons[ModInfo::CONTENT_INI] = std::make_tuple(":/MO/gui/content/inifile", tr("INI files"));
m_LastCheck.start();
}
@@ -353,7 +354,6 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const int highlight = modInfo->getHighlight();
if (highlight & ModInfo::HIGHLIGHT_IMPORTANT) return QBrush(Qt::darkRed);
else if (highlight & ModInfo::HIGHLIGHT_INVALID) return QBrush(Qt::darkGray);
- else if (highlight & ModInfo::HIGHLIGHT_PLUGIN) return QBrush(Qt::darkBlue);
} else if (column == COL_VERSION) {
if (!modInfo->getNewestVersion().isValid()) {
return QVariant();
@@ -367,11 +367,11 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const } else if ((role == Qt::BackgroundRole)
|| (role == ViewMarkingScrollBar::DEFAULT_ROLE)) {
if (modInfo->getHighlight() & ModInfo::HIGHLIGHT_PLUGIN) {
- return QColor(0, 0, 255, 32);
+ return QColor(0, 0, 255, 64);
} else if (m_Overwrite.find(modIndex) != m_Overwrite.end()) {
- return QColor(0, 255, 0, 32);
+ return QColor(0, 255, 0, 64);
} else if (m_Overwritten.find(modIndex) != m_Overwritten.end()) {
- return QColor(255, 0, 0, 32);
+ return QColor(255, 0, 0, 64);
} else {
return QVariant();
}
@@ -699,7 +699,9 @@ void ModList::modInfoChanged(ModInfo::Ptr info) int row = ModInfo::getIndex(info->name());
info->testValid();
+ emit aboutToChangeData();
emit dataChanged(index(row, 0), index(row, columnCount()));
+ emit postDataChanged();
} else {
qCritical("modInfoChanged not called after modInfoAboutToChange");
}
@@ -996,6 +998,15 @@ bool ModList::removeRows(int row, int count, const QModelIndex &parent) bool success = false;
+ if (count == 1) {
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(row);
+ std::vector<ModInfo::EFlag> flags = modInfo->getFlags();
+ if ((std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end()) && (QDir(modInfo->absolutePath()).count() > 2)) {
+ emit clearOverwrite();
+ success = true;
+ }
+ }
+
for (int i = 0; i < count; ++i) {
ModInfo::Ptr modInfo = ModInfo::getByIndex(row + i);
if (!modInfo->isRegular()) {
@@ -1107,6 +1118,7 @@ QString ModList::getColumnToolTip(int column) "<tr><td><img src=\":/MO/gui/content/skse\" width=32/></td><td>Script Extender plugins</td></tr>"
"<tr><td><img src=\":/MO/gui/content/skyproc\" width=32/></td><td>SkyProc Patcher</td></tr>"
"<tr><td><img src=\":/MO/gui/content/menu\" width=32/></td><td>Mod Configuration Menu</td></tr>"
+ "<tr><td><img src=\":/MO/gui/content/inifile\" width=32/></td><td>INI files</td></tr>"
"</table>");
case COL_INSTALLTIME: return tr("Time this mod was installed");
default: return tr("unknown");
@@ -1215,6 +1227,7 @@ bool ModList::eventFilter(QObject *obj, QEvent *event) } else if (keyEvent->key() == Qt::Key_Space) {
return toggleSelection(itemView);
}
+ return QAbstractItemModel::eventFilter(obj, event);
}
return QAbstractItemModel::eventFilter(obj, event);
}
diff --git a/src/modlist.h b/src/modlist.h index b5f18e98..2db98bd1 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -244,6 +244,11 @@ signals: */
void fileMoved(const QString &relativePath, const QString &oldOriginName, const QString &newOriginName);
+ /**
+ * @brief emitted to have the overwrite folder cleared
+ */
+ void clearOverwrite();
+
void aboutToChangeData();
void postDataChanged();
diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp index 435967c9..88084ae1 100644 --- a/src/modlistsortproxy.cpp +++ b/src/modlistsortproxy.cpp @@ -208,6 +208,16 @@ bool ModListSortProxy::lessThan(const QModelIndex &left, if (leftTime != rightTime)
return leftTime < rightTime;
} break;
+ case ModList::COL_GAME: {
+ if (leftMod->getGameName() != rightMod->getGameName()) {
+ lt = leftMod->getGameName() < rightMod->getGameName();
+ }
+ else {
+ int comp = QString::compare(leftMod->name(), rightMod->name(), Qt::CaseInsensitive);
+ if (comp != 0)
+ lt = comp < 0;
+ }
+ } break;
case ModList::COL_PRIORITY: {
// nop, already compared by priority
} break;
diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp index d2a52c7b..e97e9800 100644 --- a/src/nexusinterface.cpp +++ b/src/nexusinterface.cpp @@ -147,10 +147,7 @@ QAtomicInt NexusInterface::NXMRequestInfo::s_NextID(0); NexusInterface::NexusInterface(PluginContainer *pluginContainer)
: m_NMMVersion(), m_PluginContainer(pluginContainer)
{
- VS_FIXEDFILEINFO version = GetFileVersion(ToWString(QApplication::applicationFilePath()));
- m_MOVersion = VersionInfo(version.dwFileVersionMS >> 16,
- version.dwFileVersionMS & 0xFFFF,
- version.dwFileVersionLS >> 16);
+ m_MOVersion = createVersionInfo();
m_AccessManager = new NXMAccessManager(this, m_MOVersion.displayString());
m_DiskCache = new QNetworkDiskCache(this);
diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp index 05016e8f..426c8b9c 100644 --- a/src/nxmaccessmanager.cpp +++ b/src/nxmaccessmanager.cpp @@ -224,12 +224,12 @@ void NXMAccessManager::login(const QString &username, const QString &password) QString NXMAccessManager::userAgent(const QString &subModule) const
{
QStringList comments;
- comments << "compatible to Nexus Client v" + m_NMMVersion;
+ comments << "Nexus Client v" + m_NMMVersion;
if (!subModule.isEmpty()) {
comments << "module: " + subModule;
}
- return QString("Mod Organizer v%1 (%2)").arg(m_MOVersion, comments.join("; "));
+ return QString("Mod Organizer/%1 (%2)").arg(m_MOVersion, comments.join("; "));
}
diff --git a/src/organizer_en.ts b/src/organizer_en.ts index 0a604b27..01a4abcb 100644 --- a/src/organizer_en.ts +++ b/src/organizer_en.ts @@ -303,16 +303,21 @@ p, li { white-space: pre-wrap; } </message> <message> <location filename="downloadlist.cpp" line="66"/> + <source>Size</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlist.cpp" line="67"/> <source>Done</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlist.cpp" line="82"/> + <location filename="downloadlist.cpp" line="83"/> <source>Information missing, please select "Query Info" from the context menu to re-retrieve.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlist.cpp" line="89"/> + <location filename="downloadlist.cpp" line="90"/> <source>pending download</source> <translation type="unfinished"></translation> </message> @@ -326,27 +331,27 @@ p, li { white-space: pre-wrap; } <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidget.ui" line="99"/> - <location filename="downloadlistwidget.cpp" line="150"/> - <location filename="downloadlistwidget.cpp" line="152"/> + <location filename="downloadlistwidget.ui" line="102"/> + <location filename="downloadlistwidget.cpp" line="169"/> + <location filename="downloadlistwidget.cpp" line="171"/> <source>Done - Double Click to install</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidget.cpp" line="116"/> - <location filename="downloadlistwidget.cpp" line="118"/> + <location filename="downloadlistwidget.cpp" line="135"/> + <location filename="downloadlistwidget.cpp" line="137"/> <source>Paused - Double Click to resume</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidget.cpp" line="136"/> - <location filename="downloadlistwidget.cpp" line="138"/> + <location filename="downloadlistwidget.cpp" line="155"/> + <location filename="downloadlistwidget.cpp" line="157"/> <source>Installed - Double Click to re-install</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidget.cpp" line="143"/> - <location filename="downloadlistwidget.cpp" line="145"/> + <location filename="downloadlistwidget.cpp" line="162"/> + <location filename="downloadlistwidget.cpp" line="164"/> <source>Uninstalled - Double Click to re-install</source> <translation type="unfinished"></translation> </message> @@ -360,7 +365,7 @@ p, li { white-space: pre-wrap; } <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.ui" line="122"/> + <location filename="downloadlistwidgetcompact.ui" line="129"/> <source>Done</source> <translation type="unfinished"></translation> </message> @@ -368,528 +373,634 @@ p, li { white-space: pre-wrap; } <context> <name>DownloadListWidgetCompactDelegate</name> <message> - <location filename="downloadlistwidgetcompact.cpp" line="92"/> + <location filename="downloadlistwidgetcompact.cpp" line="109"/> <source>< game %1 mod %2 file %3 ></source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.cpp" line="97"/> + <location filename="downloadlistwidgetcompact.cpp" line="114"/> <source>Pending</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.cpp" line="120"/> + <location filename="downloadlistwidgetcompact.cpp" line="141"/> <source>Paused</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.cpp" line="122"/> + <location filename="downloadlistwidgetcompact.cpp" line="143"/> <source>Fetching Info 1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.cpp" line="124"/> + <location filename="downloadlistwidgetcompact.cpp" line="145"/> <source>Fetching Info 2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.cpp" line="129"/> + <location filename="downloadlistwidgetcompact.cpp" line="150"/> <source>Installed</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.cpp" line="131"/> + <location filename="downloadlistwidgetcompact.cpp" line="152"/> <source>Uninstalled</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.cpp" line="133"/> + <location filename="downloadlistwidgetcompact.cpp" line="154"/> <source>Done</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.cpp" line="242"/> - <location filename="downloadlistwidgetcompact.cpp" line="251"/> - <location filename="downloadlistwidgetcompact.cpp" line="260"/> - <location filename="downloadlistwidgetcompact.cpp" line="269"/> + <location filename="downloadlistwidgetcompact.cpp" line="233"/> + <location filename="downloadlistwidgetcompact.cpp" line="283"/> + <location filename="downloadlistwidgetcompact.cpp" line="292"/> + <location filename="downloadlistwidgetcompact.cpp" line="301"/> + <location filename="downloadlistwidgetcompact.cpp" line="310"/> + <location filename="downloadlistwidgetcompact.cpp" line="319"/> + <location filename="downloadlistwidgetcompact.cpp" line="328"/> <source>Are you sure?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.cpp" line="243"/> + <location filename="downloadlistwidgetcompact.cpp" line="234"/> + <source>This will permanently delete the selected download.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="284"/> <source>This will remove all finished downloads from this list and from disk.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.cpp" line="252"/> + <location filename="downloadlistwidgetcompact.cpp" line="293"/> <source>This will remove all installed downloads from this list and from disk.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.cpp" line="261"/> + <location filename="downloadlistwidgetcompact.cpp" line="302"/> + <source>This will remove all uninstalled downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="311"/> <source>This will permanently remove all finished downloads from this list (but NOT from disk).</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.cpp" line="270"/> + <location filename="downloadlistwidgetcompact.cpp" line="320"/> <source>This will permanently remove all installed downloads from this list (but NOT from disk).</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.cpp" line="299"/> + <location filename="downloadlistwidgetcompact.cpp" line="329"/> + <source>This will permanently remove all uninstalled downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="358"/> <source>Install</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.cpp" line="301"/> + <location filename="downloadlistwidgetcompact.cpp" line="360"/> <source>Query Info</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.cpp" line="303"/> + <location filename="downloadlistwidgetcompact.cpp" line="362"/> + <source>Visit on Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="364"/> + <location filename="downloadlistwidgetcompact.cpp" line="375"/> + <location filename="downloadlistwidgetcompact.cpp" line="379"/> + <source>Show in Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="366"/> <source>Delete</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.cpp" line="305"/> + <location filename="downloadlistwidgetcompact.cpp" line="368"/> <source>Un-Hide</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.cpp" line="307"/> + <location filename="downloadlistwidgetcompact.cpp" line="370"/> <source>Hide</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.cpp" line="310"/> + <location filename="downloadlistwidgetcompact.cpp" line="373"/> <source>Cancel</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.cpp" line="311"/> + <location filename="downloadlistwidgetcompact.cpp" line="374"/> <source>Pause</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.cpp" line="313"/> + <location filename="downloadlistwidgetcompact.cpp" line="377"/> <source>Remove</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.cpp" line="314"/> + <location filename="downloadlistwidgetcompact.cpp" line="378"/> <source>Resume</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.cpp" line="319"/> + <location filename="downloadlistwidgetcompact.cpp" line="383"/> <source>Delete Installed...</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.cpp" line="320"/> + <location filename="downloadlistwidgetcompact.cpp" line="384"/> + <source>Delete Uninstalled...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="385"/> <source>Delete All...</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.cpp" line="323"/> + <location filename="downloadlistwidgetcompact.cpp" line="388"/> <source>Hide Installed...</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidgetcompact.cpp" line="324"/> + <location filename="downloadlistwidgetcompact.cpp" line="389"/> + <source>Hide Uninstalled...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="390"/> <source>Hide All...</source> <translation type="unfinished"></translation> </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="394"/> + <source>Un-Hide All...</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>DownloadListWidgetDelegate</name> <message> - <location filename="downloadlistwidget.cpp" line="93"/> + <location filename="downloadlistwidget.cpp" line="112"/> <source>< game %1 mod %2 file %3 ></source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidget.cpp" line="96"/> + <location filename="downloadlistwidget.cpp" line="115"/> <source>Pending</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidget.cpp" line="123"/> + <location filename="downloadlistwidget.cpp" line="142"/> <source>Fetching Info 1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidget.cpp" line="126"/> + <location filename="downloadlistwidget.cpp" line="145"/> <source>Fetching Info 2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidget.cpp" line="259"/> - <location filename="downloadlistwidget.cpp" line="268"/> - <location filename="downloadlistwidget.cpp" line="277"/> - <location filename="downloadlistwidget.cpp" line="286"/> + <location filename="downloadlistwidget.cpp" line="324"/> + <location filename="downloadlistwidget.cpp" line="333"/> + <location filename="downloadlistwidget.cpp" line="342"/> <source>Are you sure?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidget.cpp" line="260"/> + <location filename="downloadlistwidget.cpp" line="298"/> <source>This will remove all finished downloads from this list and from disk.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidget.cpp" line="269"/> + <location filename="downloadlistwidget.cpp" line="248"/> + <location filename="downloadlistwidget.cpp" line="297"/> + <location filename="downloadlistwidget.cpp" line="306"/> + <location filename="downloadlistwidget.cpp" line="315"/> + <source>Delete Files?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="249"/> + <source>This will permanently delete the selected download.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="307"/> <source>This will remove all installed downloads from this list and from disk.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidget.cpp" line="278"/> + <location filename="downloadlistwidget.cpp" line="316"/> + <source>This will remove all uninstalled downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="325"/> <source>This will remove all finished downloads from this list (but NOT from disk).</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidget.cpp" line="287"/> + <location filename="downloadlistwidget.cpp" line="334"/> <source>This will remove all installed downloads from this list (but NOT from disk).</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidget.cpp" line="315"/> + <location filename="downloadlistwidget.cpp" line="343"/> + <source>This will remove all uninstalled downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="371"/> <source>Install</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidget.cpp" line="317"/> + <location filename="downloadlistwidget.cpp" line="373"/> <source>Query Info</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidget.cpp" line="319"/> + <location filename="downloadlistwidget.cpp" line="375"/> + <source>Visit on Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="378"/> + <location filename="downloadlistwidget.cpp" line="391"/> + <location filename="downloadlistwidget.cpp" line="395"/> + <source>Show in Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="382"/> + <location filename="downloadlistwidget.cpp" line="393"/> <source>Delete</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidget.cpp" line="321"/> + <location filename="downloadlistwidget.cpp" line="384"/> <source>Un-Hide</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidget.cpp" line="323"/> + <location filename="downloadlistwidget.cpp" line="386"/> <source>Hide</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidget.cpp" line="326"/> + <location filename="downloadlistwidget.cpp" line="389"/> <source>Cancel</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidget.cpp" line="327"/> + <location filename="downloadlistwidget.cpp" line="390"/> <source>Pause</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidget.cpp" line="329"/> - <source>Remove</source> + <location filename="downloadlistwidget.cpp" line="394"/> + <source>Resume</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidget.cpp" line="330"/> - <source>Resume</source> + <location filename="downloadlistwidget.cpp" line="400"/> + <source>Delete Installed...</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidget.cpp" line="335"/> - <source>Delete Installed...</source> + <location filename="downloadlistwidget.cpp" line="401"/> + <source>Delete Uninstalled...</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidget.cpp" line="336"/> + <location filename="downloadlistwidget.cpp" line="402"/> <source>Delete All...</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidget.cpp" line="339"/> + <location filename="downloadlistwidget.cpp" line="406"/> <source>Hide Installed...</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadlistwidget.cpp" line="340"/> + <location filename="downloadlistwidget.cpp" line="407"/> + <source>Hide Uninstalled...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="408"/> <source>Hide All...</source> <translation type="unfinished"></translation> </message> + <message> + <location filename="downloadlistwidget.cpp" line="412"/> + <source>Un-Hide All...</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>DownloadManager</name> <message> - <location filename="downloadmanager.cpp" line="155"/> + <location filename="downloadmanager.cpp" line="178"/> <source>failed to rename "%1" to "%2"</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="338"/> + <location filename="downloadmanager.cpp" line="389"/> <source>Memory allocation error (in refreshing directory).</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="424"/> + <location filename="downloadmanager.cpp" line="479"/> <source>failed to download %1: could not open output file: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="447"/> + <location filename="downloadmanager.cpp" line="502"/> <source>Download again?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="447"/> + <location filename="downloadmanager.cpp" line="502"/> <source>A file with the same name has already been downloaded. Do you want to download it again? The new file will receive a different name.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="489"/> + <location filename="downloadmanager.cpp" line="546"/> <source>Wrong Game</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="489"/> + <location filename="downloadmanager.cpp" line="546"/> <source>The download link is for a mod for "%1" but this instance of MO has been set up for "%2".</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="497"/> - <location filename="downloadmanager.cpp" line="508"/> + <location filename="downloadmanager.cpp" line="554"/> + <location filename="downloadmanager.cpp" line="565"/> <source>Already Started</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="497"/> + <location filename="downloadmanager.cpp" line="554"/> <source>A download for this mod file has already been queued.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="508"/> + <location filename="downloadmanager.cpp" line="565"/> <source>There is already a download started for this file (mod: %1, file: %2).</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="528"/> - <location filename="downloadmanager.cpp" line="630"/> + <location filename="downloadmanager.cpp" line="588"/> + <location filename="downloadmanager.cpp" line="725"/> <source>remove: invalid download index %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="546"/> + <location filename="downloadmanager.cpp" line="607"/> <source>failed to delete %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="552"/> + <location filename="downloadmanager.cpp" line="614"/> <source>failed to delete meta file for %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="595"/> + <location filename="downloadmanager.cpp" line="674"/> <source>restore: invalid download index: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="648"/> + <location filename="downloadmanager.cpp" line="747"/> <source>cancel: invalid download index %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="661"/> + <location filename="downloadmanager.cpp" line="760"/> <source>pause: invalid download index %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="681"/> + <location filename="downloadmanager.cpp" line="780"/> <source>resume: invalid download index %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="692"/> + <location filename="downloadmanager.cpp" line="791"/> <source>resume (int): invalid download index %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="707"/> + <location filename="downloadmanager.cpp" line="813"/> <source>No known download urls. Sorry, this download can't be resumed.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="745"/> + <location filename="downloadmanager.cpp" line="854"/> <source>query: invalid download index %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="767"/> + <location filename="downloadmanager.cpp" line="876"/> <source>Please enter the nexus mod id</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="767"/> + <location filename="downloadmanager.cpp" line="876"/> <source>Mod ID:</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="777"/> + <location filename="downloadmanager.cpp" line="886"/> <source>Please select the source game code for %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="807"/> + <location filename="downloadmanager.cpp" line="905"/> + <location filename="downloadmanager.cpp" line="933"/> + <source>VisitNexus: invalid download index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="926"/> + <source>Nexus ID for this Mod is unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="969"/> <source>get pending: invalid download index %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="816"/> + <location filename="downloadmanager.cpp" line="978"/> <source>get path: invalid download index %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="825"/> + <location filename="downloadmanager.cpp" line="987"/> <source>Main</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="826"/> + <location filename="downloadmanager.cpp" line="988"/> <source>Update</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="827"/> + <location filename="downloadmanager.cpp" line="989"/> <source>Optional</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="828"/> + <location filename="downloadmanager.cpp" line="990"/> <source>Old</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="829"/> + <location filename="downloadmanager.cpp" line="991"/> <source>Misc</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="830"/> + <location filename="downloadmanager.cpp" line="992"/> <source>Unknown</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="837"/> + <location filename="downloadmanager.cpp" line="999"/> <source>display name: invalid download index %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="857"/> + <location filename="downloadmanager.cpp" line="1019"/> <source>file name: invalid download index %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="866"/> + <location filename="downloadmanager.cpp" line="1028"/> <source>file time: invalid download index %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="880"/> + <location filename="downloadmanager.cpp" line="1042"/> <source>file size: invalid download index %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="890"/> + <location filename="downloadmanager.cpp" line="1052"/> <source>progress: invalid download index %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="900"/> + <location filename="downloadmanager.cpp" line="1062"/> <source>state: invalid download index %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="910"/> + <location filename="downloadmanager.cpp" line="1072"/> <source>infocomplete: invalid download index %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="925"/> - <location filename="downloadmanager.cpp" line="933"/> + <location filename="downloadmanager.cpp" line="1087"/> + <location filename="downloadmanager.cpp" line="1095"/> <source>mod id: invalid download index %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="941"/> + <location filename="downloadmanager.cpp" line="1103"/> <source>ishidden: invalid download index %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="950"/> + <location filename="downloadmanager.cpp" line="1112"/> <source>file info: invalid download index %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="960"/> + <location filename="downloadmanager.cpp" line="1122"/> <source>mark installed: invalid download index %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="995"/> + <location filename="downloadmanager.cpp" line="1167"/> <source>mark uninstalled: invalid download index %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="1156"/> + <location filename="downloadmanager.cpp" line="1340"/> <source>Memory allocation error (in processing progress event).</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="1169"/> + <location filename="downloadmanager.cpp" line="1353"/> <source>Memory allocation error (in processing downloaded data).</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="1303"/> + <location filename="downloadmanager.cpp" line="1491"/> <source>Information updated</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="1305"/> - <location filename="downloadmanager.cpp" line="1319"/> + <location filename="downloadmanager.cpp" line="1493"/> + <location filename="downloadmanager.cpp" line="1507"/> <source>No matching file found on Nexus! Maybe this file is no longer available or it was renamed?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="1307"/> + <location filename="downloadmanager.cpp" line="1495"/> <source>No file on Nexus matches the selected file by name. Please manually choose the correct one.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="1436"/> + <location filename="downloadmanager.cpp" line="1624"/> <source>No download server available. Please try again later.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="1479"/> + <location filename="downloadmanager.cpp" line="1667"/> <source>Failed to request file info from nexus: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="1506"/> + <location filename="downloadmanager.cpp" line="1694"/> <source>Warning: Content type is: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="1512"/> + <location filename="downloadmanager.cpp" line="1699"/> <source>Download header content length: %1 downloaded file size: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="1514"/> + <location filename="downloadmanager.cpp" line="1701"/> <source>Download failed: %1 (%2)</source> <translation type="unfinished"></translation> </message> <message> - <location filename="downloadmanager.cpp" line="1617"/> + <location filename="downloadmanager.cpp" line="1723"/> + <source>We were unable to download the file due to errors after four retries. There may be an issue with the Nexus servers.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="1806"/> <source>failed to re-open %1</source> <translation type="unfinished"></translation> </message> @@ -1256,7 +1367,6 @@ p, li { white-space: pre-wrap; } <location filename="installationmanager.cpp" line="857"/> <source>None of the available installer plugins were able to handle that archive. This is likely due to a corrupted or incompatible download or unrecognized archive format.</source> - <oldsource>None of the available installer plugins were able to handle that archive</oldsource> <translation type="unfinished"></translation> </message> <message> @@ -1397,7 +1507,7 @@ This is likely due to a corrupted or incompatible download or unrecognized archi <name>MainWindow</name> <message> <location filename="mainwindow.ui" line="46"/> - <location filename="mainwindow.ui" line="600"/> + <location filename="mainwindow.ui" line="590"/> <source>Categories</source> <translation type="unfinished"></translation> </message> @@ -1462,61 +1572,61 @@ p, li { white-space: pre-wrap; } <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="280"/> - <location filename="mainwindow.ui" line="866"/> + <location filename="mainwindow.ui" line="270"/> + <location filename="mainwindow.ui" line="856"/> <source>Restore Backup...</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="294"/> - <location filename="mainwindow.ui" line="886"/> + <location filename="mainwindow.ui" line="284"/> + <location filename="mainwindow.ui" line="876"/> <source>Create Backup</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="410"/> + <location filename="mainwindow.ui" line="400"/> <source>List of available mods.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="413"/> + <location filename="mainwindow.ui" line="403"/> <source>This is a list of installed mods. Use the checkboxes to activate/deactivate mods and drag & drop mods to change their "installation" orders.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="498"/> + <location filename="mainwindow.ui" line="488"/> <source>Filter</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="555"/> + <location filename="mainwindow.ui" line="545"/> <source>Clear all Filters</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="595"/> + <location filename="mainwindow.ui" line="585"/> <source>No groups</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="605"/> + <location filename="mainwindow.ui" line="595"/> <source>Nexus IDs</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="619"/> - <location filename="mainwindow.ui" line="1003"/> - <location filename="mainwindow.ui" line="1356"/> + <location filename="mainwindow.ui" line="609"/> + <location filename="mainwindow.ui" line="999"/> + <location filename="mainwindow.ui" line="1316"/> <source>Namefilter</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="654"/> + <location filename="mainwindow.ui" line="644"/> <source>Pick a program to run.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="657"/> + <location filename="mainwindow.ui" line="647"/> <source><!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; } @@ -1526,12 +1636,12 @@ p, li { white-space: pre-wrap; } <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="705"/> + <location filename="mainwindow.ui" line="695"/> <source>Run program</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="708"/> + <location filename="mainwindow.ui" line="698"/> <source><!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; } @@ -1540,17 +1650,17 @@ p, li { white-space: pre-wrap; } <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="718"/> + <location filename="mainwindow.ui" line="708"/> <source>Run</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="759"/> + <location filename="mainwindow.ui" line="749"/> <source>Create a shortcut in your start menu or on the desktop to the specified program</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="762"/> + <location filename="mainwindow.ui" line="752"/> <source><!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; } @@ -1559,27 +1669,27 @@ p, li { white-space: pre-wrap; } <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="769"/> + <location filename="mainwindow.ui" line="759"/> <source>Shortcut</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="819"/> + <location filename="mainwindow.ui" line="809"/> <source>Plugins</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="842"/> + <location filename="mainwindow.ui" line="832"/> <source>Sort</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="948"/> + <location filename="mainwindow.ui" line="938"/> <source>List of available esp/esm files</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="951"/> + <location filename="mainwindow.ui" line="941"/> <source><!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; } @@ -1588,27 +1698,27 @@ p, li { white-space: pre-wrap; } <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1016"/> + <location filename="mainwindow.ui" line="1012"/> <source>Archives</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1049"/> + <location filename="mainwindow.ui" line="1032"/> <source><html><head/><body><p>BSAs / BA2s are bundles of game assets (textures, scripts, etc.). By default, the engine loads these bundles in a separate step from loose files. <p>Their load order is specified by the priority of the corresponding plugin (right pane, plugins tab).</p><p>If there is a matching plugin, the game will load them no matter what.</p></body></html></source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1052"/> + <location filename="mainwindow.ui" line="1035"/> <source><html><head/><body><p>Currently detected archives. (<a href="#"><span style=" text-decoration: underline; color:#0000ff;">What is an archive?</span></a>)</p></body></html></source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1067"/> + <location filename="mainwindow.ui" line="1050"/> <source>List of available BS Archives. Archives not checked here are not managed by MO and ignore installation order.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1070"/> + <location filename="mainwindow.ui" line="1053"/> <source>BSA files are archives (comparable to .zip files) that contain data assets (meshes, textures, ...) to be used by the game. As such they "compete" with loose files in your data directory over which is loaded. By default, BSAs that share their base name with an enabled ESP (i.e. plugin.esp and plugin.bsa) are automatically loaded and will have precedence over all loose files, the installation order you set up to the left is then ignored! @@ -1616,61 +1726,60 @@ p, li { white-space: pre-wrap; } <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1116"/> - <location filename="mainwindow.ui" line="1175"/> + <location filename="mainwindow.ui" line="1132"/> <source>File</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1125"/> + <location filename="mainwindow.ui" line="1082"/> <source>Data</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1143"/> + <location filename="mainwindow.ui" line="1100"/> <source>refresh data-directory overview</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1146"/> + <location filename="mainwindow.ui" line="1103"/> <source>Refresh the overview. This may take a moment.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1149"/> - <location filename="mainwindow.cpp" line="3395"/> - <location filename="mainwindow.cpp" line="4183"/> + <location filename="mainwindow.ui" line="1106"/> + <location filename="mainwindow.cpp" line="3505"/> + <location filename="mainwindow.cpp" line="4293"/> <source>Refresh</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1165"/> + <location filename="mainwindow.ui" line="1122"/> <source>This is an overview of your data directory as visible to the game (and tools). </source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1180"/> + <location filename="mainwindow.ui" line="1137"/> <source>Mod</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1190"/> - <location filename="mainwindow.ui" line="1193"/> + <location filename="mainwindow.ui" line="1147"/> + <location filename="mainwindow.ui" line="1150"/> <source>Filter the above list so that only conflicts are displayed.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1196"/> + <location filename="mainwindow.ui" line="1153"/> <source>Show only conflicts</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1204"/> + <location filename="mainwindow.ui" line="1161"/> <source>Saves</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1228"/> + <location filename="mainwindow.ui" line="1185"/> <source><!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; } @@ -1681,155 +1790,155 @@ p, li { white-space: pre-wrap; } <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1248"/> + <location filename="mainwindow.ui" line="1205"/> <source>Downloads</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1283"/> + <location filename="mainwindow.ui" line="1240"/> <source>This is a list of mods you downloaded from Nexus. Double click one to install it. You can also drag an archive into here.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1336"/> + <location filename="mainwindow.ui" line="1296"/> <source>Show Hidden</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1398"/> + <location filename="mainwindow.ui" line="1358"/> <source>Tool Bar</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1441"/> + <location filename="mainwindow.ui" line="1401"/> <source>Install Mod</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1444"/> + <location filename="mainwindow.ui" line="1404"/> <source>Install &Mod</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1447"/> + <location filename="mainwindow.ui" line="1407"/> <source>Install a new mod from an archive</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1450"/> + <location filename="mainwindow.ui" line="1410"/> <source>Ctrl+M</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1459"/> + <location filename="mainwindow.ui" line="1419"/> <source>Profiles</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1462"/> + <location filename="mainwindow.ui" line="1422"/> <source>&Profiles</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1465"/> + <location filename="mainwindow.ui" line="1425"/> <source>Configure Profiles</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1468"/> + <location filename="mainwindow.ui" line="1428"/> <source>Ctrl+P</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1477"/> + <location filename="mainwindow.ui" line="1437"/> <source>Executables</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1480"/> + <location filename="mainwindow.ui" line="1440"/> <source>&Executables</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1483"/> + <location filename="mainwindow.ui" line="1443"/> <source>Configure the executables that can be started through Mod Organizer</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1486"/> + <location filename="mainwindow.ui" line="1446"/> <source>Ctrl+E</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1495"/> - <location filename="mainwindow.ui" line="1501"/> + <location filename="mainwindow.ui" line="1455"/> + <location filename="mainwindow.ui" line="1461"/> <source>Tools</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1498"/> + <location filename="mainwindow.ui" line="1458"/> <source>&Tools</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1504"/> + <location filename="mainwindow.ui" line="1464"/> <source>Ctrl+I</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1513"/> + <location filename="mainwindow.ui" line="1473"/> <source>Settings</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1516"/> + <location filename="mainwindow.ui" line="1476"/> <source>&Settings</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1519"/> + <location filename="mainwindow.ui" line="1479"/> <source>Configure settings and workarounds</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1522"/> + <location filename="mainwindow.ui" line="1482"/> <source>Ctrl+S</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1531"/> + <location filename="mainwindow.ui" line="1491"/> <source>Nexus</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1534"/> + <location filename="mainwindow.ui" line="1494"/> <source>Search nexus network for more mods</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1537"/> + <location filename="mainwindow.ui" line="1497"/> <source>Ctrl+N</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1549"/> - <location filename="mainwindow.cpp" line="4124"/> + <location filename="mainwindow.ui" line="1509"/> + <location filename="mainwindow.cpp" line="4234"/> <source>Update</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1552"/> + <location filename="mainwindow.ui" line="1512"/> <source>Mod Organizer is up-to-date</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1564"/> - <location filename="mainwindow.cpp" line="628"/> + <location filename="mainwindow.ui" line="1524"/> + <location filename="mainwindow.cpp" line="630"/> <source>No Problems</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1567"/> + <location filename="mainwindow.ui" line="1527"/> <source>This button will be highlighted if MO discovered potential problems in your setup and provide tips on how to fix them. !Work in progress! @@ -1837,730 +1946,740 @@ Right now this has very limited functionality</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1579"/> - <location filename="mainwindow.ui" line="1582"/> + <location filename="mainwindow.ui" line="1539"/> + <location filename="mainwindow.ui" line="1542"/> <source>Help</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1585"/> + <location filename="mainwindow.ui" line="1545"/> <source>Ctrl+H</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1594"/> + <location filename="mainwindow.ui" line="1554"/> <source>Endorse MO</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1597"/> - <location filename="mainwindow.cpp" line="4202"/> + <location filename="mainwindow.ui" line="1557"/> + <location filename="mainwindow.cpp" line="4316"/> <source>Endorse Mod Organizer</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1602"/> + <location filename="mainwindow.ui" line="1562"/> <source>Copy Log to Clipboard</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1605"/> + <location filename="mainwindow.ui" line="1565"/> <source>Ctrl+C</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1614"/> + <location filename="mainwindow.ui" line="1574"/> <source>Change Game</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.ui" line="1617"/> + <location filename="mainwindow.ui" line="1577"/> <source>Open the Instance selection dialog to manage a different Game</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="300"/> + <location filename="mainwindow.cpp" line="321"/> <source>Toolbar</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="301"/> + <location filename="mainwindow.cpp" line="322"/> <source>Desktop</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="302"/> + <location filename="mainwindow.cpp" line="323"/> <source>Start Menu</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="326"/> + <location filename="mainwindow.cpp" line="347"/> <source>There is no supported sort mechanism for this game. You will probably have to use a third-party tool.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="616"/> + <location filename="mainwindow.cpp" line="618"/> <source>Problems</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="617"/> + <location filename="mainwindow.cpp" line="619"/> <source>There are potential problems with your setup</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="629"/> + <location filename="mainwindow.cpp" line="631"/> <source>Everything seems to be in order</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="691"/> + <location filename="mainwindow.cpp" line="693"/> <source>Help on UI</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="695"/> + <location filename="mainwindow.cpp" line="697"/> <source>Documentation Wiki</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="699"/> + <location filename="mainwindow.cpp" line="701"/> <source>Report Issue</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="703"/> + <location filename="mainwindow.cpp" line="705"/> <source>Tutorials</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="742"/> + <location filename="mainwindow.cpp" line="744"/> <source>About</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="743"/> + <location filename="mainwindow.cpp" line="745"/> <source>About Qt</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="795"/> + <location filename="mainwindow.cpp" line="797"/> <source>Name</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="796"/> + <location filename="mainwindow.cpp" line="798"/> <source>Please enter a name for the new profile</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="804"/> + <location filename="mainwindow.cpp" line="806"/> <source>failed to create profile: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="848"/> + <location filename="mainwindow.cpp" line="850"/> <source>Show tutorial?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="849"/> + <location filename="mainwindow.cpp" line="851"/> <source>You are starting Mod Organizer for the first time. Do you want to show a tutorial of its basic features? If you choose no you can always start the tutorial from the "Help"-menu.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="885"/> + <location filename="mainwindow.cpp" line="887"/> <source>Downloads in progress</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="886"/> + <location filename="mainwindow.cpp" line="888"/> <source>There are still downloads in progress, do you really want to quit?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="1003"/> + <location filename="mainwindow.cpp" line="1005"/> <source>Plugin "%1" failed: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="1005"/> + <location filename="mainwindow.cpp" line="1007"/> <source>Plugin "%1" failed</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="1041"/> + <location filename="mainwindow.cpp" line="1043"/> <source>Browse Mod Page</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="1176"/> + <location filename="mainwindow.cpp" line="1178"/> <source>Also in: <br></source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="1187"/> + <location filename="mainwindow.cpp" line="1189"/> <source>No conflict</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="1299"/> + <location filename="mainwindow.cpp" line="1301"/> <source><Edit...></source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="1567"/> + <location filename="mainwindow.cpp" line="1569"/> <source>This bsa is enabled in the ini file so it may be required!</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="1629"/> + <location filename="mainwindow.cpp" line="1631"/> <source>Activating Network Proxy</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="1687"/> + <location filename="mainwindow.cpp" line="1689"/> <source>Notice: Your current MO version (%1) is lower than the previous version (%2).<br>The GUI may not downgrade gracefully, so you may experience oddities.<br>However, there should be no serious issues.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="1776"/> + <location filename="mainwindow.cpp" line="1778"/> <source>Choose Mod</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="1777"/> + <location filename="mainwindow.cpp" line="1779"/> <source>Mod Archive</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="1939"/> + <location filename="mainwindow.cpp" line="1941"/> <source>Start Tutorial?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="1940"/> + <location filename="mainwindow.cpp" line="1942"/> <source>You're about to start a tutorial. For technical reasons it's not possible to end the tutorial early. Continue?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2076"/> + <location filename="mainwindow.cpp" line="2078"/> <source>failed to spawn notepad.exe: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2116"/> + <location filename="mainwindow.cpp" line="2118"/> <source>failed to change origin name: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2140"/> + <location filename="mainwindow.cpp" line="2142"/> <source>failed to move "%1" from mod "%2" to "%3": %4</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2164"/> + <location filename="mainwindow.cpp" line="2166"/> <source><Contains %1></source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2199"/> + <location filename="mainwindow.cpp" line="2201"/> <source><Checked></source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2200"/> + <location filename="mainwindow.cpp" line="2202"/> <source><Unchecked></source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2201"/> + <location filename="mainwindow.cpp" line="2203"/> <source><Update></source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2202"/> + <location filename="mainwindow.cpp" line="2204"/> <source><Managed by MO></source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2203"/> + <location filename="mainwindow.cpp" line="2205"/> <source><Managed outside MO></source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2204"/> + <location filename="mainwindow.cpp" line="2206"/> <source><No category></source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2205"/> + <location filename="mainwindow.cpp" line="2207"/> <source><Conflicted></source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2206"/> + <location filename="mainwindow.cpp" line="2208"/> <source><Not Endorsed></source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2252"/> + <location filename="mainwindow.cpp" line="2254"/> <source>failed to rename mod: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2265"/> + <location filename="mainwindow.cpp" line="2267"/> <source>Overwrite?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2266"/> + <location filename="mainwindow.cpp" line="2268"/> <source>This will replace the existing mod "%1". Continue?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2269"/> + <location filename="mainwindow.cpp" line="2271"/> <source>failed to remove mod "%1"</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2273"/> - <location filename="mainwindow.cpp" line="4008"/> - <location filename="mainwindow.cpp" line="4032"/> + <location filename="mainwindow.cpp" line="2275"/> + <location filename="mainwindow.cpp" line="4118"/> + <location filename="mainwindow.cpp" line="4142"/> <source>failed to rename "%1" to "%2"</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2333"/> - <location filename="mainwindow.cpp" line="3126"/> - <location filename="mainwindow.cpp" line="3134"/> - <location filename="mainwindow.cpp" line="3592"/> + <location filename="mainwindow.cpp" line="2335"/> + <location filename="mainwindow.cpp" line="3228"/> + <location filename="mainwindow.cpp" line="3236"/> + <location filename="mainwindow.cpp" line="3702"/> <source>Confirm</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2334"/> + <location filename="mainwindow.cpp" line="2336"/> <source>Remove the following mods?<br><ul>%1</ul></source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2345"/> + <location filename="mainwindow.cpp" line="2349"/> <source>failed to remove mod: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2377"/> - <location filename="mainwindow.cpp" line="2380"/> + <location filename="mainwindow.cpp" line="2381"/> + <location filename="mainwindow.cpp" line="2384"/> <source>Failed</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2377"/> + <location filename="mainwindow.cpp" line="2381"/> <source>Installation file no longer exists</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2381"/> + <location filename="mainwindow.cpp" line="2385"/> <source>Mods installed with old versions of MO can't be reinstalled in this way.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2398"/> + <location filename="mainwindow.cpp" line="2402"/> <source>You need to be logged in with Nexus to resume a download</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2414"/> - <location filename="mainwindow.cpp" line="2441"/> + <location filename="mainwindow.cpp" line="2418"/> + <location filename="mainwindow.cpp" line="2445"/> <source>You need to be logged in with Nexus to endorse</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2489"/> + <location filename="mainwindow.cpp" line="2493"/> <source>Failed to display overwrite dialog: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2642"/> + <location filename="mainwindow.cpp" line="2673"/> <source>Nexus ID for this Mod is unknown</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2652"/> + <location filename="mainwindow.cpp" line="2683"/> <source>Web page for this mod is unknown</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2722"/> - <location filename="mainwindow.cpp" line="2751"/> - <location filename="mainwindow.cpp" line="3425"/> + <location filename="mainwindow.cpp" line="2761"/> + <location filename="mainwindow.cpp" line="2790"/> + <location filename="mainwindow.cpp" line="3535"/> <source>Create Mod...</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2723"/> + <location filename="mainwindow.cpp" line="2762"/> <source>This will create an empty mod. Please enter a name:</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2732"/> - <location filename="mainwindow.cpp" line="2761"/> + <location filename="mainwindow.cpp" line="2771"/> + <location filename="mainwindow.cpp" line="2800"/> <source>A mod with this name already exists</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2752"/> + <location filename="mainwindow.cpp" line="2791"/> <source>This will move all files from overwrite into a new, regular mod. Please enter a name:</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2793"/> - <location filename="mainwindow.cpp" line="4513"/> + <location filename="mainwindow.cpp" line="2832"/> + <location filename="mainwindow.cpp" line="4634"/> <source>Are you sure?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="2794"/> + <location filename="mainwindow.cpp" line="2833"/> <source>About to recursively delete: </source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3038"/> + <location filename="mainwindow.cpp" line="3122"/> <source>Not logged in, endorsement information will be wrong</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3046"/> + <location filename="mainwindow.cpp" line="3130"/> <source>Continue?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3047"/> + <location filename="mainwindow.cpp" line="3131"/> <source>The versioning scheme decides which version is considered newer than another. This function will guess the versioning scheme under the assumption that the installed version is outdated.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3067"/> - <location filename="mainwindow.cpp" line="4092"/> + <location filename="mainwindow.cpp" line="3151"/> + <location filename="mainwindow.cpp" line="4202"/> <source>Sorry</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3068"/> + <location filename="mainwindow.cpp" line="3152"/> <source>I don't know a versioning scheme where %1 is newer than %2.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3126"/> + <location filename="mainwindow.cpp" line="3228"/> <source>Really enable all visible mods?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3134"/> + <location filename="mainwindow.cpp" line="3236"/> <source>Really disable all visible mods?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3187"/> + <location filename="mainwindow.cpp" line="3301"/> <source>Export to csv</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3190"/> + <location filename="mainwindow.cpp" line="3304"/> <source>CSV (Comma Separated Values) is a format that can be imported in programs like Excel to create a spreadsheet. You can also use online editors and converters instead.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3193"/> + <location filename="mainwindow.cpp" line="3307"/> <source>Select what mods you want export:</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3194"/> + <location filename="mainwindow.cpp" line="3308"/> <source>All installed mods</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3195"/> + <location filename="mainwindow.cpp" line="3309"/> <source>Only active (checked) mods from your current profile</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3196"/> + <location filename="mainwindow.cpp" line="3310"/> <source>All currently visible mods in the mod list</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3217"/> + <location filename="mainwindow.cpp" line="3331"/> <source>Choose what Columns to export:</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3220"/> + <location filename="mainwindow.cpp" line="3334"/> <source>Mod_Priority</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3222"/> + <location filename="mainwindow.cpp" line="3336"/> <source>Mod_Name</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3224"/> + <location filename="mainwindow.cpp" line="3338"/> <source>Mod_Status</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3225"/> + <location filename="mainwindow.cpp" line="3339"/> <source>Primary_Category</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3226"/> + <location filename="mainwindow.cpp" line="3340"/> <source>Nexus_ID</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3227"/> + <location filename="mainwindow.cpp" line="3341"/> <source>Mod_Nexus_URL</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3228"/> + <location filename="mainwindow.cpp" line="3342"/> <source>Mod_Version</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3229"/> + <location filename="mainwindow.cpp" line="3343"/> <source>Install_Date</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3230"/> + <location filename="mainwindow.cpp" line="3344"/> <source>Download_File_Name</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3332"/> + <location filename="mainwindow.cpp" line="3446"/> <source>export failed: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3351"/> + <location filename="mainwindow.cpp" line="3465"/> <source>Open Game folder</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3353"/> + <location filename="mainwindow.cpp" line="3467"/> <source>Open MyGames folder</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3357"/> + <location filename="mainwindow.cpp" line="3471"/> <source>Open Instance folder</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3359"/> + <location filename="mainwindow.cpp" line="3473"/> + <source>Open Mods folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3475"/> <source>Open Profile folder</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3361"/> + <location filename="mainwindow.cpp" line="3477"/> <source>Open Downloads folder</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3365"/> + <location filename="mainwindow.cpp" line="3481"/> <source>Open MO2 Install folder</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3367"/> + <location filename="mainwindow.cpp" line="3483"/> + <source>Open MO2 Plugins folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3485"/> <source>Open MO2 Logs folder</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3384"/> + <location filename="mainwindow.cpp" line="3494"/> <source>Install Mod...</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3386"/> + <location filename="mainwindow.cpp" line="3496"/> <source>Create empty mod</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3390"/> + <location filename="mainwindow.cpp" line="3500"/> <source>Enable all visible</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3391"/> + <location filename="mainwindow.cpp" line="3501"/> <source>Disable all visible</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3393"/> + <location filename="mainwindow.cpp" line="3503"/> <source>Check all for update</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3397"/> + <location filename="mainwindow.cpp" line="3507"/> <source>Export to csv...</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3418"/> + <location filename="mainwindow.cpp" line="3528"/> <source>All Mods</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3424"/> + <location filename="mainwindow.cpp" line="3534"/> <source>Sync to Mods...</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3426"/> + <location filename="mainwindow.cpp" line="3536"/> <source>Clear Overwrite...</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3428"/> - <location filename="mainwindow.cpp" line="3508"/> + <location filename="mainwindow.cpp" line="3538"/> + <location filename="mainwindow.cpp" line="3618"/> <source>Open in explorer</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3430"/> + <location filename="mainwindow.cpp" line="3540"/> <source>Restore Backup</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3431"/> + <location filename="mainwindow.cpp" line="3541"/> <source>Remove Backup...</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3435"/> + <location filename="mainwindow.cpp" line="3545"/> <source>Change Categories</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3448"/> + <location filename="mainwindow.cpp" line="3558"/> <source>Primary Category</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3454"/> + <location filename="mainwindow.cpp" line="3564"/> <source>Change versioning scheme</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3458"/> + <location filename="mainwindow.cpp" line="3568"/> <source>Un-ignore update</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3460"/> + <location filename="mainwindow.cpp" line="3570"/> <source>Ignore update</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3465"/> + <location filename="mainwindow.cpp" line="3575"/> <source>Rename Mod...</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3466"/> + <location filename="mainwindow.cpp" line="3576"/> <source>Reinstall Mod</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3467"/> + <location filename="mainwindow.cpp" line="3577"/> <source>Remove Mod...</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3474"/> + <location filename="mainwindow.cpp" line="3584"/> <source>Un-Endorse</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3477"/> - <location filename="mainwindow.cpp" line="3481"/> + <location filename="mainwindow.cpp" line="3587"/> + <location filename="mainwindow.cpp" line="3591"/> <source>Endorse</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3478"/> + <location filename="mainwindow.cpp" line="3588"/> <source>Won't endorse</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3484"/> + <location filename="mainwindow.cpp" line="3594"/> <source>Endorsement state unknown</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3495"/> + <location filename="mainwindow.cpp" line="3605"/> <source>Ignore missing data</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3499"/> + <location filename="mainwindow.cpp" line="3609"/> <source>Mark as converted/working</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3503"/> + <location filename="mainwindow.cpp" line="3613"/> <source>Visit on Nexus</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3505"/> + <location filename="mainwindow.cpp" line="3615"/> <source>Visit web page</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3512"/> + <location filename="mainwindow.cpp" line="3622"/> <source>Information...</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3519"/> - <location filename="mainwindow.cpp" line="4646"/> + <location filename="mainwindow.cpp" line="3629"/> + <location filename="mainwindow.cpp" line="4767"/> <source>Exception: </source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3521"/> - <location filename="mainwindow.cpp" line="4648"/> + <location filename="mainwindow.cpp" line="3631"/> + <location filename="mainwindow.cpp" line="4769"/> <source>Unknown exception</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3552"/> + <location filename="mainwindow.cpp" line="3662"/> <source><All></source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3554"/> + <location filename="mainwindow.cpp" line="3664"/> <source><Multiple></source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3589"/> + <location filename="mainwindow.cpp" line="3699"/> <source>%1 more</source> <translation type="unfinished"></translation> </message> <message numerus="yes"> - <location filename="mainwindow.cpp" line="3593"/> + <location filename="mainwindow.cpp" line="3703"/> <source>Are you sure you want to remove the following %n save(s)?<br><ul>%1</ul><br>Removed saves will be sent to the Recycle Bin.</source> <translation type="unfinished"> <numerusform></numerusform> @@ -2568,12 +2687,12 @@ You can also use online editors and converters instead.</source> </translation> </message> <message> - <location filename="mainwindow.cpp" line="3638"/> + <location filename="mainwindow.cpp" line="3748"/> <source>Enable Mods...</source> <translation type="unfinished"></translation> </message> <message numerus="yes"> - <location filename="mainwindow.cpp" line="3653"/> + <location filename="mainwindow.cpp" line="3763"/> <source>Delete %n save(s)</source> <translation type="unfinished"> <numerusform></numerusform> @@ -2581,319 +2700,319 @@ You can also use online editors and converters instead.</source> </translation> </message> <message> - <location filename="mainwindow.cpp" line="3695"/> + <location filename="mainwindow.cpp" line="3805"/> <source>failed to remove %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3717"/> + <location filename="mainwindow.cpp" line="3827"/> <source>failed to create %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3759"/> + <location filename="mainwindow.cpp" line="3869"/> <source>Can't change download directory while downloads are in progress!</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3880"/> + <location filename="mainwindow.cpp" line="3990"/> <source>failed to write to file %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3886"/> + <location filename="mainwindow.cpp" line="3996"/> <source>%1 written</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3927"/> + <location filename="mainwindow.cpp" line="4037"/> <source>Select binary</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3927"/> + <location filename="mainwindow.cpp" line="4037"/> <source>Binary</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3953"/> + <location filename="mainwindow.cpp" line="4063"/> <source>Enter Name</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3954"/> + <location filename="mainwindow.cpp" line="4064"/> <source>Please enter a name for the executable</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3968"/> + <location filename="mainwindow.cpp" line="4078"/> <source>Not an executable</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3968"/> + <location filename="mainwindow.cpp" line="4078"/> <source>This is not a recognized executable.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3993"/> - <location filename="mainwindow.cpp" line="4018"/> + <location filename="mainwindow.cpp" line="4103"/> + <location filename="mainwindow.cpp" line="4128"/> <source>Replace file?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3993"/> + <location filename="mainwindow.cpp" line="4103"/> <source>There already is a hidden version of this file. Replace it?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3996"/> - <location filename="mainwindow.cpp" line="4021"/> + <location filename="mainwindow.cpp" line="4106"/> + <location filename="mainwindow.cpp" line="4131"/> <source>File operation failed</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="3996"/> - <location filename="mainwindow.cpp" line="4021"/> + <location filename="mainwindow.cpp" line="4106"/> + <location filename="mainwindow.cpp" line="4131"/> <source>Failed to remove "%1". Maybe you lack the required file permissions?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4018"/> + <location filename="mainwindow.cpp" line="4128"/> <source>There already is a visible version of this file. Replace it?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4065"/> + <location filename="mainwindow.cpp" line="4175"/> <source>file not found: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4078"/> + <location filename="mainwindow.cpp" line="4188"/> <source>failed to generate preview for %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4092"/> + <location filename="mainwindow.cpp" line="4202"/> <source>Sorry, can't preview anything. This function currently does not support extracting from bsas.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4126"/> + <location filename="mainwindow.cpp" line="4236"/> <source>Update available</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4163"/> + <location filename="mainwindow.cpp" line="4273"/> <source>Open/Execute</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4164"/> + <location filename="mainwindow.cpp" line="4274"/> <source>Add as Executable</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4168"/> + <location filename="mainwindow.cpp" line="4278"/> <source>Preview</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4174"/> + <location filename="mainwindow.cpp" line="4284"/> <source>Un-Hide</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4176"/> + <location filename="mainwindow.cpp" line="4286"/> <source>Hide</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4182"/> + <location filename="mainwindow.cpp" line="4292"/> <source>Write To File...</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4203"/> + <location filename="mainwindow.cpp" line="4317"/> <source>Do you want to endorse Mod Organizer on %1 now?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4322"/> + <location filename="mainwindow.cpp" line="4443"/> <source>Thank you!</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4322"/> + <location filename="mainwindow.cpp" line="4443"/> <source>Thank you for your endorsement!</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4357"/> + <location filename="mainwindow.cpp" line="4478"/> <source>Request to Nexus failed: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4372"/> - <location filename="mainwindow.cpp" line="4434"/> + <location filename="mainwindow.cpp" line="4493"/> + <location filename="mainwindow.cpp" line="4555"/> <source>failed to read %1: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4384"/> - <location filename="mainwindow.cpp" line="4833"/> + <location filename="mainwindow.cpp" line="4505"/> + <location filename="mainwindow.cpp" line="4954"/> <source>Error</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4384"/> + <location filename="mainwindow.cpp" line="4505"/> <source>failed to extract %1 (errorcode %2)</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4416"/> + <location filename="mainwindow.cpp" line="4537"/> <source>Extract BSA</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4445"/> + <location filename="mainwindow.cpp" line="4566"/> <source>This archive contains invalid hashes. Some files may be broken.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4491"/> + <location filename="mainwindow.cpp" line="4612"/> <source>Extract...</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4514"/> + <location filename="mainwindow.cpp" line="4635"/> <source>This will restart MO, continue?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4554"/> + <location filename="mainwindow.cpp" line="4675"/> <source>Edit Categories...</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4555"/> + <location filename="mainwindow.cpp" line="4676"/> <source>Deselect filter</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4606"/> + <location filename="mainwindow.cpp" line="4727"/> <source>Remove</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4617"/> + <location filename="mainwindow.cpp" line="4738"/> <source>Enable all</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4618"/> + <location filename="mainwindow.cpp" line="4739"/> <source>Disable all</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4637"/> + <location filename="mainwindow.cpp" line="4758"/> <source>Unlock load order</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4640"/> + <location filename="mainwindow.cpp" line="4761"/> <source>Lock load order</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4782"/> + <location filename="mainwindow.cpp" line="4903"/> <source>depends on missing "%1"</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4786"/> + <location filename="mainwindow.cpp" line="4907"/> <source>incompatible with "%1"</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4812"/> + <location filename="mainwindow.cpp" line="4933"/> <source>Please wait while LOOT is running</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4906"/> + <location filename="mainwindow.cpp" line="5027"/> <source>loot failed. Exit code was: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4928"/> + <location filename="mainwindow.cpp" line="5049"/> <source>failed to start loot</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4931"/> + <location filename="mainwindow.cpp" line="5052"/> <source>failed to run loot: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4935"/> + <location filename="mainwindow.cpp" line="5056"/> <source>Errors occured</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4982"/> + <location filename="mainwindow.cpp" line="5103"/> <source>Backup of load order created</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="4992"/> + <location filename="mainwindow.cpp" line="5113"/> <source>Choose backup to restore</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="5005"/> + <location filename="mainwindow.cpp" line="5126"/> <source>No Backups</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="5005"/> + <location filename="mainwindow.cpp" line="5126"/> <source>There are no backups to restore</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="5026"/> - <location filename="mainwindow.cpp" line="5048"/> + <location filename="mainwindow.cpp" line="5147"/> + <location filename="mainwindow.cpp" line="5169"/> <source>Restore failed</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="5027"/> - <location filename="mainwindow.cpp" line="5049"/> + <location filename="mainwindow.cpp" line="5148"/> + <location filename="mainwindow.cpp" line="5170"/> <source>Failed to restore the backup. Errorcode: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="5038"/> + <location filename="mainwindow.cpp" line="5159"/> <source>Backup of modlist created</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="5144"/> + <location filename="mainwindow.cpp" line="5265"/> <source>A file with the same name has already been downloaded. What would you like to do?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="5146"/> + <location filename="mainwindow.cpp" line="5267"/> <source>Overwrite</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="5147"/> + <location filename="mainwindow.cpp" line="5268"/> <source>Rename new file</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="5148"/> + <location filename="mainwindow.cpp" line="5269"/> <source>Ignore file</source> <translation type="unfinished"></translation> </message> @@ -2961,16 +3080,21 @@ You can also use online editors and converters instead.</source> </message> <message> <location filename="modinfo.cpp" line="105"/> + <source>INI files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.cpp" line="106"/> <source>invalid content type %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modinfo.cpp" line="128"/> + <location filename="modinfo.cpp" line="129"/> <source>invalid mod index %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modinfo.cpp" line="158"/> + <location filename="modinfo.cpp" line="159"/> <source>remove: invalid mod index %1</source> <translation type="unfinished"></translation> </message> @@ -3606,12 +3730,12 @@ p, li { white-space: pre-wrap; } <translation type="unfinished"></translation> </message> <message> - <location filename="modinforegular.cpp" line="516"/> + <location filename="modinforegular.cpp" line="520"/> <source>%1 contains no esp/esm/esl and no asset (textures, meshes, interface, ...) directory</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modinforegular.cpp" line="520"/> + <location filename="modinforegular.cpp" line="524"/> <source>Categories: <br></source> <translation type="unfinished"></translation> </message> @@ -3669,193 +3793,198 @@ p, li { white-space: pre-wrap; } <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="136"/> + <location filename="modlist.cpp" line="76"/> + <source>INI files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="137"/> <source>This entry contains files that have been created inside the virtual data tree (i.e. by the construction kit)</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="145"/> + <location filename="modlist.cpp" line="146"/> <source>Backup</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="146"/> + <location filename="modlist.cpp" line="147"/> <source>No valid game data</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="147"/> + <location filename="modlist.cpp" line="148"/> <source>Not endorsed yet</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="149"/> + <location filename="modlist.cpp" line="150"/> <source>Overwrites files</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="150"/> + <location filename="modlist.cpp" line="151"/> <source>Overwritten files</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="151"/> + <location filename="modlist.cpp" line="152"/> <source>Overwrites & Overwritten</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="152"/> + <location filename="modlist.cpp" line="153"/> <source>Redundant</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="153"/> + <location filename="modlist.cpp" line="154"/> <source>Alternate game source</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="239"/> + <location filename="modlist.cpp" line="240"/> <source>Non-MO</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="269"/> + <location filename="modlist.cpp" line="270"/> <source>invalid</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="398"/> + <location filename="modlist.cpp" line="399"/> <source>installed version: "%1", newest version: "%2"</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="400"/> + <location filename="modlist.cpp" line="401"/> <source>The newest version on Nexus seems to be older than the one you have installed. This could either mean the version you have has been withdrawn (i.e. due to a bug) or the author uses a non-standard versioning scheme and that newest version is actually newer. Either way you may want to "upgrade".</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="408"/> + <location filename="modlist.cpp" line="409"/> <source>Categories: <br></source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="437"/> + <location filename="modlist.cpp" line="438"/> <source>Invalid name</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="442"/> + <location filename="modlist.cpp" line="443"/> <source>Name is already in use by another mod</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="937"/> + <location filename="modlist.cpp" line="940"/> <source>drag&drop failed: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="1007"/> + <location filename="modlist.cpp" line="1019"/> <source>Confirm</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="1008"/> + <location filename="modlist.cpp" line="1020"/> <source>Are you sure you want to remove "%1"?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="1071"/> + <location filename="modlist.cpp" line="1083"/> <source>Flags</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="1072"/> + <location filename="modlist.cpp" line="1084"/> <source>Content</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="1073"/> + <location filename="modlist.cpp" line="1085"/> <source>Mod Name</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="1074"/> + <location filename="modlist.cpp" line="1086"/> <source>Version</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="1075"/> + <location filename="modlist.cpp" line="1087"/> <source>Priority</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="1076"/> + <location filename="modlist.cpp" line="1088"/> <source>Category</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="1077"/> + <location filename="modlist.cpp" line="1089"/> <source>Source Game</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="1078"/> + <location filename="modlist.cpp" line="1090"/> <source>Nexus ID</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="1079"/> + <location filename="modlist.cpp" line="1091"/> <source>Installation</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="1080"/> - <location filename="modlist.cpp" line="1112"/> + <location filename="modlist.cpp" line="1092"/> + <location filename="modlist.cpp" line="1125"/> <source>unknown</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="1088"/> + <location filename="modlist.cpp" line="1100"/> <source>Name of your mods</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="1089"/> + <location filename="modlist.cpp" line="1101"/> <source>Version of the mod (if available)</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="1090"/> + <location filename="modlist.cpp" line="1102"/> <source>Installation priority of your mod. The higher, the more "important" it is and thus overwrites files from mods with lower priority.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="1092"/> + <location filename="modlist.cpp" line="1104"/> <source>Category of the mod.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="1093"/> + <location filename="modlist.cpp" line="1105"/> <source>The source game which was the origin of this mod.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="1094"/> + <location filename="modlist.cpp" line="1106"/> <source>Id of the mod as used on Nexus.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="1095"/> + <location filename="modlist.cpp" line="1107"/> <source>Emblemes to highlight things that might require attention.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="1096"/> - <source>Depicts the content of the mod:<br><table cellspacing=7><tr><td><img src=":/MO/gui/content/plugin" width=32/></td><td>Game plugins (esp/esm/esl)</td></tr><tr><td><img src=":/MO/gui/content/interface" width=32/></td><td>Interface</td></tr><tr><td><img src=":/MO/gui/content/mesh" width=32/></td><td>Meshes</td></tr><tr><td><img src=":/MO/gui/content/bsa" width=32/></td><td>BSA</td></tr><tr><td><img src=":/MO/gui/content/texture" width=32/></td><td>Textures</td></tr><tr><td><img src=":/MO/gui/content/sound" width=32/></td><td>Sounds</td></tr><tr><td><img src=":/MO/gui/content/music" width=32/></td><td>Music</td></tr><tr><td><img src=":/MO/gui/content/string" width=32/></td><td>Strings</td></tr><tr><td><img src=":/MO/gui/content/script" width=32/></td><td>Scripts (Papyrus)</td></tr><tr><td><img src=":/MO/gui/content/skse" width=32/></td><td>Script Extender plugins</td></tr><tr><td><img src=":/MO/gui/content/skyproc" width=32/></td><td>SkyProc Patcher</td></tr><tr><td><img src=":/MO/gui/content/menu" width=32/></td><td>Mod Configuration Menu</td></tr></table></source> + <location filename="modlist.cpp" line="1108"/> + <source>Depicts the content of the mod:<br><table cellspacing=7><tr><td><img src=":/MO/gui/content/plugin" width=32/></td><td>Game plugins (esp/esm/esl)</td></tr><tr><td><img src=":/MO/gui/content/interface" width=32/></td><td>Interface</td></tr><tr><td><img src=":/MO/gui/content/mesh" width=32/></td><td>Meshes</td></tr><tr><td><img src=":/MO/gui/content/bsa" width=32/></td><td>BSA</td></tr><tr><td><img src=":/MO/gui/content/texture" width=32/></td><td>Textures</td></tr><tr><td><img src=":/MO/gui/content/sound" width=32/></td><td>Sounds</td></tr><tr><td><img src=":/MO/gui/content/music" width=32/></td><td>Music</td></tr><tr><td><img src=":/MO/gui/content/string" width=32/></td><td>Strings</td></tr><tr><td><img src=":/MO/gui/content/script" width=32/></td><td>Scripts (Papyrus)</td></tr><tr><td><img src=":/MO/gui/content/skse" width=32/></td><td>Script Extender plugins</td></tr><tr><td><img src=":/MO/gui/content/skyproc" width=32/></td><td>SkyProc Patcher</td></tr><tr><td><img src=":/MO/gui/content/menu" width=32/></td><td>Mod Configuration Menu</td></tr><tr><td><img src=":/MO/gui/content/inifile" width=32/></td><td>INI files</td></tr></table></source> <translation type="unfinished"></translation> </message> <message> - <location filename="modlist.cpp" line="1111"/> + <location filename="modlist.cpp" line="1124"/> <source>Time this mod was installed</source> <translation type="unfinished"></translation> </message> @@ -3863,7 +3992,7 @@ p, li { white-space: pre-wrap; } <context> <name>ModListSortProxy</name> <message> - <location filename="modlistsortproxy.cpp" line="383"/> + <location filename="modlistsortproxy.cpp" line="393"/> <source>Drag&Drop is only supported when sorting by priority</source> <translation type="unfinished"></translation> </message> @@ -3933,17 +4062,17 @@ p, li { white-space: pre-wrap; } <context> <name>NexusInterface</name> <message> - <location filename="nexusinterface.cpp" line="212"/> + <location filename="nexusinterface.cpp" line="209"/> <source>Failed to guess mod id for "%1", please pick the correct one</source> <translation type="unfinished"></translation> </message> <message> - <location filename="nexusinterface.cpp" line="546"/> + <location filename="nexusinterface.cpp" line="543"/> <source>empty response</source> <translation type="unfinished"></translation> </message> <message> - <location filename="nexusinterface.cpp" line="575"/> + <location filename="nexusinterface.cpp" line="572"/> <source>invalid response</source> <translation type="unfinished"></translation> </message> @@ -3951,189 +4080,201 @@ p, li { white-space: pre-wrap; } <context> <name>OrganizerCore</name> <message> - <location filename="organizercore.cpp" line="332"/> - <location filename="organizercore.cpp" line="359"/> + <location filename="organizercore.cpp" line="412"/> + <location filename="organizercore.cpp" line="439"/> <source>Failed to write settings</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="333"/> + <location filename="organizercore.cpp" line="413"/> <source>An error occured trying to update MO settings to %1: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="354"/> + <location filename="organizercore.cpp" line="434"/> <source>File is write protected</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="356"/> + <location filename="organizercore.cpp" line="436"/> <source>Invalid file format (probably a bug)</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="357"/> + <location filename="organizercore.cpp" line="437"/> <source>Unknown error %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="360"/> + <location filename="organizercore.cpp" line="440"/> <source>An error occured trying to write back MO settings to %1: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="613"/> - <location filename="organizercore.cpp" line="624"/> + <location filename="organizercore.cpp" line="695"/> + <location filename="organizercore.cpp" line="706"/> <source>Download started</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="627"/> + <location filename="organizercore.cpp" line="709"/> <source>Download failed</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="893"/> - <location filename="organizercore.cpp" line="951"/> + <location filename="organizercore.cpp" line="975"/> + <location filename="organizercore.cpp" line="1033"/> <source>Installation successful</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="901"/> - <location filename="organizercore.cpp" line="961"/> + <location filename="organizercore.cpp" line="983"/> + <location filename="organizercore.cpp" line="1043"/> <source>Configure Mod</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="902"/> - <location filename="organizercore.cpp" line="962"/> + <location filename="organizercore.cpp" line="984"/> + <location filename="organizercore.cpp" line="1044"/> <source>This mod contains ini tweaks. Do you want to configure them now?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="914"/> - <location filename="organizercore.cpp" line="972"/> + <location filename="organizercore.cpp" line="996"/> + <location filename="organizercore.cpp" line="1054"/> <source>mod "%1" not found</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="917"/> - <location filename="organizercore.cpp" line="979"/> + <location filename="organizercore.cpp" line="999"/> + <location filename="organizercore.cpp" line="1061"/> <source>Installation cancelled</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="918"/> - <location filename="organizercore.cpp" line="980"/> + <location filename="organizercore.cpp" line="1000"/> + <location filename="organizercore.cpp" line="1062"/> <source>The mod was not installed completely.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="1182"/> + <location filename="organizercore.cpp" line="1264"/> <source>Executable "%1" not found</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="1208"/> + <location filename="organizercore.cpp" line="1291"/> <source>Start Steam?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="1209"/> + <location filename="organizercore.cpp" line="1292"/> <source>Steam is required to be running already to correctly start the game. Should MO try to start steam now?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="1232"/> + <location filename="organizercore.cpp" line="1315"/> <source>Error</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="1315"/> + <location filename="organizercore.cpp" line="1323"/> + <source>Windows Event Log Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="organizercore.cpp" line="1324"/> + <source>The Windows Event Log service is disabled and/or not running. This prevents USVFS from running properly. Your mods may not be working in the executable that you are launching. Note that you may have to restart MO and/or your PC after the service is fixed. + +Continue launching %1?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="organizercore.cpp" line="1412"/> <source>No profile set</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="1601"/> + <location filename="organizercore.cpp" line="1698"/> <source>Failed to refresh list of esps: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="1685"/> + <location filename="organizercore.cpp" line="1782"/> <source>Multiple esps/esls activated, please check that they don't conflict.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="1760"/> + <location filename="organizercore.cpp" line="1857"/> <source>Download?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="1761"/> + <location filename="organizercore.cpp" line="1858"/> <source>A download has been started but no installed page plugin recognizes it. If you download anyway no information (i.e. version) will be associated with the download. Continue?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="1895"/> + <location filename="organizercore.cpp" line="1992"/> <source>failed to update mod list: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="1902"/> - <location filename="organizercore.cpp" line="1919"/> + <location filename="organizercore.cpp" line="1999"/> + <location filename="organizercore.cpp" line="2016"/> <source>login successful</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="1926"/> + <location filename="organizercore.cpp" line="2023"/> <source>Login failed</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="1927"/> + <location filename="organizercore.cpp" line="2024"/> <source>Login failed, try again?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="1936"/> + <location filename="organizercore.cpp" line="2033"/> <source>login failed: %1. Download will not be associated with an account</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="1944"/> + <location filename="organizercore.cpp" line="2041"/> <source>login failed: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="1954"/> + <location filename="organizercore.cpp" line="2051"/> <source>login failed: %1. You need to log-in with Nexus to update MO.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="2007"/> + <location filename="organizercore.cpp" line="2104"/> <source>MO1 "Script Extender" load mechanism has left hook.dll in your game folder</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="2010"/> - <location filename="organizercore.cpp" line="2026"/> + <location filename="organizercore.cpp" line="2107"/> + <location filename="organizercore.cpp" line="2123"/> <source>Description missing</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="2019"/> + <location filename="organizercore.cpp" line="2116"/> <source><a href="%1">hook.dll</a> has been found in your game folder (right click to copy the full path). This is most likely a leftover of setting the ModOrganizer 1 load mechanism to "Script Extender", in which case you must remove this file either by changing the load mechanism in ModOrganizer 1 or manually removing the file, otherwise the game is likely to crash and burn.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="2053"/> + <location filename="organizercore.cpp" line="2150"/> <source>failed to save load order: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="organizercore.cpp" line="2125"/> + <location filename="organizercore.cpp" line="2222"/> <source>The designated write target "%1" is not enabled.</source> <translation type="unfinished"></translation> </message> @@ -4146,7 +4287,12 @@ Continue?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="overwriteinfodialog.ui" line="42"/> + <location filename="overwriteinfodialog.ui" line="20"/> + <source>Open in Explorer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.ui" line="49"/> <source>You can use drag&drop to move files and directories to regular mods.</source> <translation type="unfinished"></translation> </message> @@ -4234,120 +4380,135 @@ Continue?</source> <context> <name>PluginList</name> <message> - <location filename="pluginlist.cpp" line="92"/> + <location filename="pluginlist.cpp" line="102"/> <source>Name</source> <translation type="unfinished"></translation> </message> <message> - <location filename="pluginlist.cpp" line="93"/> + <location filename="pluginlist.cpp" line="103"/> <source>Priority</source> <translation type="unfinished"></translation> </message> <message> - <location filename="pluginlist.cpp" line="94"/> + <location filename="pluginlist.cpp" line="104"/> <source>Mod Index</source> <translation type="unfinished"></translation> </message> <message> - <location filename="pluginlist.cpp" line="95"/> + <location filename="pluginlist.cpp" line="105"/> <source>Flags</source> <translation type="unfinished"></translation> </message> <message> - <location filename="pluginlist.cpp" line="96"/> - <location filename="pluginlist.cpp" line="108"/> + <location filename="pluginlist.cpp" line="106"/> + <location filename="pluginlist.cpp" line="118"/> <source>unknown</source> <translation type="unfinished"></translation> </message> <message> - <location filename="pluginlist.cpp" line="104"/> + <location filename="pluginlist.cpp" line="114"/> <source>Name of your mods</source> <translation type="unfinished"></translation> </message> <message> - <location filename="pluginlist.cpp" line="105"/> + <location filename="pluginlist.cpp" line="115"/> <source>Load priority of your mod. The higher, the more "important" it is and thus overwrites data from plugins with lower priority.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="pluginlist.cpp" line="107"/> + <location filename="pluginlist.cpp" line="117"/> <source>The modindex determines the formids of objects originating from this mods.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="pluginlist.cpp" line="197"/> + <location filename="pluginlist.cpp" line="215"/> <source>failed to update esp info for file %1 (source id: %2), error: %3</source> <translation type="unfinished"></translation> </message> <message> - <location filename="pluginlist.cpp" line="270"/> + <location filename="pluginlist.cpp" line="288"/> <source>esp not found: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="pluginlist.cpp" line="277"/> - <location filename="pluginlist.cpp" line="289"/> + <location filename="pluginlist.cpp" line="295"/> + <location filename="pluginlist.cpp" line="307"/> <source>Confirm</source> <translation type="unfinished"></translation> </message> <message> - <location filename="pluginlist.cpp" line="277"/> + <location filename="pluginlist.cpp" line="295"/> <source>Really enable all plugins?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="pluginlist.cpp" line="289"/> + <location filename="pluginlist.cpp" line="307"/> <source>Really disable all plugins?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="pluginlist.cpp" line="379"/> + <location filename="pluginlist.cpp" line="397"/> <source>The file containing locked plugin indices is broken</source> <translation type="unfinished"></translation> </message> <message> - <location filename="pluginlist.cpp" line="870"/> - <location filename="pluginlist.cpp" line="874"/> + <location filename="pluginlist.cpp" line="893"/> + <location filename="pluginlist.cpp" line="897"/> <source><b>Origin</b>: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="pluginlist.cpp" line="871"/> + <location filename="pluginlist.cpp" line="894"/> <source><br><b><i>This plugin can't be disabled (enforced by the game).</i></b></source> <translation type="unfinished"></translation> </message> <message> - <location filename="pluginlist.cpp" line="876"/> + <location filename="pluginlist.cpp" line="899"/> <source>Author</source> <translation type="unfinished"></translation> </message> <message> - <location filename="pluginlist.cpp" line="879"/> + <location filename="pluginlist.cpp" line="902"/> <source>Description</source> <translation type="unfinished"></translation> </message> <message> - <location filename="pluginlist.cpp" line="882"/> + <location filename="pluginlist.cpp" line="905"/> <source>Missing Masters</source> <translation type="unfinished"></translation> </message> <message> - <location filename="pluginlist.cpp" line="889"/> + <location filename="pluginlist.cpp" line="912"/> <source>Enabled Masters</source> <translation type="unfinished"></translation> </message> <message> - <location filename="pluginlist.cpp" line="892"/> - <source>There is an ini file connected to this esp. Its settings will be added to your game settings, overwriting in case of conflicts.</source> + <location filename="pluginlist.cpp" line="915"/> + <source>Loads Archives</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="916"/> + <source>There are Archives connected to this plugin. Their assets will be added to your game, overwriting in case of conflicts following the plugin order. Loose files will always overwrite assets from Archives. (This flag only checks for Archives from the same mod as the plugin)</source> <translation type="unfinished"></translation> </message> <message> - <location filename="pluginlist.cpp" line="896"/> + <location filename="pluginlist.cpp" line="921"/> + <source>Loads INI settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="922"/> + <source>There is an ini file connected to this plugin. Its settings will be added to your game settings, overwriting in case of conflicts.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="926"/> <source>This ESP is flagged as an ESL. It will adhere to the ESP load order but the records will be loaded in ESL space.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="pluginlist.cpp" line="1067"/> + <location filename="pluginlist.cpp" line="1101"/> <source>failed to restore load order for %1</source> <translation type="unfinished"></translation> </message> @@ -4703,7 +4864,7 @@ p, li { white-space: pre-wrap; } <location filename="../../uibase/src/report.cpp" line="34"/> <location filename="../../uibase/src/report.cpp" line="37"/> <location filename="main.cpp" line="98"/> - <location filename="organizercore.cpp" line="651"/> + <location filename="organizercore.cpp" line="733"/> <source>Error</source> <translation type="unfinished"></translation> </message> @@ -4865,84 +5026,94 @@ If the folder was still in use, restart MO and try again.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="instancemanager.cpp" line="137"/> + <location filename="instancemanager.cpp" line="138"/> <source>Enter a Name for the new Instance</source> <translation type="unfinished"></translation> </message> <message> - <location filename="instancemanager.cpp" line="138"/> - <source>Enter a new name or select one from the sugested list (only letters and numbers allowed):</source> + <location filename="instancemanager.cpp" line="139"/> + <source>Enter a new name or select one from the suggested list:</source> <translation type="unfinished"></translation> </message> <message> - <location filename="instancemanager.cpp" line="147"/> - <location filename="instancemanager.cpp" line="208"/> + <location filename="instancemanager.cpp" line="148"/> + <location filename="instancemanager.cpp" line="219"/> <source>Canceled</source> <translation type="unfinished"></translation> </message> <message> - <location filename="instancemanager.cpp" line="159"/> + <location filename="instancemanager.cpp" line="154"/> + <source>Invalid instance name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="instancemanager.cpp" line="155"/> + <source>The instance name "%1" is invalid. Use the name "%2" instead?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="instancemanager.cpp" line="170"/> <source>The instance "%1" already exists.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="instancemanager.cpp" line="160"/> + <location filename="instancemanager.cpp" line="171"/> <source>Please choose a different instance name, like: "%1 1" .</source> <translation type="unfinished"></translation> </message> <message> - <location filename="instancemanager.cpp" line="179"/> + <location filename="instancemanager.cpp" line="190"/> <source>Choose Instance</source> <translation type="unfinished"></translation> </message> <message> - <location filename="instancemanager.cpp" line="180"/> + <location filename="instancemanager.cpp" line="191"/> <source>Each Instance is a full set of MO data files (mods, downloads, profiles, configuration, ...). You can use multiple instances for different games. Instances are stored in Appdata and can be accessed by all MO installations. If your MO folder is writable, you can also store a single instance locally (called a Portable install, and all the MO data files will be inside the installation folder).</source> <translation type="unfinished"></translation> </message> <message> - <location filename="instancemanager.cpp" line="192"/> + <location filename="instancemanager.cpp" line="203"/> <source>New</source> <translation type="unfinished"></translation> </message> <message> - <location filename="instancemanager.cpp" line="193"/> + <location filename="instancemanager.cpp" line="204"/> <source>Create a new instance.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="instancemanager.cpp" line="197"/> + <location filename="instancemanager.cpp" line="208"/> <source>Portable</source> <translation type="unfinished"></translation> </message> <message> - <location filename="instancemanager.cpp" line="198"/> + <location filename="instancemanager.cpp" line="209"/> <source>Use MO folder for data.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="instancemanager.cpp" line="202"/> + <location filename="instancemanager.cpp" line="213"/> <source>Manage Instances</source> <translation type="unfinished"></translation> </message> <message> - <location filename="instancemanager.cpp" line="203"/> + <location filename="instancemanager.cpp" line="214"/> <source>Delete an Instance.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="instancemanager.cpp" line="254"/> + <location filename="instancemanager.cpp" line="265"/> <location filename="profile.cpp" line="66"/> <source>failed to create %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="instancemanager.cpp" line="257"/> + <location filename="instancemanager.cpp" line="268"/> <source>Data directory created</source> <translation type="unfinished"></translation> </message> <message> - <location filename="instancemanager.cpp" line="258"/> + <location filename="instancemanager.cpp" line="269"/> <source>New data directory created at %1. If you don't want to store a lot of data there, reconfigure the storage directories via settings.</source> <translation type="unfinished"></translation> </message> @@ -5012,7 +5183,7 @@ If the folder was still in use, restart MO and try again.</source> </message> <message> <location filename="main.cpp" line="99"/> - <location filename="organizercore.cpp" line="652"/> + <location filename="organizercore.cpp" line="734"/> <source>Failed to create "%1". Your user account probably lacks permission.</source> <translation type="unfinished"></translation> </message> @@ -5038,49 +5209,49 @@ If the folder was still in use, restart MO and try again.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="main.cpp" line="541"/> + <location filename="main.cpp" line="537"/> <source>Please select the game edition you have (MO can't start the game correctly if this is set incorrectly!)</source> <translation type="unfinished"></translation> </message> <message> - <location filename="main.cpp" line="578"/> + <location filename="main.cpp" line="574"/> <source>failed to start shortcut: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="main.cpp" line="600"/> + <location filename="main.cpp" line="596"/> <source>failed to start application: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="main.cpp" line="686"/> - <location filename="settings.cpp" line="967"/> + <location filename="main.cpp" line="682"/> + <location filename="settings.cpp" line="968"/> <source>Mod Organizer</source> <translation type="unfinished"></translation> </message> <message> - <location filename="main.cpp" line="687"/> + <location filename="main.cpp" line="683"/> <source>An instance of Mod Organizer is already running</source> <translation type="unfinished"></translation> </message> <message> - <location filename="main.cpp" line="702"/> + <location filename="main.cpp" line="698"/> <source>Failed to set up instance</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="861"/> + <location filename="mainwindow.cpp" line="863"/> <source>Please use "Help" from the toolbar to get usage instructions to all elements</source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="1263"/> - <location filename="mainwindow.cpp" line="3837"/> + <location filename="mainwindow.cpp" line="1265"/> + <location filename="mainwindow.cpp" line="3947"/> <source><Manage...></source> <translation type="unfinished"></translation> </message> <message> - <location filename="mainwindow.cpp" line="1275"/> + <location filename="mainwindow.cpp" line="1277"/> <source>failed to parse profile %1: %2</source> <translation type="unfinished"></translation> </message> @@ -5116,12 +5287,12 @@ If the folder was still in use, restart MO and try again.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="pluginlist.cpp" line="455"/> + <location filename="pluginlist.cpp" line="473"/> <source>failed to access %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="pluginlist.cpp" line="469"/> + <location filename="pluginlist.cpp" line="487"/> <source>failed to set file time %1</source> <translation type="unfinished"></translation> </message> @@ -5131,12 +5302,12 @@ If the folder was still in use, restart MO and try again.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settings.cpp" line="974"/> + <location filename="settings.cpp" line="975"/> <source>Script Extender</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settings.cpp" line="981"/> + <location filename="settings.cpp" line="982"/> <source>Proxy DLL</source> <translation type="unfinished"></translation> </message> @@ -5281,58 +5452,58 @@ Start elevated anyway? (you will be asked if you want to allow ModOrganizer.exe <translation type="unfinished"></translation> </message> <message> - <location filename="selfupdater.cpp" line="178"/> + <location filename="selfupdater.cpp" line="173"/> <source>New update available (%1)</source> <translation type="unfinished"></translation> </message> <message> - <location filename="selfupdater.cpp" line="179"/> + <location filename="selfupdater.cpp" line="174"/> <source>Do you want to install update? All your mods and setup will be left untouched. Select Show Details option to see the full change-log.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="selfupdater.cpp" line="183"/> + <location filename="selfupdater.cpp" line="178"/> <source>Install</source> <translation type="unfinished"></translation> </message> <message> - <location filename="selfupdater.cpp" line="200"/> + <location filename="selfupdater.cpp" line="195"/> <source>Download failed</source> <translation type="unfinished"></translation> </message> <message> - <location filename="selfupdater.cpp" line="201"/> + <location filename="selfupdater.cpp" line="196"/> <source>Failed to find correct download, please try again later.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="selfupdater.cpp" line="216"/> + <location filename="selfupdater.cpp" line="211"/> <source>Update</source> <translation type="unfinished"></translation> </message> <message> - <location filename="selfupdater.cpp" line="217"/> + <location filename="selfupdater.cpp" line="212"/> <source>Download in progress</source> <translation type="unfinished"></translation> </message> <message> - <location filename="selfupdater.cpp" line="308"/> + <location filename="selfupdater.cpp" line="303"/> <source>Download failed: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="selfupdater.cpp" line="319"/> + <location filename="selfupdater.cpp" line="314"/> <source>Failed to install update: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="selfupdater.cpp" line="342"/> + <location filename="selfupdater.cpp" line="337"/> <source>Failed to start %1: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="selfupdater.cpp" line="352"/> + <location filename="selfupdater.cpp" line="347"/> <source>Error</source> <translation type="unfinished"></translation> </message> @@ -5356,12 +5527,12 @@ Select Show Details option to see the full change-log.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settings.cpp" line="757"/> + <location filename="settings.cpp" line="758"/> <source>Error</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settings.cpp" line="758"/> + <location filename="settings.cpp" line="759"/> <source>Failed to create "%1", you may not have the necessary permission. path remains unchanged.</source> <translation type="unfinished"></translation> </message> @@ -5488,81 +5659,86 @@ If you use pre-releases, never contact me directly by e-mail or via private mess <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="176"/> + <location filename="settingsdialog.ui" line="334"/> <source>Base Directory</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="183"/> - <location filename="settingsdialog.ui" line="196"/> - <location filename="settingsdialog.ui" line="281"/> + <location filename="settingsdialog.ui" line="176"/> + <location filename="settingsdialog.ui" line="193"/> + <location filename="settingsdialog.ui" line="290"/> <source>...</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="203"/> + <location filename="settingsdialog.ui" line="210"/> <source>Overwrite</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="210"/> + <location filename="settingsdialog.ui" line="203"/> <source>Caches</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="227"/> + <location filename="settingsdialog.ui" line="237"/> <source>Downloads</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="241"/> + <location filename="settingsdialog.ui" line="280"/> <source>Directory where mods are stored.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="244"/> + <location filename="settingsdialog.ui" line="283"/> <source>Directory where mods are stored. Please note that changing this will break all associations of profiles with mods that don't exist in the new location (with the same name).</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="264"/> - <location filename="settingsdialog.ui" line="267"/> + <location filename="settingsdialog.ui" line="217"/> + <location filename="settingsdialog.ui" line="220"/> <source>Directory where downloads are stored.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="274"/> + <location filename="settingsdialog.ui" line="307"/> <source>Mods</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="291"/> + <location filename="settingsdialog.ui" line="257"/> <source>Profiles</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="313"/> + <location filename="settingsdialog.ui" line="327"/> + <source>Managed Game</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="341"/> <source>Use %BASE_DIR% to refer to the Base Directory.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="333"/> + <location filename="settingsdialog.ui" line="363"/> <source>Important: All directories have to be writeable!</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="341"/> - <location filename="settingsdialog.ui" line="357"/> + <location filename="settingsdialog.ui" line="371"/> + <location filename="settingsdialog.ui" line="387"/> <source>Nexus</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="347"/> + <location filename="settingsdialog.ui" line="377"/> <source>Allows automatic log-in when the Nexus-Page for the game is clicked.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="350"/> + <location filename="settingsdialog.ui" line="380"/> <source><!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; } @@ -5571,144 +5747,144 @@ p, li { white-space: pre-wrap; } <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="366"/> + <location filename="settingsdialog.ui" line="396"/> <source>If checked and if correct credentials are entered below, log-in to Nexus (for browsing and downloading) is automatic.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="369"/> + <location filename="settingsdialog.ui" line="399"/> <source>Automatically Log-In to Nexus</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="378"/> - <location filename="settingsdialog.ui" line="564"/> + <location filename="settingsdialog.ui" line="408"/> + <location filename="settingsdialog.ui" line="594"/> <source>Username</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="392"/> - <location filename="settingsdialog.ui" line="574"/> + <location filename="settingsdialog.ui" line="422"/> + <location filename="settingsdialog.ui" line="604"/> <source>Password</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="413"/> + <location filename="settingsdialog.ui" line="443"/> <source>Remove cache and cookies. Forces a new login.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="416"/> + <location filename="settingsdialog.ui" line="446"/> <source>Clear Cache</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="445"/> + <location filename="settingsdialog.ui" line="475"/> <source>Disable automatic internet features</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="448"/> + <location filename="settingsdialog.ui" line="478"/> <source>Disable automatic internet features. This does not affect features that are explicitly invoked by the user (like checking mods for updates, endorsing, opening the web browser)</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="451"/> + <location filename="settingsdialog.ui" line="481"/> <source>Offline Mode</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="458"/> + <location filename="settingsdialog.ui" line="488"/> <source>Use a proxy for network connections.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="461"/> + <location filename="settingsdialog.ui" line="491"/> <source>Use a proxy for network connections. This uses the system-wide settings which can be configured in Internet Explorer. Please note that MO will start up a few seconds slower on some systems when using a proxy.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="464"/> + <location filename="settingsdialog.ui" line="494"/> <source>Use HTTP Proxy (Uses System Settings)</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="473"/> + <location filename="settingsdialog.ui" line="503"/> <source>Associate with "Download with manager" links</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="502"/> + <location filename="settingsdialog.ui" line="532"/> <source>Known Servers (updated on download)</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="523"/> + <location filename="settingsdialog.ui" line="553"/> <source>Preferred Servers (Drag & Drop)</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="558"/> + <location filename="settingsdialog.ui" line="588"/> <source>Steam</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="604"/> + <location filename="settingsdialog.ui" line="634"/> <source>If you save your steam user ID and password here, they will be used when logging into steam. Note, however, your password will be stored unencrypted, so make sure your computer is secure.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="631"/> + <location filename="settingsdialog.ui" line="661"/> <source>Plugins</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="653"/> + <location filename="settingsdialog.ui" line="683"/> <source>Author:</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="667"/> + <location filename="settingsdialog.ui" line="697"/> <source>Version:</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="681"/> + <location filename="settingsdialog.ui" line="711"/> <source>Description:</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="719"/> + <location filename="settingsdialog.ui" line="749"/> <source>Key</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="724"/> + <location filename="settingsdialog.ui" line="754"/> <source>Value</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="736"/> + <location filename="settingsdialog.ui" line="766"/> <source>Blacklisted Plugins (use <del> to remove):</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="747"/> + <location filename="settingsdialog.ui" line="777"/> <source>Workarounds</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="755"/> + <location filename="settingsdialog.ui" line="785"/> <source>Steam App ID</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="775"/> + <location filename="settingsdialog.ui" line="805"/> <source>The Steam AppID for your game</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="778"/> + <location filename="settingsdialog.ui" line="808"/> <source><!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; } @@ -5724,17 +5900,17 @@ p, li { white-space: pre-wrap; } <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="809"/> + <location filename="settingsdialog.ui" line="839"/> <source>Load Mechanism</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="829"/> + <location filename="settingsdialog.ui" line="859"/> <source>Select loading mechanism. See help for details.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="832"/> + <location filename="settingsdialog.ui" line="862"/> <source>Mod Organizer needs a dll to be injected into the game so all mods are visible to it. There are several means to do this: *Mod Organizer* (default) In this mode the Mod Organizer itself injects the dll. The disadvantage is that you always have to start the game through MO or a link created by it. @@ -5745,17 +5921,17 @@ If you use the Steam version of Oblivion the default will NOT work. In this case <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="849"/> + <location filename="settingsdialog.ui" line="879"/> <source>NMM Version</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="869"/> + <location filename="settingsdialog.ui" line="899"/> <source>The Version of Nexus Mod Manager to impersonate.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="872"/> + <location filename="settingsdialog.ui" line="902"/> <source>Mod Organizer uses an API provided by the Nexus to provide features like checking for updates and downloading files. Unfortunately this API has not been made available officially to third party tools like MO so we have to impersonate the Nexus Mod Manager to be allowed in. On top of this Nexus has used the client identification to lock out outdated versions of NMM to force users to update. This means that MO also needs to impersonate the new version of NMM even if MO doesn't need an update. Therefore you can configure the version to identify as here. Please note that MO does identify itself as MO to the webserver, it's not lying about what it is. It is merely adding a "compatible" NMM version to the user agent. @@ -5764,44 +5940,44 @@ tl;dr-version: If Nexus-features don't work, insert the current version num <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="897"/> + <location filename="settingsdialog.ui" line="927"/> <source>Enforces that inactive ESPs and ESMs are never loaded.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="900"/> + <location filename="settingsdialog.ui" line="930"/> <source>It seems that the Games occasionally load ESP or ESM files even if they haven't been activated as plugins. I don't yet know what the circumstances are, but user reports imply it is in some cases unwanted. If this is checked, ESPs and ESMs not checked in the List are invisible to the game and can not be loaded.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="904"/> + <location filename="settingsdialog.ui" line="934"/> <source>Hide inactive ESPs/ESMs</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="911"/> + <location filename="settingsdialog.ui" line="941"/> <source>If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on)</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="914"/> + <location filename="settingsdialog.ui" line="944"/> <source>If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on) Uncheck this if you want to use Mod Organizer with total conversions (like Nehrim) but be aware that the game will crash if required files are not enabled.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="918"/> + <location filename="settingsdialog.ui" line="948"/> <source>Force-enable game files</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="928"/> + <location filename="settingsdialog.ui" line="958"/> <source>Disable this to no longer display mods installed outside MO in the mod list (left pane). Assets from those mods will then be treated as having lowest mod priority together with the original game content.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="931"/> + <location filename="settingsdialog.ui" line="961"/> <source>By default Mod Organizer will display esp+bsa bundles installed with foreign tools as mods (left pane). This allows you to control their priority in relation to other mods. This is particularly useful if you also use Steam Workshop to install mods. However, if you installed loose file mods outside MO which conflict with BSAs also installed outside MO those conflicts can't be resolved correctly. @@ -5809,44 +5985,44 @@ If you disable this feature, MO will only display official DLCs this way. Please <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="937"/> + <location filename="settingsdialog.ui" line="967"/> <source>Display mods installed outside MO</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="947"/> - <location filename="settingsdialog.ui" line="951"/> + <location filename="settingsdialog.ui" line="977"/> + <location filename="settingsdialog.ui" line="981"/> <source>For Skyrim, this can be used instead of Archive Invalidation. It should make AI redundant for all Profiles. For the other games this is not a sufficient replacement for AI!</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="955"/> + <location filename="settingsdialog.ui" line="985"/> <source>Back-date BSAs</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="979"/> + <location filename="settingsdialog.ui" line="1009"/> <source>These are workarounds for problems with Mod Organizer. Please make sure you read the help text before changing anything here.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="990"/> + <location filename="settingsdialog.ui" line="1020"/> <source>Diagnostics</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="998"/> + <location filename="settingsdialog.ui" line="1028"/> <source>Log Level</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="1005"/> + <location filename="settingsdialog.ui" line="1035"/> <source>Decides the amount of data printed to "ModOrganizer.log"</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="1008"/> + <location filename="settingsdialog.ui" line="1038"/> <source> Decides the amount of data printed to "ModOrganizer.log". "Debug" produces very useful information for finding problems. There is usually no noteworthy performance impact but the file may become rather large. If this is a problem you may prefer the "Info" level for regluar use. On the "Error" level the log file usually remains empty. @@ -5854,37 +6030,37 @@ For the other games this is not a sufficient replacement for AI!</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="1015"/> + <location filename="settingsdialog.ui" line="1045"/> <source>Debug</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="1020"/> + <location filename="settingsdialog.ui" line="1050"/> <source>Info (recommended)</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="1025"/> + <location filename="settingsdialog.ui" line="1055"/> <source>Warning</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="1030"/> + <location filename="settingsdialog.ui" line="1060"/> <source>Error</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="1055"/> + <location filename="settingsdialog.ui" line="1085"/> <source>Crash Dumps</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="1062"/> + <location filename="settingsdialog.ui" line="1092"/> <source>Decides which type of crash dumps are collected when injected processes crash.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="1065"/> + <location filename="settingsdialog.ui" line="1095"/> <source> Decides which type of crash dumps are collected when injected processes crash. "None" Disables the generation of crash dumps by MO. @@ -5895,37 +6071,37 @@ For the other games this is not a sufficient replacement for AI!</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="1075"/> + <location filename="settingsdialog.ui" line="1105"/> <source>None</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="1080"/> + <location filename="settingsdialog.ui" line="1110"/> <source>Mini (recommended)</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="1085"/> + <location filename="settingsdialog.ui" line="1115"/> <source>Data</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="1090"/> + <location filename="settingsdialog.ui" line="1120"/> <source>Full</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="1102"/> + <location filename="settingsdialog.ui" line="1132"/> <source>Max Dumps To Keep</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="1122"/> + <location filename="settingsdialog.ui" line="1152"/> <source>Maximum number of crash dumps to keep on disk. Use 0 for unlimited.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="1125"/> + <location filename="settingsdialog.ui" line="1155"/> <source> Maximum number of crash dumps to keep on disk. Use 0 for unlimited. Set "Crash Dumps" above to None to disable crash dump collection. @@ -5933,7 +6109,7 @@ For the other games this is not a sufficient replacement for AI!</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="1137"/> + <location filename="settingsdialog.ui" line="1170"/> <source> Logs and crash dumps are stored under your current instance in the <a href="LOGS_FULL_PATH">LOGS_DIR</a> and <a href="DUMPS_FULL_PATH">DUMPS_DIR</a> folders. @@ -5943,7 +6119,7 @@ For the other games this is not a sufficient replacement for AI!</source> <translation type="unfinished"></translation> </message> <message> - <location filename="settingsdialog.ui" line="1148"/> + <location filename="settingsdialog.ui" line="1167"/> <source>Hint: right click link and copy link location</source> <translation type="unfinished"></translation> </message> diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 35486f98..74ec752e 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -186,6 +186,86 @@ QStringList toStringList(InputIterator current, InputIterator end) return result;
}
+bool checkService()
+{
+ SC_HANDLE serviceManagerHandle = NULL;
+ SC_HANDLE serviceHandle = NULL;
+ LPSERVICE_STATUS_PROCESS serviceStatus = NULL;
+ LPQUERY_SERVICE_CONFIG serviceConfig = NULL;
+ bool serviceRunning = true;
+
+ DWORD bytesNeeded;
+
+ try {
+ serviceManagerHandle = OpenSCManager(NULL, NULL, SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
+ if (!serviceManagerHandle) {
+ qWarning("failed to open service manager (query status) (error %d)", GetLastError());
+ throw 1;
+ }
+
+ serviceHandle = OpenService(serviceManagerHandle, L"EventLog", SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
+ if (!serviceHandle) {
+ qWarning("failed to open EventLog service (query status) (error %d)", GetLastError());
+ throw 2;
+ }
+
+ if (QueryServiceConfig(serviceHandle, NULL, 0, &bytesNeeded)
+ || (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
+ qWarning("failed to get size of service config (error %d)", GetLastError());
+ throw 3;
+ }
+
+ DWORD serviceConfigSize = bytesNeeded;
+ serviceConfig = (LPQUERY_SERVICE_CONFIG)LocalAlloc(LMEM_FIXED, serviceConfigSize);
+ if (!QueryServiceConfig(serviceHandle, serviceConfig, serviceConfigSize, &bytesNeeded)) {
+ qWarning("failed to query service config (error %d)", GetLastError());
+ throw 4;
+ }
+
+ if (serviceConfig->dwStartType == SERVICE_DISABLED) {
+ qCritical("Windows Event Log service is disabled!");
+ serviceRunning = false;
+ }
+
+ if (QueryServiceStatusEx(serviceHandle, SC_STATUS_PROCESS_INFO, NULL, 0, &bytesNeeded)
+ || (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
+ qWarning("failed to get size of service status (error %d)", GetLastError());
+ throw 5;
+ }
+
+ DWORD serviceStatusSize = bytesNeeded;
+ serviceStatus = (LPSERVICE_STATUS_PROCESS)LocalAlloc(LMEM_FIXED, serviceStatusSize);
+ if (!QueryServiceStatusEx(serviceHandle, SC_STATUS_PROCESS_INFO, (LPBYTE)serviceStatus, serviceStatusSize, &bytesNeeded)) {
+ qWarning("failed to query service status (error %d)", GetLastError());
+ throw 6;
+ }
+
+ if (serviceStatus->dwCurrentState != SERVICE_RUNNING) {
+ qCritical("Windows Event Log service is not running");
+ serviceRunning = false;
+ }
+ }
+ catch (int e) {
+ UNUSED_VAR(e);
+ serviceRunning = false;
+ }
+
+ if (serviceStatus) {
+ LocalFree(serviceStatus);
+ }
+ if (serviceConfig) {
+ LocalFree(serviceConfig);
+ }
+ if (serviceHandle) {
+ CloseServiceHandle(serviceHandle);
+ }
+ if (serviceManagerHandle) {
+ CloseServiceHandle(serviceManagerHandle);
+ }
+
+ return serviceRunning;
+}
+
OrganizerCore::OrganizerCore(const QSettings &initSettings)
: m_UserInterface(nullptr)
, m_PluginContainer(nullptr)
@@ -472,6 +552,8 @@ void OrganizerCore::setUserInterface(IUserInterface *userInterface, SLOT(modRemoved(QString)));
connect(&m_ModList, SIGNAL(removeSelectedMods()), widget,
SLOT(removeMod_clicked()));
+ connect(&m_ModList, SIGNAL(clearOverwrite()), widget,
+ SLOT(clearOverwrite()));
connect(&m_ModList, SIGNAL(requestColumnSelect(QPoint)), widget,
SLOT(displayColumnSelection(QPoint)));
connect(&m_ModList, SIGNAL(fileMoved(QString, QString, QString)), widget,
@@ -1190,6 +1272,11 @@ HANDLE OrganizerCore::spawnBinaryProcess(const QFileInfo &binary, ToWString(m_Settings.getSteamAppID()).c_str());
}
+ QWidget *window = qApp->activeWindow();
+ if ((window != nullptr) && (!window->isVisible())) {
+ window = nullptr;
+ }
+
// This could possibly be extracted somewhere else but it's probably for when
// we have more than one provider of game registration.
if ((QFileInfo(
@@ -1200,16 +1287,12 @@ HANDLE OrganizerCore::spawnBinaryProcess(const QFileInfo &binary, .exists())
&& (m_Settings.getLoadMechanism() == LoadMechanism::LOAD_MODORGANIZER)) {
if (!testForSteam()) {
- QWidget *window = qApp->activeWindow();
- if ((window != nullptr) && (!window->isVisible())) {
- window = nullptr;
- }
if (QuestionBoxMemory::query(window, "steamQuery", binary.fileName(),
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) {
- startSteam(qApp->activeWindow());
+ startSteam(window);
}
}
}
@@ -1229,10 +1312,24 @@ HANDLE OrganizerCore::spawnBinaryProcess(const QFileInfo &binary, try {
m_USVFS.updateMapping(fileMapping(profileName, customOverwrite));
} catch (const std::exception &e) {
- QMessageBox::warning(qApp->activeWindow(), tr("Error"), e.what());
+ QMessageBox::warning(window, tr("Error"), e.what());
return INVALID_HANDLE_VALUE;
}
+ // Check if the Windows Event Logging service is running. For some reason, this seems to be
+ // critical to the successful running of usvfs.
+ if (!checkService()) {
+ if (QuestionBoxMemory::query(window, QString("eventLogService"), binary.fileName(),
+ tr("Windows Event Log Error"),
+ tr("The Windows Event Log service is disabled and/or not running. This prevents"
+ " USVFS from running properly. Your mods may not be working in the executable"
+ " that you are launching. Note that you may have to restart MO and/or your PC"
+ " after the service is fixed.\n\nContinue launching %1?").arg(binary.fileName()),
+ QDialogButtonBox::Yes | QDialogButtonBox::No) == QDialogButtonBox::No) {
+ return INVALID_HANDLE_VALUE;
+ }
+ }
+
QString modsPath = settings().getModDirectory();
// Check if this a request with either an executable or a working directory under our mods folder
@@ -2204,4 +2301,4 @@ std::vector<Mapping> OrganizerCore::fileMapping( result.insert(result.end(), subRes.begin(), subRes.end());
}
return result;
-}
+}
\ No newline at end of file diff --git a/src/overwriteinfodialog.cpp b/src/overwriteinfodialog.cpp index 3bb67354..1fe3f645 100644 --- a/src/overwriteinfodialog.cpp +++ b/src/overwriteinfodialog.cpp @@ -261,6 +261,10 @@ void OverwriteInfoDialog::createDirectoryTriggered() ui->filesView->edit(newIndex);
}
+void OverwriteInfoDialog::on_explorerButton_clicked()
+{
+ ::ShellExecuteW(nullptr, L"explore", ToWString(m_ModInfo->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+}
void OverwriteInfoDialog::on_filesView_customContextMenuRequested(const QPoint &pos)
{
diff --git a/src/overwriteinfodialog.h b/src/overwriteinfodialog.h index 7d44c9e8..4b731736 100644 --- a/src/overwriteinfodialog.h +++ b/src/overwriteinfodialog.h @@ -56,6 +56,7 @@ private slots: void openTriggered();
void createDirectoryTriggered();
+ void on_explorerButton_clicked();
void on_filesView_customContextMenuRequested(const QPoint &pos);
private:
diff --git a/src/overwriteinfodialog.ui b/src/overwriteinfodialog.ui index 5e5986ca..8a09ce59 100644 --- a/src/overwriteinfodialog.ui +++ b/src/overwriteinfodialog.ui @@ -14,6 +14,13 @@ <string>Overwrite</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
+ <item alignment="Qt::AlignLeft">
+ <widget class="QPushButton" name="explorerButton">
+ <property name="text">
+ <string>Open in Explorer</string>
+ </property>
+ </widget>
+ </item>
<item>
<widget class="QTreeView" name="filesView">
<property name="contextMenuPolicy">
diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index a6ae8fa7..323cd98f 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -72,11 +72,21 @@ static bool ByDate(const PluginList::ESPInfo& LHS, const PluginList::ESPInfo& RH return QFileInfo(LHS.m_FullPath).lastModified() < QFileInfo(RHS.m_FullPath).lastModified();
}
+static QString TruncateString(const QString& text) {
+ QString new_text = text;
+ if (new_text.length() > 1024) {
+ new_text.truncate(1024);
+ new_text += "...";
+ }
+ return new_text;
+}
+
PluginList::PluginList(QObject *parent)
: QAbstractItemModel(parent)
, m_FontMetrics(QFont())
{
connect(this, SIGNAL(writePluginsList()), this, SLOT(generatePluginIndexes()));
+ m_LastCheck.start();
}
PluginList::~PluginList()
@@ -181,9 +191,17 @@ void PluginList::refresh(const QString &profileName try {
FilesOrigin &origin = baseDirectory.getOriginByID(current->getOrigin(archive));
+
QString iniPath = QFileInfo(filename).baseName() + ".ini";
bool hasIni = baseDirectory.findFile(ToWString(iniPath)).get() != nullptr;
+ std::set<QString> loadedArchives;
+ QString originPath = QString::fromWCharArray(origin.getPath().c_str());
+ QDir dir(QDir::toNativeSeparators(originPath));
+ for (QString filename : dir.entryList(QStringList() << QFileInfo(filename).baseName() + "*.bsa" << QFileInfo(filename).baseName() + "*.ba2")) {
+ loadedArchives.insert(filename);
+ }
+
QString originName = ToQString(origin.getName());
unsigned int modIndex = ModInfo::getIndex(originName);
if (modIndex != UINT_MAX) {
@@ -191,7 +209,7 @@ void PluginList::refresh(const QString &profileName originName = modInfo->name();
}
- m_ESPs.push_back(ESPInfo(filename, forceEnabled, originName, ToQString(current->getFullPath()), hasIni));
+ m_ESPs.push_back(ESPInfo(filename, forceEnabled, originName, ToQString(current->getFullPath()), hasIni, loadedArchives));
m_ESPs.rbegin()->m_Priority = -1;
} catch (const std::exception &e) {
reportError(tr("failed to update esp info for file %1 (source id: %2), error: %3").arg(filename).arg(current->getOrigin(archive)).arg(e.what()));
@@ -575,6 +593,11 @@ void PluginList::disconnectSlots() { m_PluginStateChanged.disconnect_all_slots();
}
+int PluginList::timeElapsedSinceLastChecked() const
+{
+ return m_LastCheck.elapsed();
+}
+
QStringList PluginList::pluginNames() const
{
QStringList result;
@@ -838,7 +861,7 @@ QVariant PluginList::data(const QModelIndex &modelIndex, int role) const } else if (role == Qt::BackgroundRole
|| (role == ViewMarkingScrollBar::DEFAULT_ROLE)) {
if (m_ESPs[index].m_ModSelected) {
- return QColor(0, 0, 255, 32);
+ return QColor(0, 0, 255, 64);
} else {
return QVariant();
}
@@ -873,23 +896,30 @@ QVariant PluginList::data(const QModelIndex &modelIndex, int role) const } else {
QString text = tr("<b>Origin</b>: %1").arg(m_ESPs[index].m_OriginName);
if (m_ESPs[index].m_Author.size() > 0) {
- text += "<br><b>" + tr("Author") + "</b>: " + m_ESPs[index].m_Author;
+ text += "<br><b>" + tr("Author") + "</b>: " + TruncateString(m_ESPs[index].m_Author);
}
if (m_ESPs[index].m_Description.size() > 0) {
- text += "<br><b>" + tr("Description") + "</b>: " + m_ESPs[index].m_Description;
+ text += "<br><b>" + tr("Description") + "</b>: " + TruncateString(m_ESPs[index].m_Description);
}
if (m_ESPs[index].m_MasterUnset.size() > 0) {
- text += "<br><b>" + tr("Missing Masters") + "</b>: <b>" + SetJoin(m_ESPs[index].m_MasterUnset, ", ") + "</b>";
+ text += "<br><b>" + tr("Missing Masters") + "</b>: <b>" + TruncateString(SetJoin(m_ESPs[index].m_MasterUnset, ", ")) + "</b>";
}
std::set<QString> enabledMasters;
std::set_difference(m_ESPs[index].m_Masters.begin(), m_ESPs[index].m_Masters.end(),
m_ESPs[index].m_MasterUnset.begin(), m_ESPs[index].m_MasterUnset.end(),
std::inserter(enabledMasters, enabledMasters.end()));
if (!enabledMasters.empty()) {
- text += "<br><b>" + tr("Enabled Masters") + "</b>: " + SetJoin(enabledMasters, ", ");
+ text += "<br><b>" + tr("Enabled Masters") + "</b>: " + TruncateString(SetJoin(enabledMasters, ", "));
+ }
+ if (!m_ESPs[index].m_Archives.empty()) {
+ text += "<br><b>" + tr("Loads Archives") + "</b>: " + TruncateString(SetJoin(m_ESPs[index].m_Archives, ", "));
+ text += "<br>" + tr("There are Archives connected to this plugin. "
+ "Their assets will be added to your game, overwriting in case of conflicts following the plugin order. "
+ "Loose files will always overwrite assets from Archives. (This flag only checks for Archives from the same mod as the plugin)");
}
if (m_ESPs[index].m_HasIni) {
- text += "<br>" + tr("There is an ini file connected to this esp. "
+ text += "<br><b>" + tr("Loads INI settings") + "</b>: ";
+ text += "<br>" + tr("There is an ini file connected to this plugin. "
"Its settings will be added to your game settings, overwriting in case of conflicts.");
}
if (m_ESPs[index].m_IsLightFlagged && !m_ESPs[index].m_IsLight) {
@@ -917,6 +947,9 @@ QVariant PluginList::data(const QModelIndex &modelIndex, int role) const if (m_ESPs[index].m_HasIni) {
result.append(":/MO/gui/attachment");
}
+ if (!m_ESPs[index].m_Archives.empty()) {
+ result.append(":/MO/gui/archive_conflict_neutral");
+ }
if (m_ESPs[index].m_IsLightFlagged && !m_ESPs[index].m_IsLight) {
result.append(":/MO/gui/awaiting");
}
@@ -936,6 +969,7 @@ bool PluginList::setData(const QModelIndex &modIndex, const QVariant &value, int if (role == Qt::CheckStateRole) {
m_ESPs[modIndex.row()].m_Enabled =
value.toInt() == Qt::Checked || m_ESPs[modIndex.row()].m_ForceEnabled;
+ m_LastCheck.restart();
emit dataChanged(modIndex, modIndex);
refreshLoadOrder();
@@ -1228,9 +1262,9 @@ bool PluginList::eventFilter(QObject *obj, QEvent *event) PluginList::ESPInfo::ESPInfo(const QString &name, bool enabled,
const QString &originName, const QString &fullPath,
- bool hasIni)
+ bool hasIni, std::set<QString> archives)
: m_Name(name), m_FullPath(fullPath), m_Enabled(enabled), m_ForceEnabled(enabled),
- m_Priority(0), m_LoadOrder(-1), m_OriginName(originName), m_HasIni(hasIni), m_ModSelected(false)
+ m_Priority(0), m_LoadOrder(-1), m_OriginName(originName), m_HasIni(hasIni), m_Archives(archives), m_ModSelected(false)
{
try {
ESP::File file(ToWString(fullPath));
diff --git a/src/pluginlist.h b/src/pluginlist.h index f6745aa8..b8e35c32 100644 --- a/src/pluginlist.h +++ b/src/pluginlist.h @@ -28,6 +28,7 @@ namespace MOBase { class IPluginGame; } #include <QString>
#include <QListWidget>
#include <QTimer>
+#include <QTime>
#include <QTemporaryFile>
#pragma warning(push)
@@ -192,6 +193,8 @@ public: */
int enabledCount() const;
+ int timeElapsedSinceLastChecked() const;
+
QString getName(int index) const { return m_ESPs.at(index).m_Name; }
int getPriority(int index) const { return m_ESPs.at(index).m_Priority; }
QString getIndexPriority(int index) const;
@@ -273,11 +276,12 @@ signals: void writePluginsList();
+
private:
struct ESPInfo {
- ESPInfo(const QString &name, bool enabled, const QString &originName, const QString &fullPath, bool hasIni);
+ ESPInfo(const QString &name, bool enabled, const QString &originName, const QString &fullPath, bool hasIni, std::set<QString> archives);
QString m_Name;
QString m_FullPath;
bool m_Enabled;
@@ -294,6 +298,7 @@ private: QString m_Author;
QString m_Description;
bool m_HasIni;
+ std::set<QString> m_Archives;
std::set<QString> m_Masters;
mutable std::set<QString> m_MasterUnset;
bool operator < (const ESPInfo& str) const
@@ -346,6 +351,8 @@ private: QTemporaryFile m_TempFile;
+ QTime m_LastCheck;
+
const MOBase::IPluginGame *m_GamePlugin;
};
diff --git a/src/resources.qrc b/src/resources.qrc index a18baf45..f3459ea7 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -93,6 +93,7 @@ <file alias="string">resources/contents/conversation.png</file> <file alias="bsa">resources/contents/locked-chest.png</file> <file alias="menu">resources/contents/config.png</file> + <file alias="inifile">resources/contents/feather-and-scroll.png</file> </qresource> <qresource prefix="/qt/etc"> <file>qt.conf</file> diff --git a/src/resources/contents/feather-and-scroll.png b/src/resources/contents/feather-and-scroll.png Binary files differnew file mode 100644 index 00000000..f82694ca --- /dev/null +++ b/src/resources/contents/feather-and-scroll.png diff --git a/src/selfupdater.cpp b/src/selfupdater.cpp index d671bafc..2b051b09 100644 --- a/src/selfupdater.cpp +++ b/src/selfupdater.cpp @@ -102,12 +102,7 @@ SelfUpdater::SelfUpdater(NexusInterface *nexusInterface) throw MyException(InstallationManager::getErrorString(m_ArchiveHandler->getLastError()));
}
- VS_FIXEDFILEINFO version = GetFileVersion(ToWString(QApplication::applicationFilePath()));
-
- m_MOVersion = VersionInfo(version.dwFileVersionMS >> 16,
- version.dwFileVersionMS & 0xFFFF,
- version.dwFileVersionLS >> 16,
- version.dwFileVersionLS & 0xFFFF);
+ m_MOVersion = createVersionInfo();
}
diff --git a/src/settings.cpp b/src/settings.cpp index 2bcf2d02..db4ea565 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -712,9 +712,10 @@ Settings::PathsTab::PathsTab(Settings *parent, SettingsDialog &dialog) , m_cacheDirEdit(m_dialog.findChild<QLineEdit *>("cacheDirEdit")) , m_profilesDirEdit(m_dialog.findChild<QLineEdit *>("profilesDirEdit")) , m_overwriteDirEdit(m_dialog.findChild<QLineEdit *>("overwriteDirEdit")) + , m_managedGameDirEdit(m_dialog.findChild<QLineEdit *>("managedGameDirEdit")) { m_baseDirEdit->setText(m_parent->getBaseDirectory()); - + m_managedGameDirEdit->setText(m_parent->m_GamePlugin->gameDirectory().absoluteFilePath(m_parent->m_GamePlugin->binaryName())); QString basePath = parent->getBaseDirectory(); QDir baseDir(basePath); for (const auto &dir : { diff --git a/src/settings.h b/src/settings.h index 76ab55da..c49edfcb 100644 --- a/src/settings.h +++ b/src/settings.h @@ -403,6 +403,7 @@ private: QLineEdit *m_cacheDirEdit; QLineEdit *m_profilesDirEdit; QLineEdit *m_overwriteDirEdit; + QLineEdit *m_managedGameDirEdit; }; class DiagnosticsTab : public SettingsTab diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index 44fc9b5e..058d082a 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -241,7 +241,7 @@ void SettingsDialog::deleteBlacklistItem() void SettingsDialog::on_associateButton_clicked() { - Settings::instance().registerAsNXMHandler(false); + Settings::instance().registerAsNXMHandler(true); } void SettingsDialog::on_clearCacheButton_clicked() diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 85688cb8..374e1b84 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -17,7 +17,7 @@ <item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
- <number>0</number>
+ <number>1</number>
</property>
<widget class="QWidget" name="generalTab">
<attribute name="title">
@@ -170,26 +170,23 @@ If you use pre-releases, never contact me directly by e-mail or via private mess <layout class="QVBoxLayout" name="verticalLayout_10">
<item>
<layout class="QGridLayout" name="gridLayout_2">
- <item row="0" column="0">
- <widget class="QLabel" name="label_25">
+ <item row="6" column="2">
+ <widget class="QPushButton" name="browseOverwriteDirBtn">
<property name="text">
- <string>Base Directory</string>
+ <string>...</string>
</property>
</widget>
</item>
- <item row="6" column="2">
- <widget class="QPushButton" name="browseOverwriteDirBtn">
+ <item row="3" column="2">
+ <widget class="QPushButton" name="browseModDirBtn">
<property name="text">
- <string>...</string>
+ <string notr="true">...</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="overwriteDirEdit"/>
</item>
- <item row="0" column="1">
- <widget class="QLineEdit" name="baseDirEdit"/>
- </item>
<item row="0" column="2">
<widget class="QPushButton" name="browseBaseDirBtn">
<property name="text">
@@ -197,12 +194,8 @@ If you use pre-releases, never contact me directly by e-mail or via private mess </property>
</widget>
</item>
- <item row="6" column="0">
- <widget class="QLabel" name="label_24">
- <property name="text">
- <string>Overwrite</string>
- </property>
- </widget>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="baseDirEdit"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_9">
@@ -211,37 +204,57 @@ If you use pre-releases, never contact me directly by e-mail or via private mess </property>
</widget>
</item>
- <item row="3" column="2">
- <widget class="QPushButton" name="browseModDirBtn">
+ <item row="6" column="0">
+ <widget class="QLabel" name="label_24">
<property name="text">
- <string notr="true">...</string>
+ <string>Overwrite</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="downloadDirEdit">
+ <property name="toolTip">
+ <string>Directory where downloads are stored.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Directory where downloads are stored.</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="cacheDirEdit"/>
</item>
- <item row="2" column="0">
- <widget class="QLabel" name="label_7">
+ <item row="4" column="2">
+ <widget class="QPushButton" name="browseCacheDirBtn">
<property name="text">
- <string>Downloads</string>
+ <string notr="true">...</string>
</property>
</widget>
</item>
- <item row="4" column="2">
- <widget class="QPushButton" name="browseCacheDirBtn">
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_7">
<property name="text">
- <string notr="true">...</string>
+ <string>Downloads</string>
</property>
</widget>
</item>
- <item row="3" column="1">
- <widget class="QLineEdit" name="modDirEdit">
- <property name="toolTip">
- <string>Directory where mods are stored.</string>
+ <item row="1" column="1">
+ <spacer name="verticalSpacer_8">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
</property>
- <property name="whatsThis">
- <string>Directory where mods are stored. Please note that changing this will break all associations of profiles with mods that don't exist in the new location (with the same name).</string>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="label_22">
+ <property name="text">
+ <string>Profiles</string>
</property>
</widget>
</item>
@@ -258,20 +271,16 @@ If you use pre-releases, never contact me directly by e-mail or via private mess </property>
</widget>
</item>
- <item row="2" column="1">
- <widget class="QLineEdit" name="downloadDirEdit">
+ <item row="5" column="1">
+ <widget class="QLineEdit" name="profilesDirEdit"/>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="modDirEdit">
<property name="toolTip">
- <string>Directory where downloads are stored.</string>
+ <string>Directory where mods are stored.</string>
</property>
<property name="whatsThis">
- <string>Directory where downloads are stored.</string>
- </property>
- </widget>
- </item>
- <item row="3" column="0">
- <widget class="QLabel" name="label_8">
- <property name="text">
- <string>Mods</string>
+ <string>Directory where mods are stored. Please note that changing this will break all associations of profiles with mods that don't exist in the new location (with the same name).</string>
</property>
</widget>
</item>
@@ -282,18 +291,25 @@ If you use pre-releases, never contact me directly by e-mail or via private mess </property>
</widget>
</item>
- <item row="5" column="1">
- <widget class="QLineEdit" name="profilesDirEdit"/>
+ <item row="11" column="1">
+ <widget class="QLineEdit" name="managedGameDirEdit">
+ <property name="acceptDrops">
+ <bool>false</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
</item>
- <item row="5" column="0">
- <widget class="QLabel" name="label_22">
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_8">
<property name="text">
- <string>Profiles</string>
+ <string>Mods</string>
</property>
</widget>
</item>
- <item row="1" column="1">
- <spacer name="verticalSpacer_8">
+ <item row="10" column="1">
+ <spacer name="verticalSpacer_7">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
@@ -305,16 +321,30 @@ If you use pre-releases, never contact me directly by e-mail or via private mess </property>
</spacer>
</item>
+ <item row="11" column="0">
+ <widget class="QLabel" name="label_29">
+ <property name="text">
+ <string>Managed Game</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_25">
+ <property name="text">
+ <string>Base Directory</string>
+ </property>
+ </widget>
+ </item>
+ <item row="9" column="0" colspan="3">
+ <widget class="QLabel" name="label_26">
+ <property name="text">
+ <string>Use %BASE_DIR% to refer to the Base Directory.</string>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
<item>
- <widget class="QLabel" name="label_26">
- <property name="text">
- <string>Use %BASE_DIR% to refer to the Base Directory.</string>
- </property>
- </widget>
- </item>
- <item>
<spacer name="verticalSpacer_6">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -336,7 +366,7 @@ If you use pre-releases, never contact me directly by e-mail or via private mess </item>
</layout>
</widget>
- <widget class="QWidget" name="nexusTab">
+ <widget class="QWidget" name="nexusTab">
<attribute name="title">
<string>Nexus</string>
</attribute>
@@ -890,8 +920,8 @@ tl;dr-version: If Nexus-features don't work, insert the current version number o </item>
<item>
<widget class="QCheckBox" name="hideUncheckedBox">
- <property name="enabled">
- <bool>false</bool>
+ <property name="enabled">
+ <bool>false</bool>
</property>
<property name="toolTip">
<string>Enforces that inactive ESPs and ESMs are never loaded.</string>
@@ -986,187 +1016,187 @@ For the other games this is not a sufficient replacement for AI!</string> </layout>
</widget>
<widget class="QWidget" name="diagnosticsTab">
- <attribute name="title">
- <string>Diagnostics</string>
- </attribute>
- <layout class="QGridLayout" name="gridLayout_4">
- <item row="0" column="0">
- <layout class="QHBoxLayout" name="horizontalLayout_6">
- <item>
- <widget class="QLabel" name="label_12">
- <property name="text">
- <string>Log Level</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QComboBox" name="logLevelBox">
- <property name="toolTip">
- <string>Decides the amount of data printed to "ModOrganizer.log"</string>
- </property>
- <property name="whatsThis">
- <string>
+ <attribute name="title">
+ <string>Diagnostics</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout_4">
+ <item row="0" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout_6">
+ <item>
+ <widget class="QLabel" name="label_12">
+ <property name="text">
+ <string>Log Level</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="logLevelBox">
+ <property name="toolTip">
+ <string>Decides the amount of data printed to "ModOrganizer.log"</string>
+ </property>
+ <property name="whatsThis">
+ <string>
Decides the amount of data printed to "ModOrganizer.log".
"Debug" produces very useful information for finding problems. There is usually no noteworthy performance impact but the file may become rather large. If this is a problem you may prefer the "Info" level for regluar use. On the "Error" level the log file usually remains empty.
</string>
- </property>
- <item>
- <property name="text">
- <string>Debug</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Info (recommended)</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Warning</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Error</string>
- </property>
- </item>
- </widget>
- </item>
- </layout>
- </item>
- <item row="1" column="0">
- <spacer name="verticalSpacer_9">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="2" column="0">
- <layout class="QHBoxLayout" name="horizontalLayout_12">
- <item>
- <widget class="QLabel" name="label_27">
- <property name="text">
- <string>Crash Dumps</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QComboBox" name="dumpsTypeBox">
- <property name="toolTip">
- <string>Decides which type of crash dumps are collected when injected processes crash.</string>
- </property>
- <property name="whatsThis">
- <string>
+ </property>
+ <item>
+ <property name="text">
+ <string>Debug</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Info (recommended)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Warning</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Error</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <spacer name="verticalSpacer_9">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout_12">
+ <item>
+ <widget class="QLabel" name="label_27">
+ <property name="text">
+ <string>Crash Dumps</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="dumpsTypeBox">
+ <property name="toolTip">
+ <string>Decides which type of crash dumps are collected when injected processes crash.</string>
+ </property>
+ <property name="whatsThis">
+ <string>
Decides which type of crash dumps are collected when injected processes crash.
"None" Disables the generation of crash dumps by MO.
"Mini" Default level which generates small dumps (only stack traces).
"Data" Much larger dumps with additional information which may be need (also data segments).
"Full" Even larger dumps with a full memory dump of the process.
</string>
- </property>
- <item>
- <property name="text">
- <string>None</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Mini (recommended)</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Data</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Full</string>
- </property>
- </item>
- </widget>
- </item>
- </layout>
- </item>
- <item row="3" column="0">
- <layout class="QHBoxLayout" name="horizontalLayout_13">
- <item>
- <widget class="QLabel" name="label_28">
- <property name="text">
- <string>Max Dumps To Keep</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_6">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>60</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QSpinBox" name="dumpsMaxEdit">
- <property name="toolTip">
- <string>Maximum number of crash dumps to keep on disk. Use 0 for unlimited.</string>
- </property>
- <property name="whatsThis">
- <string>
+ </property>
+ <item>
+ <property name="text">
+ <string>None</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Mini (recommended)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Data</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Full</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="3" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout_13">
+ <item>
+ <widget class="QLabel" name="label_28">
+ <property name="text">
+ <string>Max Dumps To Keep</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_6">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>60</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="dumpsMaxEdit">
+ <property name="toolTip">
+ <string>Maximum number of crash dumps to keep on disk. Use 0 for unlimited.</string>
+ </property>
+ <property name="whatsThis">
+ <string>
Maximum number of crash dumps to keep on disk. Use 0 for unlimited.
- Set "Crash Dumps" above to None to disable crash dump collection.
+ Set "Crash Dumps" above to None to disable crash dump collection.
</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="4" column="0">
- <widget class="QLabel" name="diagnosticsExplainedLabel">
- <property name="text">
- <string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="diagnosticsExplainedLabel">
+ <property name="toolTip">
+ <string>Hint: right click link and copy link location</string>
+ </property>
+ <property name="text">
+ <string>
Logs and crash dumps are stored under your current instance in the <a href="LOGS_FULL_PATH">LOGS_DIR</a>
and <a href="DUMPS_FULL_PATH">DUMPS_DIR</a> folders.
Sending logs and/or crash dumps to the developers can help investigate issues.
It is recommended to compress large log and dmp files before sending.
</string>
- </property>
- <property name="wordWrap">
- <bool>true</bool>
- </property>
- <property name="toolTip">
- <string>Hint: right click link and copy link location</string>
- </property>
- </widget>
- </item>
- <item row="5" column="0">
- <spacer name="verticalSpacer_10">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Expanding</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>232</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
-</widget>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
+ <spacer name="verticalSpacer_10">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Expanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>232</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
</widget>
</item>
<item>
diff --git a/src/shared/util.cpp b/src/shared/util.cpp index 5491a9e6..102565f5 100644 --- a/src/shared/util.cpp +++ b/src/shared/util.cpp @@ -27,6 +27,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <DbgHelp.h>
#include <set>
#include <boost/scoped_array.hpp>
+#include <QApplication>
namespace MOShared {
@@ -174,5 +175,78 @@ VS_FIXEDFILEINFO GetFileVersion(const std::wstring &fileName) }
}
+std::wstring GetFileVersionString(const std::wstring &fileName)
+{
+ DWORD handle = 0UL;
+ DWORD size = ::GetFileVersionInfoSizeW(fileName.c_str(), &handle);
+ if (size == 0) {
+ throw windows_error("failed to determine file version info size");
+ }
+
+ boost::scoped_array<char> buffer(new char[size]);
+ try {
+ handle = 0UL;
+ if (!::GetFileVersionInfoW(fileName.c_str(), handle, size, buffer.get())) {
+ throw windows_error("failed to determine file version info");
+ }
+
+ LPVOID strBuffer = nullptr;
+ UINT strLength = 0;
+ if (!::VerQueryValue(buffer.get(), L"\\StringFileInfo\\040904B0\\ProductVersion", &strBuffer, &strLength)) {
+ throw windows_error("failed to determine file version");
+ }
+
+ return std::wstring((LPCTSTR)strBuffer);
+ }
+ catch (...) {
+ throw;
+ }
+}
+
+MOBase::VersionInfo createVersionInfo()
+{
+ VS_FIXEDFILEINFO version = GetFileVersion(QApplication::applicationFilePath().toStdWString());
+
+ if (version.dwFileFlags | VS_FF_PRERELEASE)
+ {
+ // Pre-release builds need annotating
+ QString versionString = QString::fromStdWString(GetFileVersionString(QApplication::applicationFilePath().toStdWString()));
+
+ // The pre-release flag can be set without the string specifying what type of pre-release
+ bool noLetters = true;
+ for (QChar character : versionString)
+ {
+ if (character.isLetter())
+ {
+ noLetters = false;
+ break;
+ }
+ }
+
+ if (noLetters)
+ {
+ // Default to pre-alpha when release type is unspecified
+ return MOBase::VersionInfo(version.dwFileVersionMS >> 16,
+ version.dwFileVersionMS & 0xFFFF,
+ version.dwFileVersionLS >> 16,
+ version.dwFileVersionLS & 0xFFFF,
+ MOBase::VersionInfo::RELEASE_PREALPHA);
+ }
+ else
+ {
+ // Trust the string to make sense
+ return MOBase::VersionInfo(versionString);
+ }
+ }
+ else
+ {
+ // Non-pre-release builds just need their version numbers reading
+ return MOBase::VersionInfo(version.dwFileVersionMS >> 16,
+ version.dwFileVersionMS & 0xFFFF,
+ version.dwFileVersionLS >> 16,
+ version.dwFileVersionLS & 0xFFFF);
+ }
+}
+
} // namespace MOShared
diff --git a/src/shared/util.h b/src/shared/util.h index 1e498059..1fdfb089 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -25,6 +25,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #define WIN32_LEAN_AND_MEAN
#include <Windows.h>
+#include <versioninfo.h>
+
namespace MOShared {
/// Test if a file (or directory) by the specified name exists
@@ -45,6 +47,8 @@ std::wstring ToLower(const std::wstring &text); bool CaseInsensitiveEqual(const std::wstring &lhs, const std::wstring &rhs);
VS_FIXEDFILEINFO GetFileVersion(const std::wstring &fileName);
+std::wstring GetFileVersionString(const std::wstring &fileName);
+MOBase::VersionInfo createVersionInfo();
} // namespace MOShared
diff --git a/src/version.rc b/src/version.rc index 083cbfb0..39565d70 100644 --- a/src/version.rc +++ b/src/version.rc @@ -1,13 +1,16 @@ #include "Winver.h"
-#define VER_FILEVERSION 2,1,3
-#define VER_FILEVERSION_STR "2.1.3\0"
+// If VS_FF_PRERELEASE is not set, MO labels the build as a release and uses VER_FILEVERSION to determine version number.
+// Otherwise, if letters are used in VER_FILEVERSION_STR, uses the full MOBase::VersionInfo parser
+// Otherwise, uses the numbers from VER_FILEVERSION and sets the release type as pre-alpha
+#define VER_FILEVERSION 2,1,4
+#define VER_FILEVERSION_STR "2.1.4\0"
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION
PRODUCTVERSION VER_FILEVERSION
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
-FILEFLAGS (0)
+FILEFLAGS VS_FF_PRERELEASE
FILEOS VOS__WINDOWS32
FILETYPE VFT_APP
FILESUBTYPE (0)
|
