Compare commits

..
15 Commits
Author SHA1 Message Date
isanae 1412befe1b Merge pull request #1198 from isanae/2_3_0
Remove RC
2020-08-17 01:48:22 -04:00
isanae e6e88074ea removed rc 2020-08-17 01:42:11 -04:00
isanae 2388f2471b Merge pull request #1195 from isanae/2_3_0
Cherry pick: die after dump
2020-08-13 14:48:35 -04:00
isanae 2c6c223cb0 bumped to 2.3.2rc2 2020-08-13 14:47:35 -04:00
isanae f16738ffd6 always call the previous terminate handler, which should abort
without it, execution just resumes and dumps are created endlessly
2020-08-13 14:46:47 -04:00
isanae f2dc4ddd30 Merge pull request #1189 from isanae/2_3_0
switched to 2.3.2-rc1
2020-08-12 06:23:19 -04:00
isanae 322b5d59f0 switched to 2.3.2-rc1 2020-08-12 06:22:28 -04:00
isanae 06d356e48f Merge pull request #1188 from isanae/2_3_0
bumped to 2.3.2
2020-08-12 04:26:19 -04:00
isanae 8db55c451c bumped to 2.3.2 2020-08-12 04:24:48 -04:00
isanae 768e6291b3 Merge pull request #1183 from AnyOldName3/cherry-pick-NexusBridgeFix
Cherry pick NexusBridge fix
2020-08-10 18:34:24 -04:00
AnyOldName3 2cdb7c5b13 Don't use reference as class member
This particular QString was only ever constructed from a temporary,
so it was literally never going to work. We only hadn't noticed this
earlier as no one had tried using the mod repository bridge from a
plugin before (which is fairly bad given that three people have
theoretically tested it while working on its Python bindings in the
past).
2020-08-08 14:18:14 +01:00
isanae b9f9e6af94 Merge pull request #1178 from isanae/2_3_0
Merge 2.3.1 changes
2020-08-01 11:33:35 -04:00
isanae b9078ffefd bump to 2.3.1 2020-08-01 11:29:09 -04:00
isanae 04c5986aa6 added startSafeThread() to get core dumps for threads other than the main thread
added terminate handler
2020-08-01 11:29:09 -04:00
isanae 1cb18b3c00 fixed warning when trying to get the file type of files without extensions 2020-08-01 11:29:09 -04:00
237 changed files with 14280 additions and 29948 deletions
@@ -1,27 +0,0 @@
---
name: Game support Request
about: Request support for a new game
title: Add support for game [GAME NAME]
labels: 'additional games support, Feature Request, area: mo2 game plugins'
assignees: ''
---
**This template is useful to add basic support using https://github.com/ModOrganizer2/modorganizer-basic_games.**
**If you are vaguely familiar with programming you can try following the instructions on that link to get something working yourself. If you have trouble with that please fill in this template.**
**Please provide the following information for the game (remove the optional lines you do not use):**
- **Name:** Name of the game
- **Short name:** Name of the game in Nexus URL (e.g. skyrimse for Skyrim SE).
- **Nexus ID [optional]:** ID of the game on Nexus (you can usually find this in Nexus URL).
- **Executable:** Name of the main executable for the game (relative to the game folder).
- **Launcher [optional]:** Name of the game launcher (relative to the game folder).
- **Data path:** Path to the data folder of the game (relative to the game folder).
- **Documents path:** Path to folder containing INI files, etc., for the game (usually under "My Games", or the game folder itself).
- **Saves directory [optional]:** Path to the folder containing save games (this default to the path above).
- **Save extension [optional]:** Extension of the saves
- **Steam ID [optional]:** ID of the game on Steam (if the game is on Steam).
**Provide additional details regarding the game that could be required for the plugin.**
+1 -1
View File
@@ -20,7 +20,7 @@ Steps to reproduce the behavior:
## Environment:
* Mod Organizer Version that exhibits the issue:
* Last Mod Organizer Version that did not exhibit the issue (if applicable):
* Last Mod Organizer Verison that did not exhibit the issue (if applicable):
* Desktop OS/version used to run Mod Organizer:
## Details:
+20 -28
View File
@@ -16,46 +16,42 @@ init:
environment:
WEBHOOK_URL:
secure: gOKbXaZM9ImtMD5XrYITvdyZUW/az082G9OIN1EC1VaKiI9iefpxhBavJ6Al6CzIZvQ+3pxnLqjmNgA7cDc22wcj2kB4hSG5qhbTI8wGa8jLQ5L65nuRZ3vrIqghBz9G3GLglgZkg6eqH9r3Kqc6UzcpCGzxxPOqm550nRcIiUU=
MO_VERSION: 2.4.0
VER_STUB_NORMAL: dev-appveyor-
MO_VERSION: 2.3.0
VER_STUB_NORMAL: dev-appveyor
VER_STUB_NIGHTLY: dev-nightly-
build_script:
- pwsh: >-
# Maintenance comments:
- cmd: >-
REM Maintenance comments:
# APPVEYOR_BUILD_FOLDER= "c:\projects\modorganizer-slug"
REM APPVEYOR_BUILD_FOLDER= "c:\projects\modorganizer-slug"
# -Need to update py3 version used to invoke unimake.py once in a while.
REM -Need to update py3 version used to invoke unimake.py once in a while.
# -Need update MO_VERSION env variable after each release.
REM -Need update MO_VERSION env variable after each release.
# -Always clones umbrella master
REM -Always clones umbrella master
# -Will checkout all the branches matching the one that triggered the build on the main repo.
REM -Will checkout all the branches matching the one that triggered the build on the main repo.
# End comments.
REM End comments.
$ErrorActionPreference = 'Stop'
git clone --depth=1 --no-single-branch https://github.com/ModOrganizer2/modorganizer-umbrella.git c:\projects\modorganizer-umbrella
git clone --depth=1 https://github.com/ModOrganizer2/modorganizer-umbrella.git c:\projects\modorganizer-umbrella 2> $null
mkdir %APPVEYOR_BUILD_FOLDER%\modorganizer-build -type directory
New-Item -ItemType Directory -Path ${env:APPVEYOR_BUILD_FOLDER}\modorganizer-build
cd c:\projects\modorganizer-umbrella
($env:APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH -eq $null) ? ($branch = $env:APPVEYOR_REPO_BRANCH) : ($branch = $env:APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH)
git checkout $(git show-ref --verify --quiet refs/remotes/origin/${branch} || echo '-b') ${branch}
C:\Python38-x64\python.exe unimake.py -d ${env:APPVEYOR_BUILD_FOLDER}\modorganizer-build -s Appveyor_Build=True -s Feature_Branch=${env:APPVEYOR_REPO_BRANCH} -s override_build_version=${env:APPVEYOR_BUILD_VERSION}
if($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode ) }
C:\Python38-x64\python.exe unimake.py -d %APPVEYOR_BUILD_FOLDER%\modorganizer-build -s Appveyor_Build=True -s Feature_Branch=%APPVEYOR_REPO_BRANCH% -s override_build_version=%APPVEYOR_BUILD_VERSION%
test: off
artifacts:
- path: '\modorganizer-build\install\bin\ModOrganizer.exe'
- path: '\modorganizer-build\install\bin'
name: Mod.Organizer-$(APPVEYOR_BUILD_VERSION)
- path: '\modorganizer-build\install\pdb\ModOrganizer.pdb'
name: PDB-Mod.Organizer-$(APPVEYOR_BUILD_VERSION)
- path: '\modorganizer-build\install\pdb'
name: PDBs-Mod.Organizer-$(APPVEYOR_BUILD_VERSION)
deploy: off
on_success:
- ps: >-
@@ -63,15 +59,11 @@ on_success:
Invoke-RestMethod https://raw.githubusercontent.com/DiscordHooks/appveyor-discord-webhook/master/send.ps1 -o send.ps1
if($env:APPVEYOR_SCHEDULED_BUILD -ne 'True'){
./send.ps1 success $env:WEBHOOK_URL
}
./send.ps1 success $env:WEBHOOK_URL
on_failure:
- ps: >-
Set-Location -Path $env:APPVEYOR_BUILD_FOLDER
Invoke-RestMethod https://raw.githubusercontent.com/DiscordHooks/appveyor-discord-webhook/master/send.ps1 -o send.ps1
if($env:APPVEYOR_SCHEDULED_BUILD -ne 'True'){
./send.ps1 failure $env:WEBHOOK_URL
}
./send.ps1 failure $env:WEBHOOK_URL
+1 -1
View File
@@ -1,2 +1,2 @@
pushd "%~dp0"
start ModOrganizer.exe crashdump
start ModOrganizer.exe --crashdump
-97
View File
@@ -8,102 +8,5 @@ file={m_wsFile}
loaded={m_loaded}
expanded={m_expanded}
}}</DisplayString></Type>
<Type Name="QFileInfoPrivate">
<DisplayString Condition="0 == this">&lt;null&gt;</DisplayString>
<DisplayString>{fileEntry}</DisplayString>
<StringView>fileEntry</StringView>
<Expand>
<Item Name="QSharedData">*((Qt5Core.dll!QSharedData *) this)</Item>
<Item Name="fileEntry">fileEntry</Item>
<!--
<Item Name="metaData">metaData</Item>
<Item Name="fileListsInitialized">fileListsInitialized</Item>
<Item Name="fileEngine">fileEngine</Item>
<Item Name="fileNames">fileNames</Item>
<Item Name="fileOwners">fileOwners</Item>
<Item Name="cachedFlags">cachedFlags</Item>
<Item Name="isDefaultConstructed">isDefaultConstructed</Item>
<Item Name="cache_enabled">cache_enabled</Item>
<Item Name="fileFlags">fileFlags</Item>
<Item Name="fileSize">fileSize</Item>
<Item Name="fileTimes">fileTimes</Item>
-->
</Expand>
</Type>
<Type Name="QFileInfo">
<DisplayString>{*((Qt5Core.dll!QFileInfoPrivate *) d_ptr.d)}</DisplayString>
<StringView>*((Qt5Core.dll!QFileInfoPrivate *) d_ptr.d)</StringView>
<Expand>
<Item Name="QFileInfoPrivate">*((Qt5Core.dll!QFileInfoPrivate *) d_ptr.d)</Item>
</Expand>
</Type>
<Type Name="QFileSystemEntry">
<DisplayString Condition="0 == this">&lt;null&gt;</DisplayString>
<DisplayString>{m_filePath}</DisplayString>
<StringView>m_filePath</StringView>
<!--
<Expand>
<Item Name="m_filePath">m_filePath</Item>
<Item Name="m_nativeFilePath">m_nativeFilePath</Item>
<Item Name="m_lastSeparator">m_lastSeparator</Item>
<Item Name="m_firstDotInFileName">m_firstDotInFileName</Item>
<Item Name="m_lastDotInFileName">m_lastDotInFileName</Item>
</Expand>
-->
</Type>
<Type Name="QDirPrivate">
<DisplayString Condition="0 == this">&lt;null&gt;</DisplayString>
<DisplayString>{dirEntry}</DisplayString>
<StringView>dirEntry</StringView>
<Expand>
<Item Name="QSharedData">*((Qt5Core.dll!QSharedData *) this)</Item>
<Item Name="dirEntry">dirEntry</Item>
<Item Name="nameFilters">nameFilters</Item>
<Item Name="absoluteDirEntry">absoluteDirEntry</Item>
<!--
<Item Name="metaData">metaData</Item>
<Item Name="fileListsInitialized">fileListsInitialized</Item>
<Item Name="fileEngine">fileEngine</Item>
<Item Name="files">files</Item>
<Item Name="fileInfos">fileInfos</Item>
<Item Name="sort">sort</Item>
<Item Name="filters">filters</Item>
-->
</Expand>
</Type>
<Type Name="QDir">
<DisplayString>{*((Qt5Core.dll!QDirPrivate *) d_ptr.d)}</DisplayString>
<StringView>*((Qt5Core.dll!QDirPrivate *) d_ptr.d)</StringView>
<Expand>
<Item Name="QDirPrivate">*((Qt5Core.dll!QDirPrivate *) d_ptr.d)</Item>
</Expand>
</Type>
<Type Name="QFilePrivate">
<DisplayString Condition="0 == this">&lt;null&gt;</DisplayString>
<DisplayString>{fileName}</DisplayString>
<StringView>fileName</StringView>
<Expand>
<Item Name="QFileDevice">*((Qt5Core.dll!QFileDevice *) this)</Item>
<Item Name="fileName">fileName</Item>
</Expand>
</Type>
<Type Name="QFile">
<DisplayString>{*((Qt5Core.dll!QFilePrivate *) d_ptr.d)}</DisplayString>
<StringView>*((Qt5Core.dll!QFilePrivate *) d_ptr.d)</StringView>
<Expand>
<Item Name="QFilePrivate">*((Qt5Core.dll!QFilePrivate *) d_ptr.d)</Item>
</Expand>
</Type>
</AutoVisualizer>
+7 -11
View File
@@ -12,17 +12,17 @@ The project took up speed again after a few more coders showed up in late 2017,
## Help Wanted!
Mod Organizer 2 is an open project in the hands of the community, there are problems that need to be solved and things that could be added. MO2 really needs developers and if you have the programming skills and some free time you can really improve the experience of the modding community.
To have more information, please join the open MO2 Development discord server: [Mod Organizer 2](https://discord.gg/vD2ZbfX)
To have more information, please join the open MO2 Development discord server :* [ModOrganizerDevs](https://discord.gg/vD2ZbfX)
If you want to help translate MO2 to your language you should join the discord server too and head to the #translation channel.
To setup a development environment on your machine, there is the [mob project](https://github.com/modorganizer2/mob) that handles that.
If you want to submit your code changes, please use a good formatting style like the default one in Visual Studio.
To setup a development environment on your machine, there is the [umbrella project](https://github.com/Modorganizer2/modorganizer-umbrella) that handles that.
If you want to submit your code changes, please use a good formating style like the default one in Visual Studio.
Through the work of a few people of the community MO2 has come quite far, now it needs some more of those people to go further.
## Reporting Issues:
Issues should be reported to the GitHub page or on the open discord server: [Mod Organizer 2](https://discord.gg/vD2ZbfX). Here is also where dev builds are tested, bugs are reported and investigated, suggestions are discussed and a lot more.
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, LostDragonist, AnyOldName3, isa, Holt59 and many others for the development.
Credits to Tannin, LePresidente, Silarn, erasmux, AL12, LostDragonist, AnyOldName3 and many others for the development.
## Download Location
@@ -35,11 +35,11 @@ Credits to Tannin, LePresidente, Silarn, erasmux, AL12, LostDragonist, AnyOldNam
## Building
Please refer to [Modorganizer2/mob](https://github.com/modorganizer2/mob) for build instructions.
Please refer to [Modorganizer2/modorganizer-umbrella](https://github.com/Modorganizer2/modorganizer-umbrella) for build instructions.
## Other Repositories
MO2 consists of multiple repositories on github. The mob project will download them automatically as required. They should however also be buildable individually.
MO2 consists of multiple repositories on github. The Umbrella project will download them automatically as required. They should however also be buildable individually.
Here is a complete list:
* https://github.com/LePresidente/cpython-1
@@ -47,7 +47,6 @@ Here is a complete list:
* https://github.com/ModOrganizer2/githubpp
* https://github.com/ModOrganizer2/modorganizer
* https://github.com/ModOrganizer2/modorganizer-archive
* https://github.com/ModOrganizer2/modorganizer-basic_games
* https://github.com/ModOrganizer2/modorganizer-bsatk
* https://github.com/ModOrganizer2/modorganizer-bsa_extractor
* https://github.com/ModOrganizer2/modorganizer-check_fnis
@@ -69,13 +68,10 @@ Here is a complete list:
* 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_wizard
* https://github.com/ModOrganizer2/modorganizer-installer_bundle
* https://github.com/ModOrganizer2/modorganizer-installer_fomod
* https://github.com/ModOrganizer2/modorganizer-installer_fomod_csharp
* https://github.com/ModOrganizer2/modorganizer-installer_manual
* https://github.com/ModOrganizer2/modorganizer-installer_ncc
* https://github.com/ModOrganizer2/modorganizer-installer_omod
* https://github.com/ModOrganizer2/modorganizer-installer_quick
* https://github.com/ModOrganizer2/modorganizer-lootcli
* https://github.com/ModOrganizer2/modorganizer-NCC
+20 -52
View File
@@ -11,14 +11,12 @@ endif()
add_filter(NAME src/application GROUPS
iuserinterface
commandline
main
moapplication
moshortcut
multiprocess
sanitychecks
selfupdater
updatedialog
singleinstance
)
add_filter(NAME src/browser GROUPS
@@ -30,10 +28,12 @@ add_filter(NAME src/core GROUPS
categories
archivefiletree
installationmanager
instancemanager
loadmechanism
nexusinterface
nxmaccessmanager
organizercore
plugincontainer
organizerproxy
apiuseraccount
processrunner
qdirfiletree
@@ -63,13 +63,13 @@ add_filter(NAME src/dialogs GROUPS
add_filter(NAME src/downloads GROUPS
downloadlist
downloadlistview
downloadlistsortproxy
downloadlistwidget
downloadmanager
)
add_filter(NAME src/env GROUPS
env
envdump
envfs
envmetrics
envmodule
@@ -84,13 +84,6 @@ add_filter(NAME src/executables GROUPS
editexecutablesdialog
)
add_filter(NAME src/instances GROUPS
createinstancedialog
createinstancedialogpages
instancemanager
instancemanagerdialog
)
add_filter(NAME src/loot GROUPS
loot
lootdialog
@@ -98,13 +91,12 @@ add_filter(NAME src/loot GROUPS
add_filter(NAME src/mainwindow GROUPS
datatab
downloadstab
iconfetcher
filetree
filetreeitem
filetreemodel
filterlist
mainwindow
savestab
statusbar
)
@@ -131,34 +123,17 @@ add_filter(NAME src/modinfo/dialog GROUPS
modinfodialogtab
modinfodialogtextfiles
)
add_filter(NAME src/modinfo/dialog/widgets GROUPS
modidlineedit
)
add_filter(NAME src/modlist GROUPS
modlist
modlistdropinfo
modlistsortproxy
modlistbypriorityproxy
)
add_filter(NAME src/modlist/view GROUPS
filterlist
modlistview
modlistviewactions
modlistcontextmenu
modflagicondelegate
modcontenticondelegate
modconflicticondelegate
modlistversiondelegate
)
add_filter(NAME src/plugins GROUPS
plugincontainer
pluginlist
pluginlistsortproxy
pluginlistview
pluginlistcontextmenu
)
add_filter(NAME src/previews GROUPS
@@ -172,14 +147,6 @@ add_filter(NAME src/profiles GROUPS
profilesdialog
)
add_filter(NAME src/proxies GROUPS
downloadmanagerproxy
modlistproxy
organizerproxy
pluginlistproxy
proxyutils
)
add_filter(NAME src/register GROUPS
shared/directoryentry
shared/fileentry
@@ -202,25 +169,25 @@ add_filter(NAME src/settingsdialog GROUPS
settingsdialognexus
settingsdialogpaths
settingsdialogplugins
settingsdialogsteam
settingsdialogworkarounds
settingsdialogmodlist
settingsdialogtheme
disableproxyplugindialog
)
add_filter(NAME src/utilities GROUPS
shared/appconfig
bbcode
csvbuilder
shared/error_report
shared/leaktrace
persistentcookiejar
serverinfo
spawn
shared/stackdata
shared/util
usvfsconnector
shared/windows_error
thread_utils
json
glob_matching
)
add_filter(NAME src/widgets GROUPS
@@ -231,12 +198,13 @@ add_filter(NAME src/widgets GROUPS
lcdnumber
loglist
loghighlighter
modflagicondelegate
modconflicticondelegate
modidlineedit
noeditdelegate
qtgroupingproxy
texteditor
viewmarkingscrollbar
modelutils
copyeventfilter
)
@@ -247,17 +215,17 @@ target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE
)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/dlls.manifest.qt5"
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dlls.manifest.qt5
DESTINATION bin/dlls
RENAME dlls.manifest)
install(FILES ${qm_files} DESTINATION bin/translations)
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/stylesheets"
"${CMAKE_CURRENT_SOURCE_DIR}/tutorials"
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/stylesheets
${CMAKE_CURRENT_SOURCE_DIR}/tutorials
DESTINATION bin)
deploy_qt(BINARIES ModOrganizer.exe uibase.dll plugins/bsa_packer.dll)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../qdds.dll" DESTINATION bin/dlls/imageformats)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/resources/markdown.html" DESTINATION bin/resources)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../qdds.dll DESTINATION bin/dlls/imageformats)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/markdown.html DESTINATION bin/resources)
+1 -1
View File
@@ -120,5 +120,5 @@ void AboutDialog::on_creditsList_currentItemChanged(QListWidgetItem *current, QL
void AboutDialog::on_sourceText_linkActivated(const QString &link)
{
MOBase::shell::Open(QUrl(link));
emit linkClicked(link);
}
+4
View File
@@ -40,6 +40,10 @@ public:
explicit AboutDialog(const QString &version, QWidget *parent = 0);
~AboutDialog();
signals:
void linkClicked(QString link);
private:
enum Licenses {
+22 -52
View File
@@ -220,11 +220,6 @@
<string notr="true">isa</string>
</property>
</item>
<item>
<property name="text">
<string>Holt59</string>
</property>
</item>
</widget>
</item>
</layout>
@@ -261,6 +256,11 @@
<string notr="true">przester</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Holt59</string>
</property>
</item>
</widget>
</item>
</layout>
@@ -429,36 +429,11 @@
<string>Tannin (Original Creator)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">6788</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">blacksol</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">BlueAmulet</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Bridger</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Brixified</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">deathneko11</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">DoubleYou</string>
@@ -469,6 +444,21 @@
<string notr="true">Drew Warwick</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">deathneko11</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Bridger</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Brixified</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">GamerPoet</string>
@@ -489,11 +479,6 @@
<string notr="true">GSDFan</string>
</property>
</item>
<item>
<property name="text">
<string>Luca|EzioTheDeadPoet</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">ogrotten</string>
@@ -504,21 +489,11 @@
<string notr="true">outdatedtv</string>
</property>
</item>
<item>
<property name="text">
<string>Patchier</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">PurpleFez</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Qudix</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">reedts</string>
@@ -534,11 +509,6 @@
<string notr="true">SuperSandro2000</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Trosski</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Uhuru</string>
@@ -551,12 +521,12 @@
</item>
<item>
<property name="text">
<string notr="true">thosrtanner</string>
<string notr="true">z929669</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">z929669</string>
<string notr="true">thosrtanner</string>
</property>
</item>
</widget>
+2 -16
View File
@@ -282,23 +282,9 @@ bool CategoryFactory::categoryExists(int id) const
}
bool CategoryFactory::isDescendantOf(int id, int parentID) const
bool CategoryFactory::isDecendantOf(int id, int parentID) const
{
// handles cycles
std::set<int> seen;
return isDescendantOfImpl(id, parentID, seen);
}
bool CategoryFactory::isDescendantOfImpl(
int id, int parentID, std::set<int>& seen) const
{
if (!seen.insert(id).second) {
log::error("cycle in category: {}", id);
return false;
}
std::map<int, unsigned int>::const_iterator iter = m_IDMap.find(id);
if (iter != m_IDMap.end()) {
unsigned int index = iter->second;
if (m_Categories[index].m_ParentID == 0) {
@@ -306,7 +292,7 @@ bool CategoryFactory::isDescendantOfImpl(
} else if (m_Categories[index].m_ParentID == parentID) {
return true;
} else {
return isDescendantOfImpl(m_Categories[index].m_ParentID, parentID, seen);
return isDecendantOf(m_Categories[index].m_ParentID, parentID);
}
} else {
log::warn("{} is no valid category id", id);
+2 -3
View File
@@ -124,7 +124,7 @@ public:
* @param parentID the parent id to test for
* @return true if id is a child of parentID
**/
bool isDescendantOf(int id, int parentID) const;
bool isDecendantOf(int id, int parentID) const;
/**
* @brief test if the specified category has child categories
@@ -209,8 +209,7 @@ private:
std::map<int, unsigned int> m_NexusMap;
private:
// called by isDescendantOf()
bool isDescendantOfImpl(int id, int parentID, std::set<int>& seen) const;
};
-931
View File
File diff suppressed because it is too large Load Diff
-379
View File
@@ -1,379 +0,0 @@
#ifndef MODORGANIZER_COMMANDLINE_INCLUDED
#define MODORGANIZER_COMMANDLINE_INCLUDED
#include "moshortcut.h"
#include <vector>
#include <memory>
class OrganizerCore;
class MOApplication;
class MOMultiProcess;
namespace cl
{
namespace po = boost::program_options;
// base class for all commands
//
class Command
{
public:
virtual ~Command() = default;
// command name, used on the command line to invoke it; this is meta().name
//
std::string name() const;
// command short description, shown in general help; this is
// meta().description
//
std::string description() const;
// usage line, puts together the name and whatever meta().usage is
//
std::string usageLine() const;
// shown after the usage line; this is meta().more
//
std::string moreInfo() const;
// returns all options for this command, including hidden ones; used to parse
// the command line
//
po::options_description allOptions() const;
// returns visible options, used to display usage
//
po::options_description visibleOptions() const;
// returns positional arguments
//
po::positional_options_description positional() const;
// when this returns true, the command line is not parsed at all and doRun()
// is expected to use untouched()
//
virtual bool legacy() const;
// remembers the given values
//
void set(
const std::wstring& originalLine,
po::variables_map vm,
std::vector<std::wstring> untouched);
// called as soon as the command line has been parsed; return something to
// exit immediately
//
virtual std::optional<int> runEarly();
// called as soon as the MOApplication has been created, which is also the
// first time where Qt stuff is available
//
virtual std::optional<int> runPostApplication(MOApplication& a);
// called as soon as the multi process checks have confirmed that this is
// a primary instance; return something to exit immediately
//
virtual std::optional<int> runPostMultiProcess(MOMultiProcess& mp);
// called after the OrganizerCore has been initialized; return something to
// exit immediatley
//
virtual std::optional<int> runPostOrganizer(OrganizerCore& core);
// whether this command can be forwarded to the primary instance if one is
// already running
//
// if an instance is already running and this returns true, the whole command
// line is sent as a message to the primary instance, which will construct a
// new CommandLine and call runPostOrganizer() with it
//
// if an instance is already running and this returns false, the "an instance
// is already running" error dialog will be shown
//
// if this is the primary instance, this function is not called
//
virtual bool canForwardToPrimary() const;
protected:
// meta information about this command, returned by derived classes
//
struct Meta
{
std::string name, description, usage, more;
Meta(
std::string name, std::string description,
std::string usage, std::string more);
};
// meta
//
virtual Meta meta() const = 0;
// returns visible options specific to this command
//
virtual po::options_description getVisibleOptions() const;
// returns hidden options specific to this command
//
virtual po::options_description getInternalOptions() const;
// returns positional arguments specific to this command
//
virtual po::positional_options_description getPositional() const;
// returns the original command line
//
const std::wstring& originalCmd() const;
// variables
//
const po::variables_map& vm() const;
// returns unparsed options, only used by launch
//
const std::vector<std::wstring>& untouched() const;
private:
std::wstring m_original;
po::variables_map m_vm;
std::vector<std::wstring> m_untouched;
};
// generates a crash dump for another MO process
//
class CrashDumpCommand : public Command
{
protected:
po::options_description getVisibleOptions() const override;
Meta meta() const override;
std::optional<int> runEarly() override;
};
// this is the `launch` command used when starting a process from within the
// virtualized directory, see processrunner.cpp
//
// it has its own parsing of the command line to extract the argument after
// `launch` and use it as the cwd of the process, but pass the remaining
// arguments verbatim
//
// this is very old code that should probably never be changed
//
// note that it's actually buggy; in particular, it doesn't handle multiple
// whitespace between arguments
//
class LaunchCommand : public Command
{
public:
bool legacy() const override;
protected:
Meta meta() const override;
std::optional<int> runEarly() override;
int SpawnWaitProcess(LPCWSTR workingDirectory, LPCWSTR commandLine);
LPCWSTR UntouchedCommandLineArguments(
int parseArgCount, std::vector<std::wstring>& parsedArgs);
};
// runs a program or an executable
//
class RunCommand : public Command
{
protected:
Meta meta() const override;
po::options_description getVisibleOptions() const override;
po::options_description getInternalOptions() const override;
po::positional_options_description getPositional() const override;
bool canForwardToPrimary() const override;
std::optional<int> runPostOrganizer(OrganizerCore& core) override;
};
// reloads the given plugin
//
class ReloadPluginCommand : public Command
{
protected:
Meta meta() const override;
po::options_description getInternalOptions() const override;
po::positional_options_description getPositional() const override;
bool canForwardToPrimary() const override;
std::optional<int> runPostOrganizer(OrganizerCore& core) override;
};
// refreshes mo
//
class RefreshCommand : public Command
{
protected:
Meta meta() const override;
bool canForwardToPrimary() const override;
std::optional<int> runPostOrganizer(OrganizerCore& core) override;
};
// parses the command line and runs any given command
//
// the command line used to support a few commands but with no real conventions;
// those are mostly preserved for backwards compatibility, but deprecated:
//
// - moshortcut:// for desktop/taskbar shortcuts, may contain an instance name
// and a configured executable or arbitrary binary (still used in MO for
// shortcuts)
//
// - nxm:// links
//
// - the name of a configured executable or path to binary, followed by
// arbitrary parameters, forwarded to the program
//
// any command added CommandLine will unfortunately break any executable with
// the same name: `ModOrganizer.exe run` used to launch a program named "run"
// but will now execute the command "run"
//
// if moshortcut:// is detected and has an instance, it will override -i if both
// are given
//
//
// the command is used in two phases:
//
// 1) run() is called in main() shortly after startup; it parses the command
// line and runs the given command, if any
//
// 2) if the command did not request to exit, the instance is loaded
// in main() et al. and setupCore() is called; it handles moshortcut,
// nxm links and starting executables/binaries
//
// either can return an exit code, which will make MO exit immediately
//
class CommandLine
{
public:
CommandLine();
// parses the given command line and calls runEarly() on the appropriate
// command, if any
//
// returns an empty optional if execution should continue, or a return code
// if MO must quit
//
std::optional<int> process(const std::wstring& line);
// called as soon as the MOApplication has been created; this handles a few
// global actions and forwards to the command, if any
//
std::optional<int> runPostApplication(MOApplication& a);
// calls Command::runPostMultiProcess() on the command, if any
//
std::optional<int> runPostMultiProcess(MOMultiProcess& mp);
// calls Command::runPostOrganizer() on the command, if any
//
// if MO wasn't invoked with a valid command, this also handles moshortcut,
// nxm links and starting processes
//
std::optional<int> runPostOrganizer(OrganizerCore& core);
// called when this instance is not the primary one
//
// if a command was executed and the command returns true for
// canForwardToPrimary(), this forwards the command line as an external
// message and returns true
//
// if the command returns false for canForwardToPrimary(), returns false
//
// if there was no valid command on the command line, this also forwards
// moshortcut and nxm links
//
// if there was no command, moshortcut or nxm links, this returns false, which
// will end up displaying an error message about an instance already running
//
bool forwardToPrimary(MOMultiProcess& multiProcess);
// clears parsed options, used when MO is "restarted" so the options aren't
// processed again
//
void clear();
// global usage string plus usage for the given command, if any
//
std::string usage(const Command* c=nullptr) const;
// whether --pick was given
//
bool pick() const;
// whether --multiple was given
//
bool multiple() const;
// profile override (-p)
//
std::optional<QString> profile() const;
// instance override (-i)
//
std::optional<QString> instance() const;
// returns the data parsed from an moshortcut:// option, if any
//
const MOShortcut& shortcut() const;
// returns the nxm:// link, if any
//
std::optional<QString> nxmLink() const;
// returns the executable/binary, if any
//
std::optional<QString> executable() const;
// returns the list of arguments, excluding moshortcut or executable name;
// deprecated, only use with executable()
//
const QStringList& untouched() const;
private:
po::options_description m_visibleOptions, m_allOptions;
po::positional_options_description m_positional;
std::vector<std::unique_ptr<Command>> m_commands;
po::variables_map m_vm;
MOShortcut m_shortcut;
std::optional<QString> m_nxmLink;
std::optional<QString> m_executable;
QStringList m_untouched;
Command* m_command;
void createOptions();
std::string more() const;
template <class... Ts>
void add()
{
(m_commands.push_back(std::make_unique<Ts>()), ...);
}
std::optional<int> runEarly();
};
} // namespace
#endif // MODORGANIZER_COMMANDLINE_INCLUDED
-51
View File
@@ -1,51 +0,0 @@
#include "copyeventfilter.h"
#include <QClipboard>
#include <QGuiApplication>
#include <QKeyEvent>
CopyEventFilter::CopyEventFilter(QAbstractItemView* view, int column, int role) :
CopyEventFilter(view, [=](auto& index) { return index.sibling(index.row(), column).data(role).toString(); })
{
}
CopyEventFilter::CopyEventFilter(
QAbstractItemView* view, std::function<QString(const QModelIndex&)> format) :
QObject(view), m_view(view), m_format(format)
{
}
void CopyEventFilter::copySelection() const
{
if (!m_view->selectionModel()->hasSelection()) {
return;
}
// sort to reflect the visual order
QModelIndexList selectedRows = m_view->selectionModel()->selectedRows();
std::sort(selectedRows.begin(), selectedRows.end(), [=](const auto& lidx, const auto& ridx) {
return m_view->visualRect(lidx).top() < m_view->visualRect(ridx).top();
});
QStringList rows;
for (auto& idx : selectedRows) {
rows.append(m_format(idx));
}
QGuiApplication::clipboard()->setText(rows.join("\n"));
}
bool CopyEventFilter::eventFilter(QObject* sender, QEvent* event)
{
if (sender == m_view && event->type() == QEvent::KeyPress) {
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->modifiers() == Qt::ControlModifier
&& keyEvent->key() == Qt::Key_C) {
copySelection();
return true;
}
}
return QObject::eventFilter(sender, event);
}
-43
View File
@@ -1,43 +0,0 @@
#ifndef COPY_EVENT_FILTER_H
#define COPY_EVENT_FILTER_H
#include <functional>
#include <QAbstractItemView>
#include <QModelIndex>
#include <QObject>
// this small class provides copy on Ctrl+C and also
// exposes a method to actual copy the selection
//
// the way the selection is copied can be customized by
// passing a functor to format each index, by default
// it only extracts the display role
//
// only works for view that selects whole row since it only
// considers the first cell in each row
//
class CopyEventFilter : public QObject
{
Q_OBJECT
public:
CopyEventFilter(QAbstractItemView* view, int column = 0, int role = Qt::DisplayRole);
CopyEventFilter(QAbstractItemView* view, std::function<QString(const QModelIndex&)> format);
// copy the selection of the view associated with this
// event filter into the clipboard
//
void copySelection() const;
bool eventFilter(QObject* sender, QEvent* event) override;
private:
QAbstractItemView* m_view;
std::function<QString(const QModelIndex&)> m_format;
};
#endif
File diff suppressed because it is too large Load Diff
-222
View File
@@ -1,222 +0,0 @@
#ifndef MODORGANIZER_CREATEINSTANCEDIALOG_INCLUDED
#define MODORGANIZER_CREATEINSTANCEDIALOG_INCLUDED
#include <QDialog>
namespace MOBase { class IPluginGame; }
namespace Ui { class CreateInstanceDialog; };
namespace cid { class Page; }
class PluginContainer;
class Settings;
// this is a wizard for creating a new instance, it is made out of Page objects,
// see createinstancedialogpages.h
//
// each page can give back one or more pieces of information that is collected
// in creationInfo() and used by finish() to do the actual creation
//
// pages can be disabled if they return true in skip(), which happens globally
// for some (IntroPage has a setting in the registry), depending on context
// (NexusPage is skipped if the API key already exists) or explicitly (when
// only some info about the instance is missing on startup, such as a game
// variant)
//
class CreateInstanceDialog : public QDialog
{
Q_OBJECT
public:
enum class Actions
{
Find = 1
};
// instance type
//
enum Types
{
NoType = 0,
Global,
Portable
};
// all the paths required by the instance, some may be empty, such as
// basically all of them except for `base` when the user doesn't use the
// "Advanced" part of the paths page
//
struct Paths
{
QString base;
QString downloads;
QString mods;
QString profiles;
QString overwrite;
QString ini;
auto operator<=>(const Paths&) const = default;
};
// all the info filled in the various pages
//
struct CreationInfo
{
Types type;
MOBase::IPluginGame* game;
QString gameLocation;
QString gameVariant;
QString instanceName;
QString dataPath;
QString iniPath;
Paths paths;
};
CreateInstanceDialog(
const PluginContainer& pc, Settings* s, QWidget *parent = nullptr);
~CreateInstanceDialog();
Ui::CreateInstanceDialog* getUI();
const PluginContainer& pluginContainer();
Settings* settings();
// disables all the pages except for the given one, used on startup when some
// specific info is missing
template <class Page>
void setSinglePage(const QString& instanceName)
{
for (auto&& p : m_pages) {
if (auto* tp=dynamic_cast<Page*>(p.get())) {
tp->setSkip(false);
} else {
p->setSkip(true);
}
}
setSinglePageImpl(instanceName);
}
// returns the page having the give path, or null
//
template <class Page>
Page* getPage()
{
for (auto&& p : m_pages) {
if (auto* tp=dynamic_cast<Page*>(p.get())) {
return tp;
}
}
return nullptr;
}
// moves to the next page; if `allowFinish` is true, calls finish() if
// currently on the last page
//
void next(bool allowFinish=true);
// moves to the previous page, if any
//
void back();
// whether the current page reports that it is ready; if this is the last
// page, next() would call finish()
//
bool canNext() const;
// whether the current page is not the first one and there is an enabled page
// prior
//
bool canBack() const;
// selects the given page by index; this doesn't check if the page should be
// skipped
//
void selectPage(std::size_t i);
// moves by `d` pages, can be negative to move back
//
void changePage(int d);
// creates the instance and closes the dialog
//
void finish();
// updates the navigation buttons based on the current page
//
void updateNavigation();
// whether this is the last enabled page
//
bool isOnLastPage() const;
// returns whether the user has requested to switch to the new instance
//
bool switching() const;
// gathers the info from all the pages as it appears, paths are not fixed;
// see creationInfo()
//
CreationInfo rawCreationInfo() const;
// gathers the info from all the pages: paths are converted to absolute and
// the base dir variable is expanded everywhere; see rawCreationInfo()
//
CreationInfo creationInfo() const;
private:
std::unique_ptr<Ui::CreateInstanceDialog> ui;
const PluginContainer& m_pc;
Settings* m_settings;
std::vector<std::unique_ptr<cid::Page>> m_pages;
QString m_originalNext;
bool m_switching;
bool m_singlePage;
// creates a shortcut for the given sequence
//
void addShortcut(QKeySequence seq, std::function<void ()> f);
// creates a shortcut for the given sequence and executes the action when
// activated
//
void addShortcutAction(QKeySequence seq, Actions a);
// calls action() with the given action on the selected page, if any
//
void doAction(Actions a);
// called from setSinglePage(), does whatever doesn't need the T
//
void setSinglePageImpl(const QString& instanceName);
// adds a line to the creation log
//
void logCreation(const QString& s);
void logCreation(const std::wstring& s);
// calls the given member function on all pages until one returns an object
// that's not empty; used by gatherInfo()
//
template <class MF, class... Args>
auto getSelected(MF mf, Args&&... args) const
{
// return type
using T = decltype((std::declval<cid::Page>().*mf)(std::forward<Args>(args)...));
for (auto&& p : m_pages) {
const auto t = (p.get()->*mf)(std::forward<Args>(args)...);
if (t != T()) {
return t;
}
}
return T();
}
};
#endif // MODORGANIZER_CREATEINSTANCEDIALOG_INCLUDED
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More