mirror of
https://github.com/ModOrganizer2/modorganizer.git
synced 2026-07-27 13:58:24 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e2b799bd6b | ||
|
|
185eb8e5ef | ||
|
|
63efd21a6a | ||
|
|
ed67ac2113 | ||
|
|
9a33dc1480 | ||
|
|
1b0c437788 | ||
|
|
5e530becc2 | ||
|
|
d9835cc4ae | ||
|
|
18ea79c2d0 | ||
|
|
37a6989ba8 | ||
|
|
830b63c4e2 | ||
|
|
662772c2fc | ||
|
|
027edcf688 | ||
|
|
ff51aa10c2 | ||
|
|
cbc9d00584 | ||
|
|
e15f768a15 | ||
|
|
e63eba2ca1 | ||
|
|
20008e17b7 | ||
|
|
c24200bc04 | ||
|
|
25a9290cd5 | ||
|
|
efe657c23e | ||
|
|
571347d2de | ||
|
|
346bc630f8 | ||
|
|
013890f644 | ||
|
|
3559364473 | ||
|
|
92cdf41243 | ||
|
|
789e95ca58 | ||
|
|
9b9a1f435e | ||
|
|
7f82ffa664 | ||
|
|
68a1afed49 | ||
|
|
7b1ece5f28 | ||
|
|
2306e006dc | ||
|
|
f6cd53e932 | ||
|
|
5335188e63 | ||
|
|
dac716bb86 | ||
|
|
c486220d20 | ||
|
|
0af33ccddf | ||
|
|
413c045383 | ||
|
|
1266e13921 | ||
|
|
f4af3264f0 | ||
|
|
f61236e4cf | ||
|
|
d7e6fd1dd6 | ||
|
|
9d9dbd9f7e | ||
|
|
93763a9364 | ||
|
|
a94977988b | ||
|
|
c501b5cca0 | ||
|
|
c87d97de8c | ||
|
|
4914fd172d | ||
|
|
02fe0d3384 | ||
|
|
e76891b926 | ||
|
|
b53be165fd | ||
|
|
849d00521a | ||
|
|
deb3c5ca21 | ||
|
|
25448ef076 | ||
|
|
40919c1520 | ||
|
|
79c451bb17 | ||
|
|
87292ca30f | ||
|
|
c0b55690bc | ||
|
|
f1384cdfa7 | ||
|
|
c9658e1a65 | ||
|
|
9431597e66 | ||
|
|
4566b51093 | ||
|
|
2212ad6f1c | ||
|
|
6142872620 | ||
|
|
4cae1397e7 | ||
|
|
7fbfc12118 | ||
|
|
4eaa0d16bb | ||
|
|
a219d03444 | ||
|
|
ad01e1d608 | ||
|
|
aaa1523db9 | ||
|
|
effd05df06 | ||
|
|
545b7b4eb7 | ||
|
|
71830a65d4 | ||
|
|
bde2e5fca1 | ||
|
|
15bbfdfa6f | ||
|
|
a85a6e635e | ||
|
|
9abb3ca162 | ||
|
|
5588b8b756 | ||
|
|
d48392c89f | ||
|
|
21d61e617b | ||
|
|
a48a20f13f | ||
|
|
2e09e633bd | ||
|
|
1189b8cc33 | ||
|
|
17f1cf0aab | ||
|
|
78cd0110d3 | ||
|
|
2c57899cf6 | ||
|
|
3dbfba91e1 | ||
|
|
2c53f9d934 | ||
|
|
6323a348da | ||
|
|
73842ee245 | ||
|
|
122744454c | ||
|
|
5de173ba1a | ||
|
|
eb26120332 | ||
|
|
6056202ead | ||
|
|
c1d90b131b | ||
|
|
63a66c8754 | ||
|
|
ab95f78689 | ||
|
|
9e66799abf | ||
|
|
dce6507dad | ||
|
|
42d2344f0b | ||
|
|
18e49b71b5 | ||
|
|
fcb29afe83 | ||
|
|
cf52aa335a | ||
|
|
9c35443780 | ||
|
|
9c6c01df56 | ||
|
|
b83807e4d5 | ||
|
|
2d50b17243 | ||
|
|
5a1d4e8783 | ||
|
|
478aeeb28c | ||
|
|
07fc9d3546 | ||
|
|
15ab8d5c5e | ||
|
|
192f14b001 | ||
|
|
3ccceb19e1 | ||
|
|
2d9a2a0432 | ||
|
|
ac650ae078 | ||
|
|
1a91174757 | ||
|
|
e2ec6632ec | ||
|
|
b1a3bdd6e8 | ||
|
|
22a004be2e | ||
|
|
a3cb400152 | ||
|
|
3e29d31231 | ||
|
|
edf48bca6f | ||
|
|
33e11e2056 | ||
|
|
67fb7e56d3 | ||
|
|
979206228d | ||
|
|
ba162804cd | ||
|
|
c6751b690a | ||
|
|
138154aca0 | ||
|
|
c576f1ff40 | ||
|
|
c4636d891f | ||
|
|
8ea8444dc8 | ||
|
|
2232bdfc77 | ||
|
|
258bddb6b7 | ||
|
|
364289db72 | ||
|
|
ef771fd8ca | ||
|
|
2060df1585 | ||
|
|
9a973ccf5f | ||
|
|
a2eb3e0266 | ||
|
|
d65031c814 | ||
|
|
c27e718fbd | ||
|
|
43b2df9077 | ||
|
|
79b2e52a58 | ||
|
|
16a7ef78d3 | ||
|
|
74202cc743 | ||
|
|
8f86130759 | ||
|
|
17e4ec7b13 | ||
|
|
9a426a2474 | ||
|
|
80594d6e1a | ||
|
|
56473e0ec8 | ||
|
|
71988e386c | ||
|
|
5e7c0fddf0 | ||
|
|
b0c15c9cfb | ||
|
|
f92027bea6 | ||
|
|
a31b5495b8 | ||
|
|
fc19486f53 | ||
|
|
232bbfb23b | ||
|
|
2af99f2170 | ||
|
|
796224d733 | ||
|
|
1e4b5d2436 | ||
|
|
94ef8dffbc | ||
|
|
7b1821a518 | ||
|
|
fb0d4d5e5a | ||
|
|
9a3a15b1f6 | ||
|
|
1ea43586d8 | ||
|
|
fd51434e5e | ||
|
|
7eb4b33214 | ||
|
|
e1e367c7ea | ||
|
|
696bb3bc47 | ||
|
|
10be66a62a | ||
|
|
a02b920b19 | ||
|
|
2f8e5b4f69 | ||
|
|
385765ecdd | ||
|
|
447a2169fe | ||
|
|
fc8a6b358f | ||
|
|
edf608ab23 | ||
|
|
d02df7e4b4 | ||
|
|
cc63717060 | ||
|
|
8f28e0af36 | ||
|
|
e80bb3a837 | ||
|
|
f6ecb93d46 | ||
|
|
4f14598cfc | ||
|
|
ce2494ba20 | ||
|
|
d5f3bee642 | ||
|
|
b38957d853 | ||
|
|
f824d255a2 | ||
|
|
344b83957e | ||
|
|
023cacab7f | ||
|
|
35bbe0001e | ||
|
|
75478f68a1 | ||
|
|
5a0b8b431c | ||
|
|
61b33a8351 | ||
|
|
103e3f3098 | ||
|
|
872c33fe55 | ||
|
|
9ddb26ea51 | ||
|
|
1867c20f02 | ||
|
|
6552054e58 | ||
|
|
a830f3e09e | ||
|
|
eaf3655492 | ||
|
|
952f1fe8cd | ||
|
|
b4530eb843 | ||
|
|
f20a1f6a84 | ||
|
|
942e656a71 | ||
|
|
7f3dc586b0 | ||
|
|
2524d65441 | ||
|
|
5efddbd515 | ||
|
|
181de232f4 | ||
|
|
1f9103c24e | ||
|
|
2d49ba2bef | ||
|
|
e41c97b64f | ||
|
|
b7d6bbb451 | ||
|
|
4a765cc152 | ||
|
|
30f170c10d | ||
|
|
b6aa12b323 | ||
|
|
19d80cc23d | ||
|
|
0c4b1e9a92 | ||
|
|
cacf7e0542 | ||
|
|
f09ec53fcf | ||
|
|
ddb40b712e | ||
|
|
186f26b71e | ||
|
|
6d6444c126 | ||
|
|
4b66c6c1ef | ||
|
|
08f35d6519 | ||
|
|
6617be8ef9 | ||
|
|
5a5bfee712 | ||
|
|
2fc55ccc86 | ||
|
|
8731159bfb | ||
|
|
1c6543454e | ||
|
|
941c50bff9 | ||
|
|
1e6e055f39 | ||
|
|
81e329fb39 | ||
|
|
15db1b76f7 | ||
|
|
75e6c72ae4 | ||
|
|
9c1806cc74 | ||
|
|
8f905e1d49 | ||
|
|
2ee5f0e96d | ||
|
|
0d220b6b41 | ||
|
|
decbbb611e | ||
|
|
aeb0b42cde | ||
|
|
38391b10e9 |
@@ -0,0 +1,16 @@
|
||||
root = true
|
||||
|
||||
[*.cpp]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
|
||||
[*.h]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
|
||||
[*.ui]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
@@ -20,7 +20,7 @@ Through the work of a few people of the community MO2 has come quite far, now it
|
||||
## Reporting Issues:
|
||||
Issues should be reported to the GitHub page or on the open discord server: [ModOrganizerDevs](https://discord.gg/vD2ZbfX). Here is also where dev builds are tested, bugs are reported and investigated, suggestions are discussed and a lot more.
|
||||
|
||||
Credits to Tannin, LePresidente, Silarn, erasmux, AL12 and many others for the development.
|
||||
Credits to Tannin, LePresidente, Silarn, erasmux, AL12, LostDragonist, AnyOldName3 and many others for the development.
|
||||
|
||||
## Download Location
|
||||
|
||||
@@ -49,6 +49,7 @@ Here is a complete list:
|
||||
* https://github.com/Modorganizer2/modorganizer-check_fnis
|
||||
* https://github.com/Modorganizer2/modorganizer-diagnose_basic
|
||||
* https://github.com/Modorganizer2/modorganizer-esptk
|
||||
* https://github.com/ModOrganizer2/modorganizer-fnistool
|
||||
* https://github.com/Modorganizer2/modorganizer-helper
|
||||
* https://github.com/Modorganizer2/modorganizer-game_fallout3
|
||||
* https://github.com/Modorganizer2/modorganizer-game_fallout4
|
||||
@@ -60,6 +61,7 @@ Here is a complete list:
|
||||
* https://github.com/Modorganizer2/modorganizer-game_oblivion
|
||||
* https://github.com/Modorganizer2/modorganizer-game_skyrim
|
||||
* https://github.com/Modorganizer2/modorganizer-game_skyrimSE
|
||||
* https://github.com/ModOrganizer2/modorganizer-game_skyrimVR
|
||||
* https://github.com/Modorganizer2/modorganizer-game_ttw
|
||||
* https://github.com/Modorganizer2/modorganizer-installer_bain
|
||||
* https://github.com/Modorganizer2/modorganizer-installer_bundle
|
||||
|
||||
+7
-1
@@ -37,6 +37,7 @@ SET(organizer_SRCS
|
||||
modinfoforeign.cpp
|
||||
modinfooverwrite.cpp
|
||||
modinforegular.cpp
|
||||
modinfoseparator.cpp
|
||||
modinfowithconflictinfo.cpp
|
||||
messagedialog.cpp
|
||||
mainwindow.cpp
|
||||
@@ -90,6 +91,7 @@ SET(organizer_SRCS
|
||||
usvfsconnector.cpp
|
||||
eventfilter.cpp
|
||||
moshortcut.cpp
|
||||
listdialog.cpp
|
||||
|
||||
shared/windows_error.cpp
|
||||
shared/error_report.cpp
|
||||
@@ -128,6 +130,7 @@ SET(organizer_HDRS
|
||||
modinfoforeign.h
|
||||
modinfooverwrite.h
|
||||
modinforegular.h
|
||||
modinfoseparator.h
|
||||
modinfowithconflictinfo.h
|
||||
messagedialog.h
|
||||
mainwindow.h
|
||||
@@ -183,6 +186,7 @@ SET(organizer_HDRS
|
||||
eventfilter.h
|
||||
descriptionpage.h
|
||||
moshortcut.h
|
||||
listdialog.h
|
||||
|
||||
shared/windows_error.h
|
||||
shared/error_report.h
|
||||
@@ -223,6 +227,7 @@ SET(organizer_UIS
|
||||
previewdialog.ui
|
||||
browserdialog.ui
|
||||
aboutdialog.ui
|
||||
listdialog.ui
|
||||
)
|
||||
|
||||
SET(organizer_QRCS
|
||||
@@ -288,7 +293,8 @@ INCLUDE_DIRECTORIES(${project_path}/uibase/src
|
||||
${project_path}/esptk/src
|
||||
${project_path}/archive/src
|
||||
${project_path}/../usvfs/include
|
||||
${project_path}/game_gamebryo/src
|
||||
${project_path}/game_gamebryo/src/gamebryo
|
||||
${project_path}/game_gamebryo/src/creation
|
||||
${project_path}/game_features/src
|
||||
${project_path}/githubpp/src
|
||||
${LZ4_ROOT}/include)
|
||||
|
||||
+6
-1
@@ -189,6 +189,11 @@
|
||||
<property name="text">
|
||||
<string notr="true">Silarn</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">LostDragonist</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -208,7 +213,7 @@
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">AnyOldName3 (Python Plugins)</string>
|
||||
<string notr="true">AnyOldName3</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
|
||||
+4
-2
@@ -47,8 +47,10 @@ public:
|
||||
static const int CATEGORY_SPECIAL_NOCATEGORY = 10003;
|
||||
static const int CATEGORY_SPECIAL_CONFLICT = 10004;
|
||||
static const int CATEGORY_SPECIAL_NOTENDORSED = 10005;
|
||||
static const int CATEGORY_SPECIAL_MANAGED = 10006;
|
||||
static const int CATEGORY_SPECIAL_UNMANAGED = 10007;
|
||||
static const int CATEGORY_SPECIAL_BACKUP = 10006;
|
||||
static const int CATEGORY_SPECIAL_MANAGED = 10007;
|
||||
static const int CATEGORY_SPECIAL_UNMANAGED = 10008;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
+2
-1
@@ -39,7 +39,8 @@ public:
|
||||
enum EColumn {
|
||||
COL_NAME = 0,
|
||||
COL_FILETIME,
|
||||
COL_STATUS
|
||||
COL_STATUS,
|
||||
COL_SIZE
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+95
-16
@@ -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,27 @@ 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::issueOpenFile()
|
||||
{
|
||||
emit openFile(m_ContextRow);
|
||||
}
|
||||
|
||||
void DownloadListWidgetDelegate::issueOpenInDownloadsFolder()
|
||||
{
|
||||
emit openInDownloadsFolder(m_ContextRow);
|
||||
}
|
||||
|
||||
void DownloadListWidgetDelegate::issueCancel()
|
||||
@@ -256,7 +299,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 +308,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 +342,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 +359,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 +376,15 @@ 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("Open File"), this, SLOT(issueOpenFile()));
|
||||
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 +394,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();
|
||||
|
||||
@@ -71,14 +71,19 @@ signals:
|
||||
void cancelDownload(int index);
|
||||
void pauseDownload(int index);
|
||||
void resumeDownload(int index);
|
||||
void visitOnNexus(int index);
|
||||
void openFile(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 +92,19 @@ private slots:
|
||||
void issueDelete();
|
||||
void issueRemoveFromView();
|
||||
void issueRestoreToView();
|
||||
void issueRestoreToViewAll();
|
||||
void issueVisitOnNexus();
|
||||
void issueOpenFile();
|
||||
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);
|
||||
|
||||
@@ -86,6 +86,9 @@
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string notr="true">KB</string>
|
||||
</property>
|
||||
<property name="visible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -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,32 @@ void DownloadListWidgetCompactDelegate::issueRemoveFromView()
|
||||
emit removeDownload(m_ContextIndex.row(), false);
|
||||
}
|
||||
|
||||
void DownloadListWidgetCompactDelegate::issueVisitOnNexus()
|
||||
{
|
||||
emit visitOnNexus(m_ContextIndex.row());
|
||||
}
|
||||
|
||||
void DownloadListWidgetCompactDelegate::issueOpenFile()
|
||||
{
|
||||
emit openFile(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 +301,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 +328,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 +346,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 +363,12 @@ 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("Open File"), this, SLOT(issueOpenFile()));
|
||||
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 +378,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 +411,3 @@ bool DownloadListWidgetCompactDelegate::editorEvent(QEvent *event, QAbstractItem
|
||||
|
||||
return QItemDelegate::editorEvent(event, model, option, index);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ class DownloadListWidgetCompact;
|
||||
class DownloadListWidgetCompact : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
public:
|
||||
explicit DownloadListWidgetCompact(QWidget *parent = 0);
|
||||
~DownloadListWidgetCompact();
|
||||
@@ -69,9 +69,13 @@ signals:
|
||||
void cancelDownload(int index);
|
||||
void pauseDownload(int index);
|
||||
void resumeDownload(int index);
|
||||
void visitOnNexus(int index);
|
||||
void openFile(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 +91,19 @@ private slots:
|
||||
void issueDelete();
|
||||
void issueRemoveFromView();
|
||||
void issueRestoreToView();
|
||||
void issueRestoreToViewAll();
|
||||
void issueVisitOnNexus();
|
||||
void issueOpenFile();
|
||||
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 +129,3 @@ private:
|
||||
};
|
||||
|
||||
#endif // DOWNLOADLISTWIDGETCOMPACT_H
|
||||
|
||||
|
||||
@@ -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,18 +58,25 @@
|
||||
</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">
|
||||
|
||||
+278
-56
File diff suppressed because it is too large
Load Diff
+38
-1
@@ -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:
|
||||
@@ -136,6 +138,13 @@ 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
|
||||
*
|
||||
@@ -143,6 +152,17 @@ public:
|
||||
**/
|
||||
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,12 @@ public slots:
|
||||
|
||||
void queryInfo(int index);
|
||||
|
||||
void visitOnNexus(int index);
|
||||
|
||||
void openFile(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 +469,7 @@ private slots:
|
||||
void downloadError(QNetworkReply::NetworkError error);
|
||||
void metaDataChanged();
|
||||
void directoryChanged(const QString &dirctory);
|
||||
void checkDownloadTimeout();
|
||||
|
||||
private:
|
||||
|
||||
@@ -497,6 +524,8 @@ private:
|
||||
|
||||
static QString getFileTypeString(int fileType);
|
||||
|
||||
void writeData(DownloadInfo *info);
|
||||
|
||||
private:
|
||||
|
||||
static const int AUTOMATIC_RETRIES = 3;
|
||||
@@ -517,6 +546,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 +559,8 @@ private:
|
||||
QRegExp m_DateExpression;
|
||||
|
||||
MOBase::IPluginGame const *m_ManagedGame;
|
||||
|
||||
QTimer m_TimeoutTimer;
|
||||
};
|
||||
|
||||
|
||||
|
||||
+928
-917
File diff suppressed because it is too large
Load Diff
+227
-224
@@ -1,224 +1,227 @@
|
||||
/*
|
||||
Copyright (C) 2012 Sebastian Herbord. All rights reserved.
|
||||
|
||||
This file is part of Mod Organizer.
|
||||
|
||||
Mod Organizer is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Mod Organizer is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INSTALLATIONMANAGER_H
|
||||
#define INSTALLATIONMANAGER_H
|
||||
|
||||
|
||||
#include <iinstallationmanager.h>
|
||||
#include <iplugininstaller.h>
|
||||
#include <guessedvalue.h>
|
||||
|
||||
#include <QObject>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <archive.h>
|
||||
#include <QProgressDialog>
|
||||
#include <set>
|
||||
#include <errorcodes.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief manages the installation of mod archives
|
||||
* This currently supports two special kind of archives:
|
||||
* - "simple" archives: properly packaged archives without options, so they can be extracted to the (virtual) data directory directly
|
||||
* - "complex" bain archives: archives with options for the bain system.
|
||||
* All other archives are managed through the manual "InstallDialog"
|
||||
* @todo this may be a good place to support plugins
|
||||
**/
|
||||
class InstallationManager : public QObject, public MOBase::IInstallationManager
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief constructor
|
||||
*
|
||||
* @param parent parent object.
|
||||
**/
|
||||
explicit InstallationManager();
|
||||
|
||||
virtual ~InstallationManager();
|
||||
|
||||
void setParentWidget(QWidget *widget);
|
||||
|
||||
void setURL(const QString &url);
|
||||
|
||||
/**
|
||||
* @brief update the directory where mods are to be installed
|
||||
* @param modsDirectory the mod directory
|
||||
* @note this is called a lot, probably redundantly
|
||||
*/
|
||||
void setModsDirectory(const QString &modsDirectory) { m_ModsDirectory = modsDirectory; }
|
||||
|
||||
/**
|
||||
* @brief update the directory where downloads are stored
|
||||
* @param downloadDirectory the download directory
|
||||
*/
|
||||
void setDownloadDirectory(const QString &downloadDirectory) { m_DownloadsDirectory = downloadDirectory; }
|
||||
|
||||
/**
|
||||
* @brief install a mod from an archive
|
||||
*
|
||||
* @param fileName absolute file name of the archive to install
|
||||
* @param modName suggested name of the mod. If this is empty (the default), a name will be guessed based on the filename. The user will always have a chance to rename the mod
|
||||
* @return true if the archive was installed, false if installation failed or was refused
|
||||
* @exception std::exception an exception may be thrown if the archive can't be opened (maybe the format is invalid or the file is damaged)
|
||||
**/
|
||||
bool install(const QString &fileName, MOBase::GuessedValue<QString> &modName, bool &hasIniTweaks);
|
||||
|
||||
/**
|
||||
* @return true if the installation was canceled
|
||||
**/
|
||||
bool wasCancelled();
|
||||
|
||||
/**
|
||||
* @brief retrieve a string describing the specified error code
|
||||
*
|
||||
* @param errorCode an error code as returned by the archiving function
|
||||
* @return the error string
|
||||
* @todo This function doesn't belong here, it is only public because the SelfUpdater class also uses "Archive" to get to the package.txt file
|
||||
**/
|
||||
static QString getErrorString(Archive::Error errorCode);
|
||||
|
||||
/**
|
||||
* @brief register an installer-plugin
|
||||
* @param the installer to register
|
||||
*/
|
||||
void registerInstaller(MOBase::IPluginInstaller *installer);
|
||||
|
||||
/**
|
||||
* @return list of file extensions we can install
|
||||
*/
|
||||
QStringList getSupportedExtensions() const;
|
||||
|
||||
/**
|
||||
* @brief extract the specified file from the currently open archive to a temporary location
|
||||
* @param (relative) name of the file within the archive
|
||||
* @return the absolute name of the temporary file
|
||||
* @note the call will fail with an exception if no archive is open (plugins deriving
|
||||
* from IPluginInstallerSimple can rely on that, custom installers shouldn't)
|
||||
* @note the temporary file is automatically cleaned up after the installation
|
||||
* @note This call can be very slow if the archive is large and "solid"
|
||||
*/
|
||||
virtual QString extractFile(const QString &fileName);
|
||||
|
||||
/**
|
||||
* @brief extract the specified files from the currently open archive to a temporary location
|
||||
* @param (relative) names of files within the archive
|
||||
* @return the absolute names of the temporary files
|
||||
* @note the call will fail with an exception if no archive is open (plugins deriving
|
||||
* from IPluginInstallerSimple can rely on that, custom installers shouldn't)
|
||||
* @note the temporary file is automatically cleaned up after the installation
|
||||
* @note This call can be very slow if the archive is large and "solid"
|
||||
*/
|
||||
virtual QStringList extractFiles(const QStringList &files, bool flatten);
|
||||
|
||||
/**
|
||||
* @brief installs an archive
|
||||
* @param modName suggested name of the mod
|
||||
* @param archiveFile path to the archive to install
|
||||
* @return the installation result
|
||||
*/
|
||||
virtual MOBase::IPluginInstaller::EInstallResult installArchive(MOBase::GuessedValue<QString> &modName, const QString &archiveName);
|
||||
|
||||
/**
|
||||
* @brief test if the specified mod name is free. If not, query the user how to proceed
|
||||
* @param modName current possible names for the mod
|
||||
* @param merge if this value is not null, the value will be set to whether the use chose to merge or replace
|
||||
* @return true if we can proceed with the installation, false if the user canceled or in case of an unrecoverable error
|
||||
*/
|
||||
virtual bool testOverwrite(MOBase::GuessedValue<QString> &modName, bool *merge = nullptr) const;
|
||||
|
||||
private:
|
||||
|
||||
void queryPassword(QString *password);
|
||||
void updateProgress(float percentage);
|
||||
void updateProgressFile(const QString &fileName);
|
||||
void report7ZipError(const QString &errorMessage);
|
||||
|
||||
MOBase::DirectoryTree *createFilesTree();
|
||||
|
||||
// remap all files in the archive to the directory structure represented by baseNode
|
||||
// files not present in baseNode are disabled
|
||||
void mapToArchive(const MOBase::DirectoryTree::Node *baseNode);
|
||||
|
||||
// recursive worker function for mapToArchive
|
||||
void mapToArchive(const MOBase::DirectoryTree::Node *node, QString path, FileData * const *data);
|
||||
bool unpackSingleFile(const QString &fileName);
|
||||
|
||||
|
||||
bool isSimpleArchiveTopLayer(const MOBase::DirectoryTree::Node *node, bool bainStyle);
|
||||
MOBase::DirectoryTree::Node *getSimpleArchiveBase(MOBase::DirectoryTree *dataTree);
|
||||
|
||||
bool doInstall(MOBase::GuessedValue<QString> &modName, QString gameName,
|
||||
int modID, const QString &version, const QString &newestVersion, int categoryID, const QString &repository);
|
||||
|
||||
QString generateBackupName(const QString &directoryName) const;
|
||||
|
||||
bool ensureValidModName(MOBase::GuessedValue<QString> &name) const;
|
||||
|
||||
void postInstallCleanup();
|
||||
|
||||
signals:
|
||||
|
||||
void progressUpdate(float percentage);
|
||||
void progressUpdate(QString const fileName);
|
||||
|
||||
private:
|
||||
|
||||
struct ByPriority {
|
||||
bool operator()(MOBase::IPluginInstaller *LHS, MOBase::IPluginInstaller *RHS) const
|
||||
{
|
||||
return LHS->priority() > RHS->priority();
|
||||
}
|
||||
};
|
||||
|
||||
struct CaseInsensitive {
|
||||
bool operator() (const QString &LHS, const QString &RHS) const
|
||||
{
|
||||
return QString::compare(LHS, RHS, Qt::CaseInsensitive) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
QWidget *m_ParentWidget;
|
||||
|
||||
QString m_ModsDirectory;
|
||||
QString m_DownloadsDirectory;
|
||||
|
||||
std::vector<MOBase::IPluginInstaller*> m_Installers;
|
||||
std::set<QString, CaseInsensitive> m_SupportedExtensions;
|
||||
|
||||
Archive *m_ArchiveHandler;
|
||||
QString m_CurrentFile;
|
||||
|
||||
QProgressDialog *m_InstallationProgress { nullptr };
|
||||
int m_Progress;
|
||||
QString m_ProgressFile;
|
||||
|
||||
std::set<QString> m_TempFilesToDelete;
|
||||
|
||||
QString m_URL;
|
||||
};
|
||||
|
||||
|
||||
#endif // INSTALLATIONMANAGER_H
|
||||
/*
|
||||
Copyright (C) 2012 Sebastian Herbord. All rights reserved.
|
||||
|
||||
This file is part of Mod Organizer.
|
||||
|
||||
Mod Organizer is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Mod Organizer is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INSTALLATIONMANAGER_H
|
||||
#define INSTALLATIONMANAGER_H
|
||||
|
||||
|
||||
#include <iinstallationmanager.h>
|
||||
#include <iplugininstaller.h>
|
||||
#include <guessedvalue.h>
|
||||
|
||||
#include <QObject>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <archive.h>
|
||||
#include <QProgressDialog>
|
||||
#include <set>
|
||||
#include <errorcodes.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief manages the installation of mod archives
|
||||
* This currently supports two special kind of archives:
|
||||
* - "simple" archives: properly packaged archives without options, so they can be extracted to the (virtual) data directory directly
|
||||
* - "complex" bain archives: archives with options for the bain system.
|
||||
* All other archives are managed through the manual "InstallDialog"
|
||||
* @todo this may be a good place to support plugins
|
||||
**/
|
||||
class InstallationManager : public QObject, public MOBase::IInstallationManager
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief constructor
|
||||
*
|
||||
* @param parent parent object.
|
||||
**/
|
||||
explicit InstallationManager();
|
||||
|
||||
virtual ~InstallationManager();
|
||||
|
||||
void setParentWidget(QWidget *widget);
|
||||
|
||||
void setURL(const QString &url);
|
||||
|
||||
/**
|
||||
* @brief update the directory where mods are to be installed
|
||||
* @param modsDirectory the mod directory
|
||||
* @note this is called a lot, probably redundantly
|
||||
*/
|
||||
void setModsDirectory(const QString &modsDirectory) { m_ModsDirectory = modsDirectory; }
|
||||
|
||||
/**
|
||||
* @brief update the directory where downloads are stored
|
||||
* @param downloadDirectory the download directory
|
||||
*/
|
||||
void setDownloadDirectory(const QString &downloadDirectory) { m_DownloadsDirectory = downloadDirectory; }
|
||||
|
||||
/**
|
||||
* @brief install a mod from an archive
|
||||
*
|
||||
* @param fileName absolute file name of the archive to install
|
||||
* @param modName suggested name of the mod. If this is empty (the default), a name will be guessed based on the filename. The user will always have a chance to rename the mod
|
||||
* @return true if the archive was installed, false if installation failed or was refused
|
||||
* @exception std::exception an exception may be thrown if the archive can't be opened (maybe the format is invalid or the file is damaged)
|
||||
**/
|
||||
bool install(const QString &fileName, MOBase::GuessedValue<QString> &modName, bool &hasIniTweaks, int modID = 0);
|
||||
|
||||
/**
|
||||
* @return true if the installation was canceled
|
||||
**/
|
||||
bool wasCancelled();
|
||||
|
||||
/**
|
||||
* @brief retrieve a string describing the specified error code
|
||||
*
|
||||
* @param errorCode an error code as returned by the archiving function
|
||||
* @return the error string
|
||||
* @todo This function doesn't belong here, it is only public because the SelfUpdater class also uses "Archive" to get to the package.txt file
|
||||
**/
|
||||
static QString getErrorString(Archive::Error errorCode);
|
||||
|
||||
/**
|
||||
* @brief register an installer-plugin
|
||||
* @param the installer to register
|
||||
*/
|
||||
void registerInstaller(MOBase::IPluginInstaller *installer);
|
||||
|
||||
/**
|
||||
* @return list of file extensions we can install
|
||||
*/
|
||||
QStringList getSupportedExtensions() const;
|
||||
|
||||
/**
|
||||
* @brief extract the specified file from the currently open archive to a temporary location
|
||||
* @param (relative) name of the file within the archive
|
||||
* @return the absolute name of the temporary file
|
||||
* @note the call will fail with an exception if no archive is open (plugins deriving
|
||||
* from IPluginInstallerSimple can rely on that, custom installers shouldn't)
|
||||
* @note the temporary file is automatically cleaned up after the installation
|
||||
* @note This call can be very slow if the archive is large and "solid"
|
||||
*/
|
||||
virtual QString extractFile(const QString &fileName);
|
||||
|
||||
/**
|
||||
* @brief extract the specified files from the currently open archive to a temporary location
|
||||
* @param (relative) names of files within the archive
|
||||
* @return the absolute names of the temporary files
|
||||
* @note the call will fail with an exception if no archive is open (plugins deriving
|
||||
* from IPluginInstallerSimple can rely on that, custom installers shouldn't)
|
||||
* @note the temporary file is automatically cleaned up after the installation
|
||||
* @note This call can be very slow if the archive is large and "solid"
|
||||
*/
|
||||
virtual QStringList extractFiles(const QStringList &files, bool flatten);
|
||||
|
||||
/**
|
||||
* @brief installs an archive
|
||||
* @param modName suggested name of the mod
|
||||
* @param archiveFile path to the archive to install
|
||||
* @return the installation result
|
||||
*/
|
||||
virtual MOBase::IPluginInstaller::EInstallResult installArchive(MOBase::GuessedValue<QString> &modName, const QString &archiveName, const int &modId = 0);
|
||||
|
||||
/**
|
||||
* @brief test if the specified mod name is free. If not, query the user how to proceed
|
||||
* @param modName current possible names for the mod
|
||||
* @param merge if this value is not null, the value will be set to whether the use chose to merge or replace
|
||||
* @return true if we can proceed with the installation, false if the user canceled or in case of an unrecoverable error
|
||||
*/
|
||||
virtual bool testOverwrite(MOBase::GuessedValue<QString> &modName, bool *merge = nullptr) const;
|
||||
|
||||
QString generateBackupName(const QString &directoryName) const;
|
||||
|
||||
private:
|
||||
|
||||
void queryPassword(QString *password);
|
||||
void updateProgress(float percentage);
|
||||
void updateProgressFile(const QString &fileName);
|
||||
void report7ZipError(const QString &errorMessage);
|
||||
|
||||
MOBase::DirectoryTree *createFilesTree();
|
||||
|
||||
// remap all files in the archive to the directory structure represented by baseNode
|
||||
// files not present in baseNode are disabled
|
||||
void mapToArchive(const MOBase::DirectoryTree::Node *baseNode);
|
||||
|
||||
// recursive worker function for mapToArchive
|
||||
void mapToArchive(const MOBase::DirectoryTree::Node *node, QString path, FileData * const *data);
|
||||
bool unpackSingleFile(const QString &fileName);
|
||||
|
||||
|
||||
bool isSimpleArchiveTopLayer(const MOBase::DirectoryTree::Node *node, bool bainStyle);
|
||||
MOBase::DirectoryTree::Node *getSimpleArchiveBase(MOBase::DirectoryTree *dataTree);
|
||||
|
||||
bool doInstall(MOBase::GuessedValue<QString> &modName, QString gameName,
|
||||
int modID, const QString &version, const QString &newestVersion, int categoryID, const QString &repository);
|
||||
|
||||
//QString generateBackupName(const QString &directoryName) const;
|
||||
|
||||
bool ensureValidModName(MOBase::GuessedValue<QString> &name) const;
|
||||
|
||||
void postInstallCleanup();
|
||||
|
||||
signals:
|
||||
|
||||
void progressUpdate(float percentage);
|
||||
void progressUpdate(QString const fileName);
|
||||
|
||||
private:
|
||||
|
||||
struct ByPriority {
|
||||
bool operator()(MOBase::IPluginInstaller *LHS, MOBase::IPluginInstaller *RHS) const
|
||||
{
|
||||
return LHS->priority() > RHS->priority();
|
||||
}
|
||||
};
|
||||
|
||||
struct CaseInsensitive {
|
||||
bool operator() (const QString &LHS, const QString &RHS) const
|
||||
{
|
||||
return QString::compare(LHS, RHS, Qt::CaseInsensitive) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
QWidget *m_ParentWidget;
|
||||
|
||||
QString m_ModsDirectory;
|
||||
QString m_DownloadsDirectory;
|
||||
|
||||
std::vector<MOBase::IPluginInstaller*> m_Installers;
|
||||
std::set<QString, CaseInsensitive> m_SupportedExtensions;
|
||||
|
||||
Archive *m_ArchiveHandler;
|
||||
QString m_CurrentFile;
|
||||
QString m_ErrorMessage;
|
||||
|
||||
QProgressDialog *m_InstallationProgress { nullptr };
|
||||
int m_Progress;
|
||||
QString m_ProgressFile;
|
||||
|
||||
std::set<QString> m_TempFilesToDelete;
|
||||
|
||||
QString m_URL;
|
||||
};
|
||||
|
||||
|
||||
#endif // INSTALLATIONMANAGER_H
|
||||
|
||||
+36
-5
@@ -66,6 +66,7 @@ void InstanceManager::clearCurrentInstance()
|
||||
{
|
||||
setCurrentInstance("");
|
||||
m_Reset = true;
|
||||
m_overrideInstance = false;
|
||||
}
|
||||
|
||||
void InstanceManager::setCurrentInstance(const QString &name)
|
||||
@@ -131,22 +132,34 @@ 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: \n"
|
||||
"(This is just the name of the Instance, not the game selection)"));
|
||||
// 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
|
||||
dialog.setComboBoxItems({ "NewName", "Fallout 4", "SkyrimSE", "Skyrim", "Fallout 3",
|
||||
"Fallout NV", "FO4VR", "Oblivion" });
|
||||
dialog.setComboBoxItems({ "NewName", "Fallout 4", "SkyrimSE", "Skyrim", "SkyrimVR", "Fallout 3",
|
||||
"Fallout NV", "TTW", "FO4VR", "Oblivion", "Morrowind" });
|
||||
dialog.setComboBoxEditable(true);
|
||||
|
||||
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 +309,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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user