Compare commits

..
239 Commits
Author SHA1 Message Date
LostDragonist e2b799bd6b Update translation file 2018-12-20 15:56:54 -06:00
LostDragonist 185eb8e5ef Merge branch 'Develop' 2018-12-20 15:34:11 -06:00
LostDragonist 63efd21a6a Fix version reporting to allow non-alpha builds 2018-12-20 15:33:01 -06:00
LostDragonist ed67ac2113 Merge pull request #586 from ModOrganizer2/Develop
Release 2.1.6
2018-12-20 14:33:08 -06:00
Al12rs 9a33dc1480 *Added "Open INIs Folder" option.
*Changed "Open Instance Folder" to open the Appdata or MO2 install instead of the baseDirectory.
2018-12-20 19:12:11 +01:00
LostDragonist 1b0c437788 Update translation file 2018-12-19 14:33:04 -06:00
LostDragonist 5e530becc2 Don't mention save games when dealing with INI files 2018-12-19 13:02:15 -06:00
LostDragonist d9835cc4ae Update translation file 2018-12-19 12:47:33 -06:00
LostDragonist 18ea79c2d0 Update translation file 2018-12-19 11:53:53 -06:00
LostDragonist 37a6989ba8 Make language about profile-specific settings and save games consistent 2018-12-19 11:53:29 -06:00
LostDragonist 830b63c4e2 Re-initialize the profile configuration if INI files are missing 2018-12-19 11:43:15 -06:00
LostDragonist 662772c2fc Optionally delete and restore profile-specific game INI files when changing the setting 2018-12-19 11:19:03 -06:00
LostDragonist 027edcf688 Enable per-profile game INI files by default again 2018-12-19 11:03:24 -06:00
Al12rs ff51aa10c2 Fixed performance issue of Data tab. 2018-12-18 00:12:28 +01:00
LostDragonist cbc9d00584 Update translation file 2018-12-15 16:23:20 -06:00
Al12rs e15f768a15 Fixed opening multiple modinfodialog from Open Origin info. 2018-12-13 21:18:35 +01:00
LostDragonist e63eba2ca1 Improve cleanup of temporary files when installing 2018-12-13 13:30:04 -06:00
LostDragonist 20008e17b7 Fix highlighting plugins when selecting mods with no visible priority 2018-12-12 17:43:43 -06:00
LostDragonist c24200bc04 Remove a weird vertical spacer from the diagnostics settings tab 2018-12-12 13:22:17 -06:00
LostDragonist 25a9290cd5 Reset previousSeparatorColor when a separator color is reset 2018-12-12 09:40:25 -06:00
Al12rs efe657c23e Removed old styles 2018-12-12 16:30:04 +01:00
LePresidente 571347d2de Pass DIR parameter to install exe, so installation directory matches current directory. 2018-12-12 16:01:50 +02:00
Al12rs 346bc630f8 Create new Separators in last used color. 2018-12-12 10:37:10 +01:00
LostDragonist 013890f644 Remember the last separator color used 2018-12-12 03:04:23 -06:00
LostDragonist 3559364473 Update translation file 2018-12-12 02:46:51 -06:00
LostDragonist 92cdf41243 Update Skyrim theme by chintsu_kun to v2.1.0 2018-12-11 20:48:16 -06:00
LostDragonist 789e95ca58 Update VS2015 Themes by chintsu_kun to v2.0.2 2018-12-11 20:47:29 -06:00
LostDragonist 9b9a1f435e Add v1.1 Paper Automata theme by 6788 2018-12-11 20:37:59 -06:00
LostDragonist 7f82ffa664 Add v4.3 Paper Light and Paper Dark themes by 6788 2018-12-11 20:37:36 -06:00
LostDragonist 68a1afed49 Implement separator text color in a way that doesn't break everything else 2018-12-11 20:31:17 -06:00
LostDragonist 7b1ece5f28 Further extend the version field to 32 characters 2018-12-11 18:31:09 -06:00
LostDragonist 2306e006dc Remove the requirement for a game launcher to be present 2018-12-11 15:45:29 -06:00
LostDragonist f6cd53e932 Change color of separator text based on the configured color of the separator 2018-12-11 15:24:25 -06:00
LostDragonist 5335188e63 Add option to remove column colors for mod list separators 2018-12-11 14:47:50 -06:00
LostDragonist dac716bb86 Allow tool plugins to define a submenu with the display name
Setting the display name to "<submenu>/<displayname>" will group plugins under the submenu.
2018-12-11 14:15:37 -06:00
Al12rs c486220d20 Updated translations and removed an excessive separator from previous commit. 2018-12-11 16:33:39 +01:00
Al12rs 0af33ccddf Added "Open Origin in Explorer" and "Open Origin Info..." options to ESPList context menu. 2018-12-11 16:26:41 +01:00
Al12rs 413c045383 * Fixed order of data tab to be Folders first.
* Remember expanded folders across refreshes.
2018-12-11 14:57:03 +01:00
LostDragonist 1266e13921 Add the ability to change the managed game directory 2018-12-11 01:52:53 -06:00
LostDragonist f4af3264f0 Sort tools menu to provide consistent results 2018-12-11 00:25:18 -06:00
Al12rs f61236e4cf Added UI locking while loadbar is active (for refresh of modlist). 2018-12-10 20:53:45 +01:00
LostDragonist d7e6fd1dd6 Don't disable ESMs when disabling mods if alternatives are available 2018-12-08 20:23:45 -06:00
LostDragonist 9d9dbd9f7e Add shortcut to select name filters on mod list and plugin list 2018-12-08 14:46:42 -06:00
LostDragonist 93763a9364 Add workaround setting to prevent the GUI from locking when running an executable 2018-12-08 11:15:16 -06:00
LostDragonist a94977988b Move the mod info separator flag to the end as it's hidden 2018-12-08 10:44:46 -06:00
LostDragonist c501b5cca0 Add notes column to mod list 2018-12-08 10:44:46 -06:00
Al12rs c87d97de8c Added missing games to the suggested names list.
Imroved dialog description.
2018-12-08 15:01:01 +01:00
LostDragonist 4914fd172d Add workarounds button to reset window geometries 2018-12-08 01:19:37 -06:00
LostDragonist 02fe0d3384 Improve refresh of data when changing profile settings 2018-12-07 23:44:31 -06:00
LostDragonist e76891b926 Update translation file 2018-12-06 03:06:46 -06:00
LostDragonist b53be165fd Savagemes -> Savegames 2018-12-06 02:59:41 -06:00
LostDragonist 849d00521a Transition profile settings to settings.ini 2018-12-05 19:17:16 -06:00
Al12rs deb3c5ca21 Fixed tooltip and "What's this" to better explain INI options. 2018-12-05 22:57:52 +01:00
Al12rs 25448ef076 * Changed "Local game settings" to "Use profile-specific Game INI files".
* Added tooltip to the option explaining what it does since it was missing.
* Improved Local Savegames text and tooltip as well.
2018-12-05 22:50:03 +01:00
LostDragonist 40919c1520 Create empty mods above the selected mod 2018-12-04 18:08:39 -06:00
LostDragonist 79c451bb17 Improvements to "send to separator..." dialog
* Scale contents with dialog size
* Save and restore dialog geometry
* Add a better window title
2018-12-03 06:04:16 -06:00
LostDragonist 87292ca30f Add filter to "send to separator..." dialog 2018-12-02 22:07:58 -06:00
LostDragonist c0b55690bc Add "send to separator..." option for mods 2018-12-02 20:26:26 -06:00
Al12rs f1384cdfa7 Fixed context menu for Data tab showing the File version for empty folders. 2018-12-02 12:48:16 +01:00
Al12rs c9658e1a65 * Added Folders and Files icons to Data tab.
* Fixed empty folders not showing up in Data tab.
2018-12-01 23:23:28 +01:00
LostDragonist 9431597e66 Correct comparison logic for blacklist warning 2018-11-29 15:33:47 -06:00
LostDragonist 4566b51093 Set general settings tab as the default again 2018-11-29 15:23:25 -06:00
LostDragonist 2212ad6f1c Add executable blacklisting 2018-11-29 14:11:09 -06:00
LostDragonist 6142872620 Prevent the user from renaming unmanaged and DLC mods 2018-11-26 07:51:45 -06:00
LostDragonist 4cae1397e7 Prevent the user from setting a negative mod priority 2018-11-26 07:44:26 -06:00
LostDragonist 7fbfc12118 Sort the plugin list 2018-11-26 07:23:11 -06:00
LostDragonist 4eaa0d16bb Resize plugin settings to make keys visible 2018-11-26 07:23:03 -06:00
LostDragonist a219d03444 Add cancel button to "Start Steam?" dialog to not start binary 2018-11-26 03:13:33 -06:00
LostDragonist ad01e1d608 Less strict implementation of path normalization 2018-11-10 22:04:12 -06:00
LostDragonist aaa1523db9 Normalize path settings to prevent extra characters 2018-11-10 16:24:45 -06:00
LostDragonist effd05df06 Tweak text color selection to prevent white text on bright green background 2018-11-09 19:05:06 -06:00
LostDragonist 545b7b4eb7 Fix button colors in the settings dialog with the default theme 2018-11-09 18:14:01 -06:00
Al12rs 71830a65d4 Added three new Transparent Styles by Gernash:
Transparent Style 101 Green
Transparent Style BOS
Transparent Style Skyrim
2018-11-09 21:50:46 +01:00
Al12rs bde2e5fca1 Improved Skyrim.qss theme performance. 2018-11-09 17:15:04 +01:00
Al12rs 15bbfdfa6f Added Nigh Eyes theme by ciathyza. 2018-11-08 20:41:40 +01:00
LostDragonist a85a6e635e Update translation file 2018-11-06 19:00:06 -06:00
LostDragonist 9abb3ca162 Prevent user from clicking the run button more than once 2018-11-05 21:43:50 -06:00
LostDragonist 5588b8b756 Change "mods" to "plugins" in "send to priority..." option for plugins 2018-11-04 13:47:39 -06:00
LostDragonist d48392c89f Don't change priority of new separators when not sorting by priority 2018-11-04 13:45:42 -06:00
LostDragonist 21d61e617b Hide "send to" context menu options when not sorting by priority 2018-11-04 13:39:22 -06:00
LostDragonist a48a20f13f Add context menu option to send to a specific priority 2018-11-04 13:10:41 -06:00
LostDragonist 2e09e633bd Fix creating separators when right-clicking overwrite 2018-11-04 12:33:37 -06:00
Al12rs 1189b8cc33 Made the "checked" filter show separators. 2018-11-04 16:19:54 +01:00
LostDragonist 17f1cf0aab Allow switching instances when MO is launched with moshortcut://<instance>: 2018-11-02 21:02:30 -05:00
Al12rs 78cd0110d3 Updated Skyrim and VS15 theme to fix highlighting on ESPlist. 2018-11-02 19:29:50 +01:00
LostDragonist 2c57899cf6 Fix matching highlights for mod and plugin selections
The selectionChanged event used before requires subtractive/additive logic to work correctly.  A separate event is fired for each row and each column for each row that is selected or deselected.  The previous logic assumed all of the selection was passed in at once.

The logic has been changed to recalculate all highlights each time the event is fired.  This is poorly optimized in regards to performance but makes the function work.
2018-11-01 17:58:49 -05:00
LostDragonist 3dbfba91e1 Add separators according to context location of context menu 2018-11-01 16:55:58 -05:00
Al12rs 2c53f9d934 Cleaned up leftover from color customizzation. 2018-11-01 16:35:02 +01:00
Al12rs 6323a348da Fixed missing category selection for separators. 2018-11-01 16:29:38 +01:00
Al12rs 73842ee245 Added ability to change color of conflict and plugin highlighting from the settings. 2018-11-01 16:20:53 +01:00
LostDragonist 122744454c Improve changing mod and plugin priorities 2018-11-01 06:40:55 -05:00
LostDragonist 5de173ba1a Add send to top/bottom options for the plugin list 2018-10-31 17:05:05 -05:00
LostDragonist eb26120332 Add send to top/bottom options for the mod list 2018-10-31 14:53:24 -05:00
LostDragonist 6056202ead Fix crash when 7-zip fails to extract a file
A thread is spun off to handle the extraction while the main thread handles the progress bar updates.  Previously, a dialog was spawned in the thread when an error in 7-zip occurred.  Now, the thread will terminate and pass the error message back to the main thread who will spawn the dialog.
2018-10-31 00:52:32 -05:00
LostDragonist c1d90b131b Add modinfoseparator to CMakeLists.txt 2018-10-30 21:38:16 -05:00
Al12rs 63a66c8754 Added VS2015 and Skyrim Stylesheets, courtesy of chintsu! 2018-10-28 19:11:44 +01:00
Al12rs ab95f78689 Added Reset color option for separators and changed the bahavior of "cancel" of the color selector dialog to keep previous color. 2018-10-28 17:27:34 +01:00
Al12rs 9e66799abf Fixed Separators not getting deleted while deleting multiple selected items. 2018-10-28 16:15:27 +01:00
Al12rs dce6507dad Added Color costumization for Separators. 2018-10-28 15:04:50 +01:00
Al12rs 42d2344f0b Added modlist Separators feature:
*New modType separator.
*Bold, italic and centralized name without _separator at the end.
*Added "create separator" option to context menu.
*Added "rename separator" option.
*Fixed rename separator issue with priority resetting.
2018-10-28 02:16:20 +02:00
Al12rs 18e49b71b5 Added uniformRowHeight = true property to the modlist, data tab, filters view and Log area. It should make Qt perform better when showing a large number of items. 2018-10-27 18:37:51 +02:00
Al12rs fcb29afe83 Increase filterview size to not cut off filternames 2018-10-13 14:44:16 +02:00
Al12rs cf52aa335a Fix Creator setting Boss button to invisible each time 2018-10-13 11:47:10 +02:00
Al12rs 9c35443780 Fixed UI file to not break each time it's opened in creator. 2018-10-13 10:42:12 +02:00
Silarn 9c6c01df56 Update path to gamebryo/creation engine sources 2018-10-01 00:14:03 -05:00
LostDragonist b83807e4d5 Set the web viewer widget in the mod info dialog to expand vertically 2018-09-30 16:04:28 -05:00
LostDragonist 2d50b17243 Fix pointer truncation to remove warning 2018-09-30 16:03:28 -05:00
LostDragonist 5a1d4e8783 Rename spacer to get remove warning 2018-09-30 16:03:27 -05:00
Al 478aeeb28c Merge pull request #536 from AnyOldName3/patch-1
Add link to upcoming FNISTool repo
2018-09-30 12:27:27 +02:00
Al 07fc9d3546 Merge pull request #537 from AnyOldName3/patch-2
Add link to Skyrim VR repo
2018-09-30 12:27:14 +02:00
Al12rs 15ab8d5c5e Changed "ignore missing game data" to not create an empty Texture folder and instead save the choice in meta.ini 2018-09-29 15:07:24 +02:00
Al12rs 192f14b001 Updated translations file 2018-09-29 12:10:41 +02:00
Al12rs 3ccceb19e1 Added .editorconfig to main repo to help keep some consistency of whitespace. 2018-09-29 09:38:03 +02:00
AnyOldName3 2d9a2a0432 Add link to Skyrim VR repo 2018-09-26 16:40:57 +01:00
AnyOldName3 ac650ae078 Add link to upcoming FNISTool repo
DO NOT MERGE UNTIL https://github.com/ModOrganizer2/modorganizer-umbrella/pull/31 IS HANDLED
2018-09-26 16:16:43 +01:00
LostDragonist 1a91174757 Merge pull request #534 from Gaerzi/patch-1
Extend version field to 12 characters
2018-09-25 14:28:46 -05:00
Gaerzi e2ec6632ec Extend version field to 12 characters
This is needed because some mods out there have version strings longer than 10 characters. For example, the current version string of [SSE Engine Fixes (skse64 plugin)](https://www.nexusmods.com/skyrimspecialedition/mods/17230) is "2.12.1.5.50" -- 11 characters in total.

12 should hopefully be enough.
2018-09-25 17:37:24 +02:00
LostDragonist b1a3bdd6e8 Automatically set CDN as a preferred server
This also removes the (free) and (premium) labels from the servers as they aren't useful anymore.  Premium users get premium speeds on all servers.  Added (automatic) tag to the CDN server to indicate it will automatically pick servers based on geography.
2018-09-17 00:01:12 -05:00
Al12rs 22a004be2e Reverted default setting tab to General 2018-09-15 19:18:29 +02:00
Al12rs a3cb400152 Store and load major dialogs geometry information. 2018-09-15 14:12:24 +02:00
Silarn 3e29d31231 Allow installs to pass Mod ID through (fixes NCC installs losing ID) 2018-09-09 04:12:23 -05:00
Al edf48bca6f Update readme.md 2018-09-08 13:08:06 +02:00
Al12rs 33e11e2056 Added debug line to check actual processed parameters passed to CreateProcessHooked() to see if we can discover somethig more on Parameter is incorrect error. 2018-09-08 12:32:45 +02:00
Al12rs 67fb7e56d3 Add option to create a Mod backup from the modlist context menu. 2018-09-07 22:04:03 +02:00
Al12rs 979206228d Added Mod Backups filter for modlist. 2018-09-07 20:53:42 +02:00
Al12rs ba162804cd Added Contains Script Extender Files filter. 2018-09-07 20:19:20 +02:00
Al12rs c6751b690a Improved Skript Extender Plugin filter to actually look for plugins and not only the SKSE folder. 2018-09-07 18:56:28 +02:00
Al12rs 138154aca0 Added "Refresh" button to downloads tab. 2018-08-31 22:16:13 +02:00
LostDragonist c576f1ff40 Refresh save game list when local game settings may have changed 2018-08-26 18:39:30 -05:00
Al12rs c4636d891f Added ModGroups contents icon and flag. 2018-08-25 14:30:27 +02:00
LostDragonist 8ea8444dc8 Update the version to 2.1.6 2018-08-24 19:50:46 -05:00
Brian Munro 2232bdfc77 Merge pull request #497 from Modorganizer2/Develop
Fix possible crash during write to disk error
2018-08-22 06:38:34 +02:00
LostDragonist 258bddb6b7 Fix possible crash during write to disk error 2018-08-21 15:59:22 -05:00
Brian Munro 364289db72 Merge pull request #495 from Modorganizer2/Develop
Release 2.1.5
2018-08-21 12:23:47 +02:00
LostDragonist ef771fd8ca Fix disabled menu item styling in Paper Dark theme 2018-08-20 00:55:18 -05:00
LostDragonist 2060df1585 Detect errors when writing downloads to disk and cancel download 2018-08-19 16:33:34 -05:00
LostDragonist 9a973ccf5f Center profile deletion dialog on parent 2018-08-19 13:02:54 -05:00
LostDragonist a2eb3e0266 Prevent user from deleting currently active profile 2018-08-19 13:02:30 -05:00
LostDragonist d65031c814 Allow user to cancel VFS mapping 2018-08-16 22:40:17 -05:00
LostDragonist c27e718fbd Add "enable/disable selected" to mod list context menu 2018-08-16 14:32:28 -05:00
LostDragonist 43b2df9077 Add "enable/disable selected" to plugin list context menu 2018-08-16 13:58:44 -05:00
LostDragonist 79b2e52a58 Fix another instance of "Open in Explorer" 2018-08-16 08:35:19 -05:00
LostDragonist 16a7ef78d3 Change version to 2.1.5 2018-08-16 08:19:05 -05:00
LostDragonist 74202cc743 Dracula theme: Make disabled widgets darker than enabled widgets
Fix by Kob, author of the Paper themes.
2018-08-16 01:29:01 -05:00
LostDragonist 8f86130759 Correct file category when manually querying info
The Nexus API appears to have been changed back in July 2018 to match what MO was expecting without the conversion.
2018-08-15 11:53:33 -05:00
LostDragonist 17e4ec7b13 Fix selecting the active profile when opening the profiles dialog 2018-08-12 19:59:54 -05:00
LostDragonist 9a426a2474 Revert "Improve robustness of endorsement checks"
This reverts commit fc8a6b358f.
2018-08-12 12:33:22 -05:00
LostDragonist 80594d6e1a Set toolbar widget names later to catch the problems and update widgets 2018-08-12 12:13:47 -05:00
Al12rs 56473e0ec8 Updated "Thanks". 2018-08-07 19:57:23 +02:00
LostDragonist 71988e386c Modify dark and dracula stylesheets to allow text colors on download widgets 2018-08-06 21:40:59 -05:00
LostDragonist 5e7c0fddf0 Update Paper themes by 6788-00 to version 3.0.1 2018-08-06 21:37:05 -05:00
Al12rs b0c15c9cfb Added Open File option to downloads tab. 2018-08-06 20:17:57 +02:00
Al12rs f92027bea6 Merge PR 2018-08-06 19:54:45 +02:00
Al a31b5495b8 Merge pull request #469 from Freso/minor-fixups
A couple of minor fixes
2018-08-06 16:13:18 +02:00
Frederik “Freso” S. Olesen fc19486f53 Fix capitalisation of "Explorer"
1. Explorer is a specific program, so it should be treated as a proper
   noun, and thus capitalised.
2. Other menu items in the same menu are Title Cases, so it looks out of
   place that this item is not.
2018-08-06 15:17:23 +02:00
Frederik “Freso” S. Olesen 232bbfb23b Fix DownloadManager::openInDownloadsFolder error message 2018-08-06 13:23:28 +02:00
Frederik “Freso” S. Olesen 2af99f2170 Clean up DownloadManager::openFile 2018-08-06 13:21:08 +02:00
Frederik “Freso” S. Olesen 796224d733 Add new "Open File" right-click dialog for Downloads
This enables the user to directly open the downloaded archived/file
which can be useful for e.g., inspection of what's inside or if they
need to copy files from inside the archive to somewhere else. Saves a
step compared to "Show in Folder" and then opening the file.
2018-08-06 12:21:02 +02:00
LostDragonist 1e4b5d2436 Set the names of the toolbar widgets to allow styling
QToolButton#foo where foo is one of:
  actionChange_Game
  actionInstallMod
  actionNexus
  actionAdd_Profile
  actionModify_Executables
  actionTool
  actionSettings
  seperator
  actionEndorseMO
  actionProblems
  actionUpdate
  actionHelp
2018-08-05 15:56:39 -05:00
LostDragonist 94ef8dffbc List load order backups from most recent to oldest 2018-08-04 22:16:39 -05:00
LePresidente 7b1821a518 Reverted bad commit, should of removed VS_FF_PRERELEASE 2018-08-04 11:24:49 +02:00
LePresidente fb0d4d5e5a use VER_FILEVERSION_STR instead of VER_FILEVERSION so pre-alpha is not shown 2018-08-04 10:35:56 +02:00
Brian Munro 9a3a15b1f6 Merge pull request #454 from Modorganizer2/Develop
Release 2.1.4
2018-08-02 09:15:12 +02:00
Al12rs 1ea43586d8 Merge branch 'Develop' of https://github.com/Modorganizer2/modorganizer into Develop 2018-08-01 20:12:32 +02:00
Al12rs fd51434e5e Enabled Ctrl+C to copy selected stuff instead of the entire log. No one used it before and now it's much more practical. 2018-08-01 20:04:59 +02:00
LostDragonist 7eb4b33214 Tweak shading of mods and plugins to better support dark themes 2018-08-01 12:55:36 -05:00
Al12rs e1e367c7ea Added CTRL+Doubleclick on plugin list as well 2018-08-01 17:55:07 +02:00
Al12rs 696bb3bc47 Added CTRL+Double Click on Modlist to open in Explorer 2018-08-01 17:18:07 +02:00
Al12rs 10be66a62a Revert "Temporarely disable the BSA list refresh if it is hidden from view. this will need to be reversted once the Bsa changes are added I presume."
This reverts commit 8f28e0af36.
2018-08-01 17:07:35 +02:00
LostDragonist a02b920b19 Force nxmhandler.exe registration when the associate button is clicked
This allows the register dialog to appear when the user had previously selected "No, don't ask again".  If a user is clicking this button, there's a good chance they want MO to be the primary nxm handler.
2018-07-27 12:34:28 -05:00
LostDragonist 2f8e5b4f69 Update translation file 2018-07-24 14:00:26 -05:00
LostDragonist 385765ecdd Truncate strings longer than 1024 characters in the plugin list tooltip 2018-07-23 14:13:12 -05:00
LostDragonist 447a2169fe Allow more characters in instance names and add an error message
Previously allowed:  "A-Za-z0-9 "
Now allowed:         "A-Za-z0-9 !@#$%^()_+-=[]{};'."
2018-07-22 19:44:39 -05:00
LostDragonist fc8a6b358f Improve robustness of endorsement checks
At times, the voted_by_user item is returned as Invalid.  toBool() causes this to be false, meaning the item is seen as not endorsed.  Now, the endorsement state is not checked if the data is invalid.
2018-07-22 14:28:38 -05:00
Al12rs edf608ab23 Allow normal QAbstractItemModel event handling for mainwindow. Somehow before it wouldn't work. 2018-07-22 15:49:40 +02:00
Al12rs d02df7e4b4 Avoided downloads defaulting to "File Time" sorting at each startup.
Improved downloads tab header sizes and resize policy.
2018-07-21 23:43:04 +02:00
Al12rs cc63717060 Added "Open Mods folder" to "Open Folder" context menu. 2018-07-21 20:09:25 +02:00
Al12rs 8f28e0af36 Temporarely disable the BSA list refresh if it is hidden from view. this will need to be reversted once the Bsa changes are added I presume. 2018-07-21 20:01:40 +02:00
Al12rs e80bb3a837 Check if there is actually something in overwrite to delete before asking confirmation. 2018-07-18 16:14:16 +02:00
Al12rs f6ecb93d46 Set delete Key to recursively clear overwrite with confirmation message. 2018-07-18 16:00:19 +02:00
Al12rs 4f14598cfc Changed size rappresentation in downloads compact view. 2018-07-18 12:06:35 +02:00
Al12rs ce2494ba20 Don't show info dialog for unmanaged pluugins. 2018-07-18 12:03:02 +02:00
Al12rs d5f3bee642 Changed unit check. 2018-07-18 12:01:50 +02:00
Al12rs b38957d853 Small visual fix for size positioning in compact downloads. 2018-07-18 12:00:55 +02:00
Al12rs f824d255a2 Added clarification to loads archives tooltip. 2018-07-17 19:51:30 +02:00
Al12rs 344b83957e Revert "Fix download index in downloadFinished"
This reverts commit 942e656a71.
2018-07-17 18:35:32 +02:00
Al12rs 023cacab7f Added ability to open mod information window by double cliking on plugins. 2018-07-17 16:26:17 +02:00
Al12rs 35bbe0001e Added a flag to the plugin list indicating if a certain plugin has one or more archives attached.
Changed the tooltip to list the loaded archives.
Fixed tool tip to have titles for subsections.
2018-07-17 14:37:50 +02:00
Al12rs 75478f68a1 Avoid asking users if they are sure they want to close of all downlaods are paused. 2018-07-17 13:32:53 +02:00
Al12rs 5a0b8b431c Added Contains INI files content filter and checking. 2018-07-17 13:10:08 +02:00
Al12rs 61b33a8351 Added feather and scroll content icon to rappresent ini files. Icon curtesy of WolfHeartAurora. 2018-07-17 13:09:57 +02:00
Al 103e3f3098 Merge pull request #438 from LostDragonist/Develop
Added support for selecting multiple mod for multiple modlist options.
Added check for Windows Event Service before spawning new hooked processes.
2018-07-17 02:08:17 +02:00
Al12rs 872c33fe55 Added new "Hide Uninstalled" and "Delete Uninstalled" options to downloads tab. 2018-07-17 00:49:41 +02:00
Al12rs 9ddb26ea51 Added size label to compact download view. 2018-07-17 00:10:30 +02:00
Al12rs 1867c20f02 Added sortable "Size" column to the downlaods tab. 2018-07-17 00:10:03 +02:00
LostDragonist 6552054e58 Detect if the Windows Event Log service is not running 2018-07-16 15:46:44 -05:00
LostDragonist a830f3e09e Allow "unignore update" to work with multiple mods 2018-07-16 15:46:44 -05:00
LostDragonist eaf3655492 Allow "ignore update" to work with multiple mods 2018-07-16 15:46:44 -05:00
LostDragonist 952f1fe8cd Allow "open in explorer" to work with multiple mods 2018-07-16 15:46:44 -05:00
LostDragonist b4530eb843 Allow "mark as converted" to work with multiple mods 2018-07-16 15:46:43 -05:00
LostDragonist f20a1f6a84 Allow "ignore missing data" to work with multiple mods 2018-07-16 15:46:43 -05:00
LostDragonist 942e656a71 Fix download index in downloadFinished
An index of 0 is valid as this is a bog standard array.  This resolves an instance of the warning "no download index 0".
2018-07-16 15:46:43 -05:00
LostDragonist 7f3dc586b0 Redirect endorsements of MO2 to the Skyrim SE nexus 2018-07-16 15:46:43 -05:00
Al12rs 2524d65441 Added "Open in Folder" option to downloads tab. 2018-07-16 20:56:47 +02:00
Al12rs 5efddbd515 Chnged download speed to be a little more consistant in display, to avoid the progrss bar jumping around all the time. Chnaged the kb->MB jumps to happen at 1000 instead of 1024 to avoid going in the 4 digits, but still divide by 1024 to keep units acuurate. 2018-07-16 14:18:25 +02:00
Silarn 181de232f4 Potential fix for corrupted downloads 2018-06-25 20:50:49 -05:00
Al12rs 1f9103c24e Added the path of the managed game in the settings menu under the path tab, it's read only for now as allowing the user to change it would probably require a lot more work. 2018-06-22 02:47:58 +02:00
Al12rs 2d49ba2bef Add open in explorer button to Overwrite dialog. 2018-06-21 18:54:20 +02:00
Al12rs e41c97b64f Merge branch 'Develop' of https://github.com/Modorganizer2/modorganizer into Develop1 2018-06-20 21:33:27 +02:00
Al12rs b7d6bbb451 Fix for downloads getting stuck after pausing them.
Disabled timer check as it appeared to terminate some downloads early.
2018-06-20 19:33:56 +02:00
Al 4a765cc152 Merge pull request #410 from LostDragonist/Develop
Extend mod backups and load order backups to a maximum of 10
2018-06-20 16:17:29 +02:00
LostDragonist 30f170c10d Extend mod backups and load order backups to a maximum of 10 2018-06-20 08:45:05 -05:00
Al12rs b6aa12b323 Fix for downloads getting insta-completed if there isn't enough bandwidth for them to procede. Now they will instead remain in the download state and continue once the bandwidth is available.
There is much room for improvement here but for now I guess this will avoid MO simply stopping the download.
2018-06-19 23:13:06 +02:00
Al 19d80cc23d Merge pull request #400 from LostDragonist/Develop
Sort by game and fix for instance names
2018-06-10 09:55:41 +02:00
LostDragonist 0c4b1e9a92 Prevent instances from ending in a space
Windows directories are not allowed to end in a space.  Allowing
this creates a broken directory that is difficult for the user
to remove.
2018-06-09 10:44:23 -07:00
Lost Dragonist cacf7e0542 Allow sorting by "source game" column 2018-06-08 22:48:53 -05:00
Silarn f09ec53fcf Updated strings 2018-06-08 18:05:01 -05:00
Al12rs ddb40b712e *Avoided some unnecessary refreshes while removing mods.
*Added "Visit on Nexus" menu entry in the downloads tab.

*Added confirmation message when deleting a single download.

*Changed text of messages to more easily distinguish deleting from hiding.
2018-05-25 15:33:53 +02:00
Al12rs 186f26b71e Added un-hide all option to downlods tab.
Improved performace when hiding/unhiding. There is still room for improvement for hiding but it requires refactoring the function
2018-05-21 01:27:13 +02:00
Al12rs 6d6444c126 Made downlods file sizes human readable instead of just being KB 2018-05-20 23:53:57 +02:00
Al12rs 4b66c6c1ef Added "Open Plugins folder" option to Open folder menu. 2018-05-20 23:02:50 +02:00
Al 08f35d6519 Merge pull request #369 from iaz3/Develop
Fix a memory leak in updateToolBar
2018-05-18 14:02:02 +02:00
Diana 6617be8ef9 Fix a memory leak in updateToolBar
updateToolBar was creating new QActions and QWidgets every call, without cleaning them up.

The spacer, help widgets, and toolbuttons only need to be created once.
Those have been moved out into the MainWindow constructor

updateToolBar is called in various places, importantly when adding/removing executable shortcuts.

Also adds a deleteLater() call to clean up executable shortcut actions.
2018-05-18 07:45:13 -04:00
Al 5a5bfee712 Merge pull request #362 from Al12rs/dirWatcher
Downloads tab: fix for freezes and greatly improved performance and responsiveness
2018-05-17 19:59:06 +02:00
Silarn 2fc55ccc86 Updated strings for downloads 2018-05-16 23:54:50 -05:00
Al12rs 8731159bfb Huge performace improvements for downloads tab by disabling the dirWatcher triggered refreshes.
Avoid app freezes caused by stacked refresh calls.
Added chack to see if a download is alerady hidden before trying to hide it.
Made sure to refresh Download tab where it was othwerwise relying in the dirwatcher to refresh.
2018-05-17 00:03:10 +02:00
Al12rs 1c6543454e Initial work on avoiding the spamming of the Downlods tab refresh caused by the fileSystemWatcher picking up changes made by MO itself and triggering multiple refreshes 2018-05-17 00:02:34 +02:00
Silarn 941c50bff9 Add UA to resume and fix edge case for hung download check 2018-05-16 14:58:43 -05:00
Silarn 1e6e055f39 Add the MO user agent string to the download requests (fixes EU#1) 2018-05-16 11:14:44 -05:00
Jeremy Rimpo 81e329fb39 Merge pull request #361 from AnyOldName3/even-better-version-parsing
Move improved version parsing to util.h and use it everywhere.
2018-05-16 09:32:13 -05:00
AnyOldName3 15db1b76f7 Move improved version parsing to util.h and use it everywhere. 2018-05-16 00:42:31 +01:00
Jeremy Rimpo 75e6c72ae4 Merge pull request #360 from AnyOldName3/better-version-parsing
Better version parsing
2018-05-15 17:55:02 -05:00
AnyOldName3 9c1806cc74 Remove sneaky test qDebug instance. 2018-05-15 23:45:15 +01:00
AnyOldName3 8f905e1d49 Change how the VersionInfo object is created from version.rc such that non-release builds are possible and get labelled as such 2018-05-15 23:43:35 +01:00
Silarn 2ee5f0e96d Push version update for 2.1.4 dev 2018-05-15 12:46:49 -05:00
Silarn 0d220b6b41 Fixes for download errors and retrying with alternate mirrors 2018-05-15 11:13:16 -05:00
Silarn decbbb611e Download resume fixes for restarting MO, hung downloads 2018-05-13 18:32:59 -05:00
Silarn aeb0b42cde Refresh the sort proxy when the data is changed 2018-05-10 11:21:27 -05:00
Silarn 38391b10e9 Fix plugin lock slot typo 2018-05-10 09:21:02 -05:00
310 changed files with 25118 additions and 4160 deletions
+16
View File
@@ -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
+3 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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:
+2 -1
View File
@@ -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
View File
@@ -39,7 +39,8 @@ public:
enum EColumn {
COL_NAME = 0,
COL_FILETIME,
COL_STATUS
COL_STATUS,
COL_SIZE
};
public:
+2
View File
@@ -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
View File
@@ -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();
+11
View File
@@ -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);
+3
View File
@@ -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>
+89 -14
View File
@@ -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);
}
+11 -2
View File
@@ -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
+10 -3
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+38 -1
View File
@@ -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;
};
File diff suppressed because it is too large Load Diff
+227 -224
View File
@@ -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
View File
@@ -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;
}
+1
View File
@@ -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