Compare commits

...
Author SHA1 Message Date
Tannin 9ee90a35dc - MO now applies a minimum to the nmm-compatibility field.
- bugfix: "visit on nexus" directed the browser to the servers meant for nmm
- bugfix: url for "check all for updates" and "enorse/unendorse" were not constructed correctly
2013-12-08 14:16:25 +01:00
Tannin ff78c6a014 - bugfix: extracting bsas did not work with non-ascii characters in the mod name
- another attempt to switch branches...
2013-12-07 17:41:45 +01:00
Tannin 340edcfbca - returned to default branch
- nexus interface will now use the nmm url
- nmm importer no longer cancels on a missing non-essential flag
2013-12-07 17:13:36 +01:00
Tannin c4f0bc39c7 Merge with default 2013-12-07 16:55:19 +01:00
Tannin e71c37df37 - bugfix: drag&drop on archive list didn't always work properly 2013-12-07 16:54:08 +01:00
Tannin b32457a7d2 - minor text fixes
- versions without a subminor version are now displayed without it (1.1 instead of 1.1.0)
- version compares now prefer the decimal comparison over the traditional
2013-12-07 16:07:28 +01:00
Tannin 6e1e8c37eb minor text changes 2013-12-07 14:23:51 +01:00
Tannin 469cc2d945 - download manager now saves the file times on nexus, for potential later use in version check
- nexus interface now supports 301 redirects
- now using the new nexus url format
- bugfix: "visit on nexus" used an outdated url scheme and thus caused unnecessary redirection
2013-12-07 12:48:18 +01:00
Tannin 0e90b9d233 - bugfix: changing nexus id directly via mod list did not cause the change to be saved 2013-12-04 19:54:28 +01:00
Tannin 0e19c84722 Added tag release v1.0.9 for changeset a61a930515ae 2013-12-01 23:52:42 +01:00
Tannin daf4ae44fa - added second context menu for changing categories that applies only changes to
the selected mods instead of replacing the existing set of categories (thanks to Ross!)
- bugfix: category filtering didn't work correctly when grouping was also active
2013-12-01 23:50:24 +01:00
Tannin ac29aa81f2 minor updates to readme and mod info ui 2013-12-01 21:43:16 +01:00
Tannin a0335d0a63 Added tag 1.0.8 for changeset a61a930515ae 2013-11-27 20:25:55 +01:00
Tannin f1515193ca - plugins can now be localized too
- fixes to the installer script
- extended build scripts to fetch translations from pootle server automatically
2013-11-27 20:25:24 +01:00
Tannin db0347212a - bugfix: installFile for mods was not a relative path if the downloads directory was non-default
- bugfix: crash after removing the last profile in the list (ordered alphabetically)
- improved subdirs ordering to ensure pythonrunner is compiled before pythonproxy
- translation files for plugins are now generated
- set some texts as un-translatable where it made no sense
- staging script now re-builds MO completely before packaging
- updated qt libraries for packaging to 4.8.5
- added python to the package
2013-11-22 17:45:34 +01:00
Tannin 5895a1a92d - bugfix: canceling creation of an ini tweak prompted an error message
- added missing files from earlier commit (wtf?)
2013-11-20 21:54:14 +01:00
Tannin c6101e34e1 - archive.dll now supports querying the crc value of files
- esptk now determines if a esp is a dummy (without records)
- hook.dll no longer creates a log file if noone wrote to it
- nexus id and installtime columns are now hidden by default
- modlist can now be refreshed without saving first (so plugins can replace the modlist.txt as a whole)
- plugins can now query more details about virtualised files
- added style options "plastique" and "cleanlooks"
- "overwrite" is no longer listed with a creation time
- a warning will now be displayed if the user has too many plugins active
- a warning will now be displayed if mods with scripts have an installation order that doesn't match the corresponding esp load order
- nmm importer now has select all/deselect all buttons
- nmm importer no longer tries to unpack missing files from archives (won't work anyway)
- initial support for importing from nmm 0.5 alpha
- removed some broken warning suppresions
- python runner now works with bundled python
- extended qbs build system (still fails to build the main gui application)
- implemented a nsis-based installer
2013-11-18 20:17:14 +01:00
Tannin 75475a7984 - started qbs based project files (not functional yet)
- modlist will now updated immediately after a change throw the modinfo dialog
- bugfix: configurator wasn't able to save after revision 137
2013-11-11 23:19:54 +01:00
Tannin 315ed6e41a Added tag release v1.0.7 for changeset 1973f6e00784 2013-11-06 18:40:09 +01:00
Tannin b2d613e9d1 Added tag release v1.0.6 for changeset 1973f6e00784 2013-11-06 18:40:03 +01:00
Tannin f010c22a3b - diagnosis plugins can now request to be re-evaluated
- main application now contains means for plugins to react on some changes (to be extended)
- plugins can now retrieve more information about a mod
- user-agent sent to nexus now automatically contains the current MO version
- included updated russian translation
- problems dialog now refreshes itself after a fix was applied
- fixed new esp/asset ordering diagnosis. May be fully functional now
- bugfix: restoring locked load order could leave MO in an endless loop (not sure if this fix is correct yet)
- bugfix: plugin list was not visually updated after some changes
- bugfix: nmm importer threw away mod ordering
2013-11-06 18:35:27 +01:00
Tannin d1594798e6 - added a new diagnosis to detect potential problems in regards to esp vs. asset ordering (not fully functional yet)
- new plugin interfaces to the mod list
- plugins can now query the origin (mod) of a esp/esm
- bugfix: potential access to profile before one was activated
- bugfix: regression in previous (not-yet-released) commit prevented changes to bsa list from being saved
2013-11-01 14:59:25 +01:00
Tannin 09bd3dbead - text files encoded in system encoding should now be correctly recognized in the mod info dialog
- archive-list can be user-sorted again (within one mod)
2013-10-26 15:02:31 +02:00
Tannin 8c0b309bde - Option to choose edition of the game. Currently only relevant for FO3 because FO3 GOTY is its own app
- applications that aren't in the executables list can again be started from the command line
- references to missing categories are now removed from mods
- bugfix: integrated fomod installer didn't update description and picture on some constellations of Windows version and theme
2013-10-25 14:49:42 +02:00
Tannin bc7c42dbe8 - directories in data-view are now sorted
- questionbox with selection memory is now exposed to plugins
- the choice to run fnis from the checker can now be memorized
2013-10-20 16:51:40 +02:00
Tannin 9a03783f49 - tooltip on download list now contains the file name
- bugfix: when refreshing the directory tree conflict information wasn't immediately refreshed (including on start)
- bugfix: dataChanged events wasn't emitted when user changed the modlist
- bugfix: file patterns in checkfnis plugin weren't completely correct
2013-10-18 23:35:38 +02:00
Tannin d73b1e38c8 - mod sorting now always uses priority as secondary sorting
- added missing ipluginlist.h
2013-10-17 19:21:22 +02:00
Tannin b47c89661e - plugin (esp/esm) list is now exposed to plugins (read-only functionality right now)
- integrated fomod installer now supports file dependencies
- bugfix: integrated fomod installer crashed if the installer had no optiosn´´ns
2013-10-16 23:04:03 +02:00
Tannin 0b84cc3d45 Merge 2013-10-16 19:34:56 +02:00
Tannin 1bf3cc585e - nmm importer now also transfers category, endorsement state and lastest version information
- nmm importer should now always determine the correct nexus id
- nmm importer will now correctly restore overwritten files for imported mods
2013-10-16 19:32:59 +02:00
Tannin eae275cc84 Added tag release v1.0.5 for changeset c6a9d2ab2d6c 2013-10-15 23:34:16 +02:00
Tannin f3cb50057b - bugfixes to last merge
- fnis-check plugin can now be disabled
2013-10-12 13:21:37 +02:00
Tannin 5518309300 Merge 2013-10-12 12:32:37 +02:00
Tannin f22bb9d6a6 Merge 2013-10-11 23:04:44 +02:00
Tannin 382226bb46 - added new plugin to test if fnis needs to be run
- some functionality to the plugin interface to enable them to search for files&directories in the virtual FS (rudimentary atm)
- functionality for plugins to react to application being started from MO
- broken ESPs are no longer reported as popup windows but only in the log file
- bugfix: plugins couldn't store persistent data if they had no user-editable settings
2013-10-11 23:03:49 +02:00
Tannin bdf04f516c - MO now warns if a nxm-link for a wrong game was attempted instead of downloading the wrong file
- bugfix: in nxmhandler adding a new line with different game but same executable didn't work (the change was silently dropped)
2013-10-10 21:23:25 +02:00
Tannin 54c7131a5e - new toggle to display hidden downloads
- hidden downloads can be un-hidden
- the installation manager now more thoroughly cleans up the temporary directory after installation
- added SkyrimLauncher.exe to the list of auto-detected executables
- bugfix: shutting down MO while downloads where active in some occasions didn't work
- bugfix: when canceling the only active download the taskbar icon didn't return to normal
2013-10-10 19:32:01 +02:00
Tannin 15e256ef44 Added tag release v1.0.4 for changeset 7732c5d2e41d 2013-10-10 19:09:29 +02:00
Tannin b23a4885e0 - bugfix: When updating MO, if login is required, the process didn't continue automatically after login 2013-10-06 14:12:25 +02:00
Tannin 823dfd410b - option to ignore/unignore updates is now only shown if there IS an update
- window now shouldn't lose focus on win 8 2 seconds after mod information gets invalidated
- small bugfix related to new version scheme parsing
2013-10-06 13:34:34 +02:00
Tannin ba09054e6b Merge 2013-10-06 12:20:07 +02:00
Tannin 694e3ed279 bugfix: statusbar may have stayed enabled if an error occured on handling the refreshed-event 2013-10-06 12:19:46 +02:00
Tannin cffd9eb4e2 - hook.dll now doesn't inject to certain applications (currently steam, chrome and firefox)
- versioning system improved. Will now report "downgrades" for mods and support a different versioning system (requires manual switch)
- updates can now be ignored until a new version is uploaded
- new splash screen
- bugfix: a few memory leaks (shouldn't account for much)
- bugfix: result of GetModuleHandle wasn't zero-terminated in some cases
2013-10-05 14:20:48 +02:00
Tannin 640b14ef25 diagnosis plugin now warns when nitpick is installed 2013-09-30 18:33:45 +02:00
Tannin 47293827bb - download progress is now visible in task bar
- esp-tooltip now lists all masters, highlighting the missing ones
- python plugin will now report a problem if the path contains a semicolon
- leak detection now (somewaht) works around the fact that we don't always get a stack trace
- bugfix: mod meta-file is now reliably created if it was missing
- bugfix: parser for nxm-links didn't handle numbers in the mod name
- bugfix: small memory leak
2013-09-28 21:13:57 +02:00
Tannin 0a3169b808 - plugin tooltip now only lists the masters that aren't enabled (if any) 2013-09-26 19:10:44 +02:00
Tannin f4528c7aaa - bugfix: esp parsing could crash for broken/unrecognized esps
- bugfix: esp parser didn't handle oblivion esps correctly
2013-09-23 22:39:58 +02:00
Tannin 4f0a6e8b88 Added tag release v1.0.2 for changeset 0aaed2f8f48d 2013-09-22 13:24:53 +02:00
Tannin c57b172204 - removed some obsolete code
- MO will no longer start an application while the directory structure is being refreshed because MO may need to access profile files afterwards
- bugfix: the overwrite info-dialog was not destroyed and could thus keep a lock on files thus preventing those files from being moved/deleted
2013-09-22 13:10:21 +02:00
Tannin dfca8be71b - esp reader now handles invalid files more gracefully
- files moved will now also be treated as "deleted" in the old location so a newly created file with that same name is not created in overwrite
- introduced a mechanism by which MO can recognize if it crashed before when attempting to load a plugin. That plugin can be blacklisted so it doesn't get loaded again
- plugins can now programaticaly change their settings
- plugins can now store data persistently without exposing that data as settings
- requesting an unset-setting from a plugin is no longer treated as a bug
- clarified warning message for when files are in overwrite directory
- the proxyPython plugin will now discover if python initialization crashed MO on a previous session and give the user a chance to fix it or disable the plugin
- bugfix: GetModuleFileName modified the buffer past the zero termination. While this doesn't violate the API documentation it is different from the regular windows implementation
- bugfix: proxy plugins couldn't access the parent widget
- bugfix: when moving a file from overwrite to a mod the in-memory file structure wasn't updated
- bugfix: name input dialog for profiles allowed names that weren't valid directory names
- bugfix: profile dialog wasn't able to delete profiles if the name started or ended in whitespaces
- bugfix: The name-cells for plugin settings could be changed (without effect)
- removed a few obsolete files from the repository
2013-09-21 19:25:33 +02:00
Tannin 08037bf876 Added tag release v1.0.1 for changeset b90a2e9174c0 2013-09-21 18:59:47 +02:00
Tannin 500ab7f706 - bugfix: testing for missing masters at the wrong time seems to have caused crashes
- bugfix: mod list is now written to a temporary file first. Only on success is the original file overwritten
- bugfix: moving a mod priority to just above the overwrite could cause a crash or error message
- bugfix: versions with a release candidate number weren't sorted correctly (woops)
- bugfix: staging script didn't include archive.dll and dlls.manifest
- installation time on overwrite no longer updates constantly
2013-09-16 22:32:42 +02:00
Tannin 08309b71ba Added tag release v1.0.0rc1 for changeset 438584941a82 2013-09-15 16:11:16 +02:00
Tannin dce78b62b8 - bugfix: when installing mods through the nmm importer if no other mods were previously installed
the correct installation directory was never set
- bugfix: the nmm importer didn't "sanitize" mod names and potentially tried to create invalid directories
- bugfix: 0.99.x packages didn't contain qt plugins to handle certain image formats
2013-09-12 21:45:57 +02:00
Tannin af6e1c3ab4 - when installing mods from outside the download directory the absolute path is now stored
- added a context menu to the toolbar buttons so tool icons can be removed directly
- initweaks modinfo tab is now always available and allows new ini tweaks to be created
- fake esms are now treated as masters (as they should)
- MO will now display a warning if not all masters of an esp are enabled. The tooltip gives a list of required masters
- bugfix: path returned by getfullpathname was sometimes not correctly terminated
- bugfix: path after reverse-rerouting was sometimes incorrect, missing a path separator
- bugfix: change of current directory sometimes used a fake directory without need
- bugfix: icons in shortcut menu were not alwayscorrectly updated
2013-09-11 22:54:45 +02:00
Tannin 50325c8fc2 Added tag release v0.99.6 for changeset d9dedb857683 2013-09-05 21:14:19 +02:00
Tannin 7a382eab75 updated versions 2013-09-05 21:14:08 +02:00
Tannin 8e6868bf88 - bugfix: automatically removes a file from old NCC release that was interfering with the current version
- bugfix: fomod installer didn't find fomod files in nested folder
- bugfix: python proxy will now not even try to initialize python if python_dir contains no python.
This is necessary because the python interpreter crashes the application if the path is invalid
2013-09-05 21:04:20 +02:00
Tannin a891146446 Added tag release v0.99.5 for changeset f75473410ed3 2013-09-02 19:28:24 +02:00
Tannin 72f14df8a7 - bugfix: "overwrite" is no longer a localizable string, at least for now, because some pieces of code rely on the name 2013-09-02 19:22:40 +02:00
Tannin 0fa7155eb8 - bugfix: division-by-zero error in the newly introduced server-speed calculation
- bugfix: temp files extracted during fomod installation were not cleaned up. This still doesn't remove directories
- bugfix: fomod installer didn't find the installer xmls because they are in a subdirectory since release 0.99.4
2013-09-02 18:51:17 +02:00
Tannin c6c61ce792 Added tag release v0.99.4 for changeset a2ccfea95ef0 2013-09-02 18:48:52 +02:00
Tannin ef801879ab - separated python proxy into two dlls. One is a wrapper without external
dependencies that fulfills the plugin interface. The other contains the actual python
functionality. This way the outer dll can always be loaded and report issues.
- The build process embeds the second dll into the first, this way only one dll has to be shipped
2013-09-01 18:36:43 +02:00
Tannin 1e6c5f7c25 - added a new column for not-yet-endorsed mods
- set categories menu no longer closes when the mouse cursor leaves the menu
- MO will no longer change the endorsement flag if an update doesn't contain it
- the column selection for the mod list can now only be accessed by mouse,
hotkeys open the context menu of the mod
- now displaying a progress dialog during login. For unknown reasons MO hangs during that time
2013-09-01 13:40:44 +02:00
Tannin 49e1dd23b6 - mod list can now be sorted by install time
- the sorting of download archives wasn't actually by index instead of file time
- bugfix: some of the plugins crashed if they failed to create a mod
2013-08-31 17:11:17 +02:00
Tannin 9c31cfa915 - the download manager now registers download speed. Right now this is only used
to display an average speed on the settings menu
- added a python27.dll compiled with vc100. This can now be bundled without introducing more dependencies
- bugfix: extracting now stops after an error
- bugfix: the way hook.dll caused CREATE_ALWAYS/CREATE_NEW to always write into overwrite could lead to the
file being created when the call should have failed (because the file existed and was protected)
- bugfix: GetPrivateProfileString does NOT properly report files as missing. This means that
the ini-query optimization could optimize away requests that should work
- bugfix: fomod installer couldn't display images because they were unpacked to the wrong temporary location
- bugfix: When disabling local saves and choosing to delete the saves nothing happened
- bugfix: the python plugin couldn't find the pyqt libraries
2013-08-30 20:59:12 +02:00
Tannin 91dd38cb29 Added tag release v0.99.3 for changeset bf57300454f1 2013-08-25 13:32:33 +02:00
Tannin bf0db9c218 - position of splitter in main window is now saved and restored
- confirmation dialog before enabling/disabling all plugins
- bugfix: GetPrivateProfileString-hook potentially accessed buffer that is allowed to be NULL
- bugfix: attempt to extract an archive crashed MO in 0.99.2
- bugfix: archive list wasn't saved correctly in 0.99.2
- bugfix: plugins.txt was incorrectly interpreted as utf-8
2013-08-25 13:15:23 +02:00
Tannin 8fcf21e771 - column sizing is now changeable by the user yet still automatically resizes fit content on first start 2013-08-24 23:11:20 +02:00
Tannin b46b2fe6f2 Merge 2013-08-24 22:50:22 +02:00
Tannin e91eebefbe - download size is now displayed
- multiple esps/mods can now be enabled/disabled at once using space
- bugfix: fomod installer didn't compile because of changes to condition checking
- bugfix: broken inverse virtual name resolution in case of non-default mod directory
2013-08-24 22:50:00 +02:00
Tannin 2e605b275b Added tag release v0.99.2 for changeset 95e629510d01 2013-08-24 14:14:00 +02:00
Tannin 5f2a49b3be - added code for c++ based boss dummy
- fixed staging scripts
2013-08-24 14:12:58 +02:00
Tannin c4955231cf - turned boss dummy into a c++ project (unmanaged exports with c# is a pain)
- updated NCC to current NMM codebase
- updated translation files
2013-08-24 12:08:57 +02:00
Tannin 87f4e2df26 Merge 2013-08-17 08:54:53 +02:00
Tannin 9272013103 - bugfix: download manager will now properly pause all downloads on exiting the application
- bugfix: resumed downloads now get their automatic-retry-count reset
- fiddled with condition tests in fomod (not sure if it works right now)
2013-08-17 08:54:09 +02:00
Tannin 78c4178f2a - plugins that failed to load are now reported as problems
- some wording fixes in the tutorial
- updated proxyPython to a modified interface
2013-08-17 08:49:36 +02:00
Tannin 7d79e3ad1e - bugfix: nameprefix-flag incorrectly interpreted on oblivion-style bsas
- bugfix: optimization for missing inis fixed
- bugfix: fixmods didn't search for esps in overwrite
- bugfix: configurator didn't work for fallout new vegas because of a missing cast
- bugfix: configurator attempted parameter formatting on ini files instead of using the raw data
- bugfix: searching for a path in the directory structure could cause a crash when not using the directory output
- optimization to findfirstfile for cases where a single file is searched
- display of bsas changed. hopefully it is more understandable now
- cache for the test whether a mod is in conflict. Should speed ab scrolling in mod list
- mod list has now an additional column for the installation time
- nmm importer no longer cancels in cases where a data file references an undeclared mod.
- integrated improved settings.json for the configurator contributed by "delta534"
2013-08-15 22:13:18 +02:00
Tannin d0f2c4fcf7 - now avoids a few unnecessary copy operations during generation of the directory structure
- bugfix: circular dependency caused a memory leak
- bugfix: removing a single mod lead to the wrong mod being deleted
2013-07-17 20:58:58 +02:00
Tannin 36ac91e0b7 - basic diagnosis plugin now catches an issue where the users fontconfig.txt refers missing files
- plugins can now resolve relative file names on the virtual directory (no enumeration yet)
- bugfix: dummy plugins were not initialized
2013-07-14 14:59:01 +02:00
Tannin 5c968a1242 - added the ability to connect to the internet through a proxy
- integrated fomod installer now supports the or-operator for page conditions
- integrated fomod installer now caches condition results to speed up tests
2013-07-13 22:11:30 +02:00
Tannin e09cef3909 - minor fixes to ncc build files
- MO will now use system-wide proxy if one is configured
2013-07-13 11:52:40 +02:00
Tannin 8d34ae3413 - some fixes to the refreshing behaviour
- "fix" buttons in problems dialog are now actually functional
- python proxy now has diagnosis functionality to warn user if correct proxy version is not available
- python proxy now has a configurable python path
2013-07-13 10:10:46 +02:00
Tannin 849a0a0ef4 bugfix: nxmhandler in headless calls didn't save changes 2013-07-05 14:34:46 +02:00
Tannin 3b3717a021 - nxmhandler now has a ui to modify the proxy-handler
- mo now registers itself with nxmhandler when launching the browser
- pdbs are now generated for plugins
- reverted configurator to pyqt4
2013-06-29 21:10:53 +02:00
Tannin fe37b48dff - caching of downloadwidgets to fix performance problem, currently broken and disabled
- added new state for downloads "uninstalled" for mods that were at one point installed and then removed
- user-configured server preference is now used
- updated tutorial to account for removal of integrated browser
- reverted to qt 4
- using performance optimised findfirstfile on win vista and up
- bugfix: it was possible to disable all columns of the mod list
- bugfix: hook.dll doesn't load on win xp
2013-06-29 18:04:10 +02:00
Tannin f8c683f700 - some fixes for qt5 compatibility
- hook.dll no longer creates a dump and uninstalls it if an exception is reported that doesn't originate from it
- NCC used read-only transactions again because otherwise solid archives become unusably slow.
- removed the integrated nexus browser
- the mod description and motd are now rendered in QTextBrowser. This (and the above) eliminates the dependency on qtwebkit
- removed the direct file download for mod files
- reduced CPU usage during downloads by invalidating only one column of the download list. This widget still needs to be replaced
- added the complete filename as an option for the modname
- applications that require elevation can now be started by invoking an elevated secondary ModOrganizer instance
- MO will now register nexus file servers and provides a settings dialog to pick preferred servers. (This preference is not used yet)
- worked around 1-2 bugs in QSortFilterProxy
- handling of nxm links is now done by an external application. This allows the registration of different applications depending on the game
- integrated fomod installer now displays the screenshot in a scalable view
- bugfix: integrated fomod installer didn't name output files correctly if the name differs from the source name
- bugfix: a successful login to nexus was (sometimes?) not correctly detected as a success
- bugfix: top-level entries in QtGroupingProxy were sometimes incorrectly displayed as groups
- bugfix: GetPrivateProfile... optimization could cause null-pointer indirection
- bugfix: GetCurrentWorkingDirectory caused buffer overflow in case of pre-flighting (buffer size 0)
- bugfix: configurator plugin now also uses qt5 (it's currently broken though)
2013-06-20 21:55:37 +02:00
Tannin 49cbe03491 - completed Qt5 compatibility
- added GetFileVerisonInfoW hook for Windows 8 compatibility
- fixed BossDummy to compile correctly with current version of the RGiesecke.DllExport assembly
- fixed NCC components compiling with different Framewerk versions
- dropped files-list in Nexus-tab of modinfo dialog
2013-06-15 14:42:20 +02:00
Tannin 6069decb15 - mod list no longer loses selection whenever categories context menu gets hidden 2013-06-08 22:23:25 +02:00
Tannin 30dece9093 Merge 2013-06-07 18:30:26 +02:00
Tannin 50d0523622 - locking/unlocking esps can now be done for the whole selection
- bugfix: MO crashed if the locked index file is borked. This shouldn't happen
anymore so I'm not sure how that file breaks to begin with
2013-06-07 18:16:52 +02:00
Tannin 067f272da3 - bugfix: archive file wasn't closed after installation
- bugfix: batch installer was treated as handler for "manual" installations
- bugfix: dropped include of unused sip interface
2013-06-06 20:19:38 +02:00
Tannin 97111de140 Merge 2013-06-05 10:05:29 +02:00
Tannin 280691ebc3 - skyrim-specific optimization to accelerate startup
- bugfix in SetCurrentDirectory hook
2013-06-05 10:04:56 +02:00
Tannin 1606c1366f - install plugins now get a chance to update name, version and modid of mods
- NCC now makes name, version and modid from the info.xml file available to the installer
- integrated fomod installer also uses version and modid from the info.xml
- mods can now be renamed during installation
- configurator plugin now highlights changed keys and saves changes
2013-06-05 09:51:48 +02:00
Tannin 8077c1ad73 updated .hgignore 2013-05-28 23:17:41 +02:00
Tannin aadd076269 - added hook for ansi version of SHFileOperation, this function may not be routed to the unicode version in every windows variant 2013-05-28 23:14:49 +02:00
Tannin d8cb9a4e37 - bugfixes in hookdll related to path-rerouting
- bugfix: expanding modlist groups after changes to modlist works now
- bugfix: sorting grouped modlist was broken
2013-05-28 22:43:19 +02:00
Tannin 3c21d1884a Merge 2013-05-25 12:26:13 +02:00
Tannin 16bda49e06 - bugfix: mod priority ordering could become incorrect
- bugfix: when grouping is enabled, newly installed mods broke grouping
- bugfix: syncing overwrite didn't clean up emptied directory
2013-05-25 12:24:48 +02:00
Tannin daf8bab136 - bugfix: installation using custom installer always created mod directory
- batch installer now displays progress during mod installation
2013-05-23 20:03:35 +02:00
Tannin 2c4ba2c62c Merge 2013-05-22 20:48:23 +02:00
Tannin 0ae7d4753c - diagnosis plugin now reports file in overwrite as a problem
- bugfix: GetModuleFileName returned the wrong string length
- bugfix: Vector Exception Handler no longer stops hook.dll on recoverable errors
2013-05-22 20:43:08 +02:00
Tannin f0ba6ce95c - added NCC to repository
- deleting files from download manager now moves them to recycle bin instead of deleting permanentyl
- cleanup in installation manager
- ini editor (old) can now be configured to open files in external editor
- bugfix: .net check in ncc installer was broken
- bugfix: mod-overwrite dialog wasn't displayed for complex installers
2013-05-22 18:16:56 +02:00
Tannin cdea0c9da5 Merge 2013-05-19 11:37:03 +02:00
Tannin 0beb88760b - added hook for GetModuleFileName
- downloads are now identifiable by ID
- fixed a bug with the multi-select categories list
- fixed a problem with the nexus-login code breaking support for certain passwords
- fixed a bug where detection of archive invalidation didn't work correctly
- fixed ncc plugin trying to handle archives that aren't actually fomods
2013-05-19 11:36:36 +02:00
Tannin 45f6cd21a2 - extended plugin interface to allow plugins access to download manager
- extended plugin interface to allow installation of mods from files
- improved detection of online state
- download tab now also displays files supported through plugins
- batch installer now has basic functionality (downloads and installes files)
2013-05-17 20:44:40 +02:00
Tannin fc3753dcc5 Merge 2013-05-10 11:00:09 +02:00
Tannin 9bc123e8e2 - initial support for exposing the nexusbridge to python
- started improving usability of nexus bridge
- support for installers implemented in python
2013-05-10 10:57:35 +02:00
Tannin d161e1a0d6 - if no version is known for a mod, the file date is used
- added files for the python proxy
2013-04-14 20:49:18 +02:00
Tannin 1c9018e9fd - bugfix: wrong multibyte to widechar conversion in hookdll breaks internationalization
- bugfix: mod names not checked for validity on rename
- bugfix: mod list wasn't invalidated after rename (regression?)
- problem reports moved to separate dialog
- ncc plugin now does the check for dotNet
- python plugin wrapper started (only supports tools currently)
- new ini editor plugin in python (non-functional currently)
2013-04-13 19:23:18 +02:00
Tannin 4fbfc9aa54 - multi-selection in category window
- profile loading is now slightly more forgiving
2013-04-12 15:31:47 +02:00
Tannin 528338d7bf some code cleanup 2013-04-05 18:24:36 +02:00
Tannin 5b04f38345 added modlist view class (updates drop behaviour on modlist depending on mime type) 2013-04-04 21:51:13 +02:00
Tannin de27ab391f - creating mods from overwrite
- moving files from overwrite to mods
- offline mode
- several fixes to the grouping system
- fix to "duplicate translation" errors
2013-04-04 21:49:44 +02:00
Tannin d9a6dbb916 Merge 2013-03-29 10:26:19 +01:00
Tannin f682f82db5 some improvements to the grouped modlist views 2013-03-29 10:25:38 +01:00
Tannin a47d971788 Merge with default 2013-03-29 10:12:34 +01:00
Tannin 59d6b7840b - post-merge cleanup 2013-03-29 09:41:41 +01:00
Tannin b4220cf2f4 Merge with branch1.0 2013-03-27 21:04:27 +01:00
Tannin e0eb97922d - added hooks for getFileVersion* functions
- automatic donwload retry
- support for storing multiple download urls
- improved "query info" functionality
- some cleanup to download manager code
- external fomod installer dialog are now brought to front
- added shell... functions to have windows handle problematic situations
- added visual clue when filters are active
- esps are now automatically activated when installing a mod
- added option to never endorse a mod
- added "previous" and "next" buttons to mod info dialog
- improved the way messagedialog text is shortened
- coloring in mod info dialog now visible in other color schemes
- plugin list is now saved automatically
- vanilla bsas are now enabled even if they are not listed in the ini file
- bugfix: setting mod to maximum now doesn't try to place the mod below overwrite
2013-03-27 20:48:33 +01:00
Tannin 10485e15e4 - some cleanup to hookdll
- exchanged grouping proxies with existing solution from the kde project
2013-03-27 12:32:23 +01:00
Tannin ec0ea9df8d Merge with default 2013-03-22 18:57:45 +01:00
Tannin 24cc386191 removed obsolete files 2013-03-22 18:54:04 +01:00
Tannin 0a19f04339 - support for grouping filters for mod list (incomplete)
- offering multiple options for mod names during installation
- support for renaming profiles
- updated installer plugins
- minor bugfixes
2013-03-22 18:46:40 +01:00
Tannin 74c75e60d6 Added tag release v0.12.9 for changeset ff711d0a1fa9 2013-03-18 20:03:57 +01:00
158 changed files with 21499 additions and 17155 deletions
+11
View File
@@ -2,3 +2,14 @@ syntax: glob
ModOrganizer-build-desktop*
outputd/*
output/*
build-ModOrganizer-*
source/NCC/*/bin
source/NCC/*/obj
source/NCC/bin
*.orig
source/plugins/proxyPython/build
staging/*
source - Copy/*
ModOrganizer-build-*
pdbs/*
source/NCC/BossDummy.x/*
+14 -11
View File
@@ -6,29 +6,31 @@ Requirements:
Visual C++ compiler 2010 (VC 10.0) or up
- Included in visual c++ express 2010 or windows sdk 7.0
Note: If you're having trouble installing the windows sdk, you may be affected by this bug: http://support.microsoft.com/kb/2717426
QtSDK 4.8.x (http://qt-project.org/downloads)
- Qt5 is not yet supported but WIP
- Install according to instruction
boost libraries (http://www.boost.org/)
- Compile according to their instructions (using vc++)
- As of time of writing boost_thread is the only compiled boost library used, you can
disable the others to safe yourself the compile time
- Compile according to their instructions (using vc++): http://www.boost.org/doc/libs/1_54_0/more/getting_started/windows.html
- A few of the boost libraries need to be built (the rest is header-only). The only compiled lib MO needs (at the time of writing) is
boost_thread. You can disable the others to safe yourself compile time (even on a modern system compiling boost can easily take an hour)
zlib (http://www.zlib.net/)
- Compile static library according to their instructions
- You should have a "zlibstatic.lib" under "build" afterwards
- Depending on the version of zlib and how you built you should have a file called zlibstatic.lib or zlibstat.lib in "build" or "x86\ZLibStatRelease".
- Please copy that lib file to "build\zlibstatic.lib" (if it doesn't exist) so MO finds it.
7z.dll (http://www.7-zip.org/download.html)
- Part of the 7-zip program
- Has to be the 32-bit dll! (approx. 893kb)
- If you don't want to install 7-zip (32-bit) you can open the 7z installer (i.e. 7z920.exe) in an archiving tool and unpack only the 7z.dll
Recommended:
------------
Qt Creator
- Included in QtSDK but there might be a newer version as a separate download
Set up (using Qt Creator):
--------------------------
@@ -40,14 +42,15 @@ Set up (using Qt Creator):
5. Switch the build configuration at the very top of the same page from "debug" to "release" (or vice versa) and repeat steps 3 and 4
6. Compile the configuration(s) you want to use (debug and/or release) (Build All). This should compile correctly.
7. return to the "projects" tab and switch to "Run Settings"
8. Determine the folder of the qt binaries in the package you downloaded. This could be "QtSDK\Desktop\Qt\4.8.5\msvc2010\bin" or "Qt4.8.5\bin"
For Release build:
8r. Add a "Run configuration" that points to <your working copy>\output\ModOrganizer.exe
9r. Copy "7z.dll" to <your working copy>\output\dlls
10r. From QtSDK\Desktop\Qt\4.8.0\msvc2010\bin copy the following files to <your working copy>\output\dlls: QtCore4.dll, QtDeclarative4.dll, QtGui4.dll, QtNetwork4.dll, QtScript4.dll, QtSql4.dll, QtWebkit4.dll, QtXml4.dll, QtXmlPatterns4.dll
9r. Add a "Run configuration" that points to <your working copy>\output\ModOrganizer.exe
10r. Copy "7z.dll" to <your working copy>\output\dlls
11r. From the qt binaries directory, copy the following files to <your working copy>\output\dlls: QtCore4.dll, QtDeclarative4.dll, QtGui4.dll, QtNetwork4.dll, QtScript4.dll, QtSql4.dll, QtWebkit4.dll, QtXml4.dll, QtXmlPatterns4.dll
For Debug build:
8d. Add a "Run configuration" that points to <your working copy>\outputd\ModOrganizer.exe
9d. Copy "7z.dll" to <your working copy>\outputd\dlls
10d. From QtSDK\Desktop\Qt\4.8.0\msvc2010\bin copy the following files to <your working copy>\outputd\dlls: QtCored4.dll, QtDeclaratived4.dll, QtGuid4.dll, QtNetworkd4.dll, QtScriptd4.dll, QtSqld4.dll, QtWebkitd4.dll, QtXmld4.dll, QtXmlPatternsd4.dll
9d. Add a "Run configuration" that points to <your working copy>\outputd\ModOrganizer.exe
10d. Copy "7z.dll" to <your working copy>\outputd\dlls
11d. From the qt binaries copy the following files to <your working copy>\outputd\dlls: QtCored4.dll, QtDeclaratived4.dll, QtGuid4.dll, QtNetworkd4.dll, QtScriptd4.dll, QtSqld4.dll, QtWebkitd4.dll, QtXmld4.dll, QtXmlPatternsd4.dll
Now you should be able to compile and run Mod Organizer.
Please note that when you change anything apart from the "organizer" subproject, qt creator may not pick up on the changes
+13 -9
View File
@@ -1,19 +1,23 @@
TEMPLATE = subdirs
CONFIG += ordered
SUBDIRS = bsatk \
shared \
uibase \
organizer \
hookdll \
archive \
helper \
shared \
uibase \
organizer \
hookdll \
archive \
helper \
plugins \
proxydll
proxydll \
nxmhandler \
BossDummy \
pythonRunner \
esptk
plugins.depends = pythonRunner
hookdll.depends = shared
organizer.depends = shared, uibase
organizer.depends = shared uibase plugins
CONFIG(debug, debug|release) {
DESTDIR = outputd
+78 -83
View File
@@ -17,86 +17,81 @@ You should have received a copy of the GNU General Public License
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "activatemodsdialog.h"
#include "ui_activatemodsdialog.h"
#include <QComboBox>
#include <QLabel>
ActivateModsDialog::ActivateModsDialog(const std::map<QString, std::vector<QString> > &missingPlugins, QWidget *parent)
: TutorableDialog("ActivateMods", parent), ui(new Ui::ActivateModsDialog)
{
ui->setupUi(this);
QTableWidget *modsTable = findChild<QTableWidget*>("modsTable");
QHeaderView *headerView = modsTable->horizontalHeader();
#if QT_VERSION >= 0x050000
headerView->setSectionResizeMode(0, QHeaderView::Stretch);
headerView->setSectionResizeMode(1, QHeaderView::Interactive);
#else
headerView->setResizeMode(0, QHeaderView::Stretch);
headerView->setResizeMode(1, QHeaderView::Interactive);
#endif
int row = 0;
modsTable->setRowCount(missingPlugins.size());
for (std::map<QString, std::vector<QString> >::const_iterator espIter = missingPlugins.begin();
espIter != missingPlugins.end(); ++espIter, ++row) {
modsTable->setCellWidget(row, 0, new QLabel(espIter->first));
if (espIter->second.size() == 0) {
modsTable->setCellWidget(row, 1, new QLabel(tr("not found")));
} else {
QComboBox* combo = new QComboBox();
for (std::vector<QString>::const_iterator modIter = espIter->second.begin();
modIter != espIter->second.end(); ++modIter) {
combo->addItem(*modIter);
}
modsTable->setCellWidget(row, 1, combo);
}
}
}
ActivateModsDialog::~ActivateModsDialog()
{
delete ui;
}
void ActivateModsDialog::on_buttonBox_accepted()
{
}
std::set<QString> ActivateModsDialog::getModsToActivate()
{
std::set<QString> result;
QTableWidget *modsTable = findChild<QTableWidget*>("modsTable");
for (int row = 0; row < modsTable->rowCount(); ++row) {
QComboBox *comboBox = dynamic_cast<QComboBox*>(modsTable->cellWidget(row, 1));
if (comboBox != NULL) {
result.insert(comboBox->currentText());
}
}
return result;
}
std::set<QString> ActivateModsDialog::getESPsToActivate()
{
std::set<QString> result;
QTableWidget *modsTable = findChild<QTableWidget*>("modsTable");
for (int row = 0; row < modsTable->rowCount(); ++row) {
QComboBox *comboBox = dynamic_cast<QComboBox*>(modsTable->cellWidget(row, 1));
if (comboBox != NULL) {
QLabel *espName = dynamic_cast<QLabel*>(modsTable->cellWidget(row, 0));
result.insert(espName->text());
}
}
return result;
}
#include "activatemodsdialog.h"
#include "ui_activatemodsdialog.h"
#include <QComboBox>
#include <QLabel>
ActivateModsDialog::ActivateModsDialog(const std::map<QString, std::vector<QString> > &missingPlugins, QWidget *parent)
: TutorableDialog("ActivateMods", parent), ui(new Ui::ActivateModsDialog)
{
ui->setupUi(this);
QTableWidget *modsTable = findChild<QTableWidget*>("modsTable");
QHeaderView *headerView = modsTable->horizontalHeader();
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
headerView->setSectionResizeMode(0, QHeaderView::Stretch);
headerView->setSectionResizeMode(1, QHeaderView::Interactive);
#else
headerView->setResizeMode(0, QHeaderView::Stretch);
headerView->setResizeMode(1, QHeaderView::Interactive);
#endif
int row = 0;
modsTable->setRowCount(missingPlugins.size());
for (std::map<QString, std::vector<QString> >::const_iterator espIter = missingPlugins.begin();
espIter != missingPlugins.end(); ++espIter, ++row) {
modsTable->setCellWidget(row, 0, new QLabel(espIter->first));
if (espIter->second.size() == 0) {
modsTable->setCellWidget(row, 1, new QLabel(tr("not found")));
} else {
QComboBox* combo = new QComboBox();
for (std::vector<QString>::const_iterator modIter = espIter->second.begin();
modIter != espIter->second.end(); ++modIter) {
combo->addItem(*modIter);
}
modsTable->setCellWidget(row, 1, combo);
}
}
}
ActivateModsDialog::~ActivateModsDialog()
{
delete ui;
}
std::set<QString> ActivateModsDialog::getModsToActivate()
{
std::set<QString> result;
QTableWidget *modsTable = findChild<QTableWidget*>("modsTable");
for (int row = 0; row < modsTable->rowCount(); ++row) {
QComboBox *comboBox = dynamic_cast<QComboBox*>(modsTable->cellWidget(row, 1));
if (comboBox != NULL) {
result.insert(comboBox->currentText());
}
}
return result;
}
std::set<QString> ActivateModsDialog::getESPsToActivate()
{
std::set<QString> result;
QTableWidget *modsTable = findChild<QTableWidget*>("modsTable");
for (int row = 0; row < modsTable->rowCount(); ++row) {
QComboBox *comboBox = dynamic_cast<QComboBox*>(modsTable->cellWidget(row, 1));
if (comboBox != NULL) {
QLabel *espName = dynamic_cast<QLabel*>(modsTable->cellWidget(row, 0));
result.insert(espName->text());
}
}
return result;
}
-1
View File
@@ -62,7 +62,6 @@ public:
std::set<QString> getESPsToActivate();
private slots:
void on_buttonBox_accepted();
private:
Ui::ActivateModsDialog *ui;
-98
View File
@@ -1,98 +0,0 @@
/*
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/>.
*/
#include "archivetree.h"
#include <QDragMoveEvent>
ArchiveTree::ArchiveTree(QWidget *parent) :
QTreeWidget(parent)
{
}
bool ArchiveTree::testMovePossible(QTreeWidgetItem *source, QTreeWidgetItem *target)
{
if ((target == NULL) ||
(source == NULL)) {
return false;
}
if ((source == target) ||
(source->parent() == target)) {
return false;
}
return true;
}
void ArchiveTree::dragEnterEvent(QDragEnterEvent *event)
{
QTreeWidgetItem *source = this->currentItem();
if ((source == NULL) || (source->parent() == NULL)) {
// can't change top level
event->ignore();
return;
} else {
QTreeWidget::dragEnterEvent(event);
}
}
void ArchiveTree::dragMoveEvent(QDragMoveEvent *event)
{
if (!testMovePossible(this->currentItem(), itemAt(event->pos()))) {
event->ignore();
} else {
QTreeWidget::dragMoveEvent(event);
}
}
void ArchiveTree::dropEvent(QDropEvent *event)
{
event->ignore();
QTreeWidgetItem *target = itemAt(event->pos());
QList<QTreeWidgetItem*> sourceItems = this->selectedItems();
for (QList<QTreeWidgetItem*>::iterator iter = sourceItems.begin();
iter != sourceItems.end(); ++iter) {
QTreeWidgetItem *source = *iter;
if ((source->parent() != NULL) &&
testMovePossible(source, target)) {
source->parent()->removeChild(source);
if (target->data(0, Qt::UserRole).toInt() != 0) {
// target is a file
if (target->parent() == NULL) {
// this should really not happen, how should a
// file get to the top level?
return;
}
int index = target->parent()->indexOfChild(target);
target->parent()->insertChild(index, source);
emit changed();
} else {
// target is a directory
target->insertChild(target->childCount(), source);
emit changed();
}
}
}
}
-55
View File
@@ -1,55 +0,0 @@
/*
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 ARCHIVETREE_H
#define ARCHIVETREE_H
#include <QTreeWidget>
/**
* @brief QT tree widget used to display the content of an archive in the manual installation dialog
**/
class ArchiveTree : public QTreeWidget
{
Q_OBJECT
public:
explicit ArchiveTree(QWidget *parent = 0);
signals:
void changed();
public slots:
protected:
virtual void dragEnterEvent(QDragEnterEvent *event);
virtual void dragMoveEvent(QDragMoveEvent *event);
virtual void dropEvent(QDropEvent *event);
private:
bool testMovePossible(QTreeWidgetItem *source, QTreeWidgetItem *target);
};
#endif // ARCHIVETREE_H
-124
View File
@@ -1,124 +0,0 @@
/*
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/>.
*/
#include "baincomplexinstallerdialog.h"
#include "textviewer.h"
#include "ui_baincomplexinstallerdialog.h"
#include <QDir>
using namespace MOBase;
BainComplexInstallerDialog::BainComplexInstallerDialog(DirectoryTree *tree, const QString &modName, bool hasPackageTXT, QWidget *parent)
: TutorableDialog("BainInstaller", parent), ui(new Ui::BainComplexInstallerDialog), m_Manual(false)
{
ui->setupUi(this);
ui->nameEdit->setText(modName);
for (DirectoryTree::const_node_iterator iter = tree->nodesBegin(); iter != tree->nodesEnd(); ++iter) {
const QString &dirName = (*iter)->getData().name;
if ((dirName.compare("fomod", Qt::CaseInsensitive) == 0) ||
(dirName.startsWith("--"))) {
continue;
}
QListWidgetItem *item = new QListWidgetItem(ui->optionsList);
item->setText((*iter)->getData().name);
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
item->setCheckState(item->text().mid(0, 2) == "00" ? Qt::Checked : Qt::Unchecked);
item->setData(Qt::UserRole, qVariantFromValue((void*)(*iter)));
ui->optionsList->addItem(item);
}
ui->packageBtn->setEnabled(hasPackageTXT);
}
BainComplexInstallerDialog::~BainComplexInstallerDialog()
{
delete ui;
}
QString BainComplexInstallerDialog::getName() const
{
return ui->nameEdit->text();
}
void BainComplexInstallerDialog::moveTreeUp(DirectoryTree *target, DirectoryTree::Node *child)
{
for (DirectoryTree::const_node_iterator iter = child->nodesBegin();
iter != child->nodesEnd();) {
target->addNode(*iter, true);
iter = child->detach(iter);
}
for (DirectoryTree::const_leaf_reverse_iterator iter = child->leafsRBegin();
iter != child->leafsREnd(); ++iter) {
target->addLeaf(*iter);
}
}
DirectoryTree *BainComplexInstallerDialog::updateTree(DirectoryTree *tree)
{
DirectoryTree *newTree = new DirectoryTree;
for (DirectoryTree::const_node_reverse_iterator iter = tree->nodesRBegin();
iter != tree->nodesREnd();) {
QList<QListWidgetItem*> items = ui->optionsList->findItems((*iter)->getData().name, Qt::MatchFixedString);
if ((items.count() == 1) && (items.at(0)->checkState() == Qt::Checked)) {
moveTreeUp(newTree, *iter);
}
iter = tree->erase(iter);
}
return newTree;
}
void BainComplexInstallerDialog::on_okBtn_clicked()
{
this->accept();
}
void BainComplexInstallerDialog::on_cancelBtn_clicked()
{
this->reject();
}
void BainComplexInstallerDialog::on_manualBtn_clicked()
{
m_Manual = true;
this->reject();
}
void BainComplexInstallerDialog::on_packageBtn_clicked()
{
TextViewer viewer("package.txt", this);
viewer.setDescription("");
viewer.addFile(QDir::tempPath().append("/package.txt"), false);
viewer.exec();
}
-95
View File
@@ -1,95 +0,0 @@
/*
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 BAINCOMPLEXINSTALLERDIALOG_H
#define BAINCOMPLEXINSTALLERDIALOG_H
#include "mytree.h"
#include "installdialog.h"
#include "tutorabledialog.h"
namespace Ui {
class BainComplexInstallerDialog;
}
/**
* @brief Dialog to choose from options offered by a (complex) bain package
**/
class BainComplexInstallerDialog : public MOBase::TutorableDialog
{
Q_OBJECT
public:
/**
* @brief Constructor
*
* @param tree the directory tree of the archive. The caller is resonsible to verify this actually qualifies as a bain installer
* @param modName proposed name for the mod. The dialog allows the user to change this
* @param hasPackageTXT set to true if a package.txt is available for this archive. The file has to be unpacked to QDir::tempPath before displaying the dialog!
* @param parent parent widget
**/
explicit BainComplexInstallerDialog(MOBase::DirectoryTree *tree, const QString &modName, bool hasPackageTXT, QWidget *parent);
~BainComplexInstallerDialog();
/**
* @return bool true if the user requested the manual dialog
**/
bool manualRequested() const { return m_Manual; }
/**
* @return QString the (user-modified) name to be used for the mod
**/
QString getName() const;
/**
* @brief retrieve the updated archive tree from the dialog. The caller is responsible to delete the returned tree.
*
* @note This call is destructive on the input tree!
*
* @param tree input tree. (TODO isn't this the same as the tree passed in the constructor?)
* @return DataTree* a new tree with only the selected options and directories arranged correctly. The caller takes custody of this pointer!
**/
MOBase::DirectoryTree *updateTree(MOBase::DirectoryTree *tree);
private slots:
void on_manualBtn_clicked();
void on_okBtn_clicked();
void on_cancelBtn_clicked();
void on_packageBtn_clicked();
private:
void moveTreeUp(MOBase::DirectoryTree *target, MOBase::DirectoryTree::Node *child);
private:
Ui::BainComplexInstallerDialog *ui;
bool m_Manual;
};
#endif // BAINCOMPLEXINSTALLERDIALOG_H
+192 -190
View File
@@ -17,193 +17,195 @@ You should have received a copy of the GNU General Public License
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "bbcode.h"
#include <QRegExp>
#include <map>
#include <algorithm>
namespace BBCode {
class BBCodeMap {
typedef std::map<QString, std::pair<QRegExp, QString> > TagMap;
public:
static BBCodeMap &instance() {
static BBCodeMap s_Instance;
return s_Instance;
}
QString convertTag(const QString &input, int &length)
{
// extract the tag name
m_TagNameExp.indexIn(input, 1, QRegExp::CaretAtOffset);
QString tagName = m_TagNameExp.cap(0).toLower();
//qDebug("tag name %s", tagName.toUtf8().constData());
TagMap::iterator tagIter = m_TagMap.find(tagName);
if (tagIter != m_TagMap.end()) {
// recognized tag
if (tagName.endsWith('=')) {
tagName.chop(1);
}
QString closeTag = tagName == "*" ? "<br/>"
: QString("[/%1]").arg(tagName);
int closeTagPos = input.indexOf(closeTag, 0, Qt::CaseInsensitive);
//qDebug("close tag %s at %d", closeTag.toUtf8().constData(), closeTagPos);
if (closeTagPos > -1) {
length = closeTagPos + closeTag.length();
QString temp = input.mid(0, length);
if (tagIter->second.first.indexIn(temp) == 0) {
return temp.replace(tagIter->second.first, tagIter->second.second);
} else {
// expression doesn't match. either the input string is invalid
// or the expression is
qWarning("%s doesn't match the expression for %s",
temp.toUtf8().constData(), tagName.toUtf8().constData());
length = 0;
return QString();
}
}
}
// not a recognized tag or tag invalid
length = 0;
return QString();
}
private:
BBCodeMap()
: m_TagNameExp("^[a-zA-Z*]*=?")
{
m_TagMap["b"] = std::make_pair(QRegExp("\\[b\\](.*)\\[/b\\]"),
"<b>\\1</b>");
m_TagMap["i"] = std::make_pair(QRegExp("\\[i\\](.*)\\[/i\\]"),
"<i>\\1</i>");
m_TagMap["u"] = std::make_pair(QRegExp("\\[u\\](.*)\\[/u\\]"),
"<u>\\1</u>");
m_TagMap["s"] = std::make_pair(QRegExp("\\[s\\](.*)\\[/s\\]"),
"<s>\\1</s>");
m_TagMap["sub"] = std::make_pair(QRegExp("\\[sub\\](.*)\\[/sub\\]"),
"<sub>\\1</sub>");
m_TagMap["sup"] = std::make_pair(QRegExp("\\[sup\\](.*)\\[/sup\\]"),
"<sup>\\1</sup>");
m_TagMap["size="] = std::make_pair(QRegExp("\\[size=([^\\]]*)\\](.*)\\[/size\\]"),
"<font size=\"\\1\">\\2</font>");
m_TagMap["color="] = std::make_pair(QRegExp("\\[color=([^\\]]*)\\](.*)\\[/color\\]"),
"<font style=\"color: #\\1;\">\\2</font>");
m_TagMap["font="] = std::make_pair(QRegExp("\\[font=([^\\]]*)\\](.*)\\[/font\\]"),
"<font face=\\1>\\2</font>");
m_TagMap["center"] = std::make_pair(QRegExp("\\[center\\](.*)\\[/center\\]"),
"<div align=\"center\">\\1</div>");
m_TagMap["quote"] = std::make_pair(QRegExp("\\[quote\\](.*)\\[/quote\\]"),
"<blockquote>\"\\1\"</blockquote>");
m_TagMap["quote="] = std::make_pair(QRegExp("\\[quote=([^\\]]*)\\](.*)\\[/quote\\]"),
"<blockquote>\"\\2\"<br/><span>--\\1</span></blockquote></p>");
m_TagMap["code"] = std::make_pair(QRegExp("\\[code\\](.*)\\[/code\\]"),
"<pre>\\1</pre>");
m_TagMap["heading"]= std::make_pair(QRegExp("\\[heading\\](.*)\\[/heading\\]"),
"<h2><strong>\\1</strong></h2>");
// lists
m_TagMap["list"] = std::make_pair(QRegExp("\\[list\\](.*)\\[/list\\]"),
"<ul>\\1</ul>");
m_TagMap["list="] = std::make_pair(QRegExp("\\[list.*\\](.*)\\[/list\\]"),
"<ol>\\1</ol>");
m_TagMap["ul"] = std::make_pair(QRegExp("\\[ul\\](.*)\\[/ul\\]"),
"<ul>\\1</ul>");
m_TagMap["ol"] = std::make_pair(QRegExp("\\[ol\\](.*)\\[/ol\\]"),
"<ol>\\1</ol>");
m_TagMap["li"] = std::make_pair(QRegExp("\\[li\\](.*)\\[/li\\]"),
"<li>\\1</li>");
m_TagMap["*"] = std::make_pair(QRegExp("\\[\\*\\](.*)<br/>"),
"<li>\\1</li>");
// tables
m_TagMap["table"] = std::make_pair(QRegExp("\\[table\\](.*)\\[/table\\]"),
"<table>\\1</table>");
m_TagMap["tr"] = std::make_pair(QRegExp("\\[tr\\](.*)\\[/tr\\]"),
"<tr>\\1</tr>");
m_TagMap["th"] = std::make_pair(QRegExp("\\[th\\](.*)\\[/th\\]"),
"<th>\\1</th>");
m_TagMap["td"] = std::make_pair(QRegExp("\\[td\\](.*)\\[/td\\]"),
"<td>\\1</td>");
// web content
m_TagMap["url"] = std::make_pair(QRegExp("\\[url\\](.*)\\[/url\\]"),
"<a href=\"\\1\">\\1</a>");
m_TagMap["url="] = std::make_pair(QRegExp("\\[url=([^\\]]*)\\](.*)\\[/url\\]"),
"<a href=\"\\1\">\\2</a>");
m_TagMap["img"] = std::make_pair(QRegExp("\\[img\\](.*)\\[/img\\]"),
"<img src=\"\\1\"/>");
m_TagMap["img="] = std::make_pair(QRegExp("\\[img=([^\\]]*)\\](.*)\\[/img\\]"),
"<img src=\"\\2\" align=\"\\1\" />");
m_TagMap["email="] = std::make_pair(QRegExp("\\[email=\"?([^\\]]*)\"?\\](.*)\\[/email\\]"),
"<a href=\"mailto:\\1\">\\2</a>");
m_TagMap["youtube"] = std::make_pair(QRegExp("\\[youtube\\](.*)\\[/youtube\\]"),
"<a href=\"http://www.youtube.com/v/\\1\">http://www.youtube.com/v/\\1</a>");
// make all patterns non-greedy and case-insensitive
for (TagMap::iterator iter = m_TagMap.begin(); iter != m_TagMap.end(); ++iter) {
iter->second.first.setCaseSensitivity(Qt::CaseInsensitive);
iter->second.first.setMinimal(true);
}
}
private:
QRegExp m_TagNameExp;
TagMap m_TagMap;
};
QString convertToHTML(const QString &inputParam)
{
// this code goes over the input string once and replaces all bbtags
// it encounters. This function is called recursively for every replaced
// string to convert nested tags.
//
// This could be implemented simpler by applying a set of regular expressions
// for each recognized bb-tag one after the other but that would probably be
// very inefficient (O(n^2)).
QString input = inputParam.mid(0).replace("\r\n", "<br/>");
input.replace("\\\"", "\"").replace("\\'", "'");
QString result;
int lastBlock = 0;
int pos = 0;
// iterate over the input buffer
while ((pos = input.indexOf('[', lastBlock)) != -1) {
// append everything between the previous tag-block and the current one
result.append(input.midRef(lastBlock, pos - lastBlock));
// convert the tag and content if necessary
int length = -1;
QString replacement = BBCodeMap::instance().convertTag(input.mid(pos), length);
if (length != 0) {
QString temp = convertToHTML(replacement);
result.append(temp);
// length contains the number of characters in the original tag
pos += length;
} else {
// nothing replaced
result.append('[');
++pos;
}
lastBlock = pos;
}
// append the remainder (everything after the last tag)
result.append(input.midRef(lastBlock));
return result;
}
} // namespace BBCode
#include "bbcode.h"
#include <QRegExp>
#include <map>
#include <algorithm>
namespace BBCode {
class BBCodeMap {
typedef std::map<QString, std::pair<QRegExp, QString> > TagMap;
public:
static BBCodeMap &instance() {
static BBCodeMap s_Instance;
return s_Instance;
}
QString convertTag(const QString &input, int &length)
{
// extract the tag name
m_TagNameExp.indexIn(input, 1, QRegExp::CaretAtOffset);
QString tagName = m_TagNameExp.cap(0).toLower();
//qDebug("tag name %s", tagName.toUtf8().constData());
TagMap::iterator tagIter = m_TagMap.find(tagName);
if (tagIter != m_TagMap.end()) {
// recognized tag
if (tagName.endsWith('=')) {
tagName.chop(1);
}
QString closeTag = tagName == "*" ? "<br/>"
: QString("[/%1]").arg(tagName);
int closeTagPos = input.indexOf(closeTag, 0, Qt::CaseInsensitive);
//qDebug("close tag %s at %d", closeTag.toUtf8().constData(), closeTagPos);
if (closeTagPos > -1) {
length = closeTagPos + closeTag.length();
QString temp = input.mid(0, length);
if (tagIter->second.first.indexIn(temp) == 0) {
return temp.replace(tagIter->second.first, tagIter->second.second);
} else {
// expression doesn't match. either the input string is invalid
// or the expression is
qWarning("%s doesn't match the expression for %s",
temp.toUtf8().constData(), tagName.toUtf8().constData());
length = 0;
return QString();
}
}
}
// not a recognized tag or tag invalid
length = 0;
return QString();
}
private:
BBCodeMap()
: m_TagNameExp("^[a-zA-Z*]*=?")
{
m_TagMap["b"] = std::make_pair(QRegExp("\\[b\\](.*)\\[/b\\]"),
"<b>\\1</b>");
m_TagMap["i"] = std::make_pair(QRegExp("\\[i\\](.*)\\[/i\\]"),
"<i>\\1</i>");
m_TagMap["u"] = std::make_pair(QRegExp("\\[u\\](.*)\\[/u\\]"),
"<u>\\1</u>");
m_TagMap["s"] = std::make_pair(QRegExp("\\[s\\](.*)\\[/s\\]"),
"<s>\\1</s>");
m_TagMap["sub"] = std::make_pair(QRegExp("\\[sub\\](.*)\\[/sub\\]"),
"<sub>\\1</sub>");
m_TagMap["sup"] = std::make_pair(QRegExp("\\[sup\\](.*)\\[/sup\\]"),
"<sup>\\1</sup>");
m_TagMap["size="] = std::make_pair(QRegExp("\\[size=([^\\]]*)\\](.*)\\[/size\\]"),
"<font size=\"\\1\">\\2</font>");
m_TagMap["color="] = std::make_pair(QRegExp("\\[color=([^\\]]*)\\](.*)\\[/color\\]"),
"<font style=\"color: #\\1;\">\\2</font>");
m_TagMap["font="] = std::make_pair(QRegExp("\\[font=([^\\]]*)\\](.*)\\[/font\\]"),
"<font face=\\1>\\2</font>");
m_TagMap["center"] = std::make_pair(QRegExp("\\[center\\](.*)\\[/center\\]"),
"<div align=\"center\">\\1</div>");
m_TagMap["quote"] = std::make_pair(QRegExp("\\[quote\\](.*)\\[/quote\\]"),
"<blockquote>\"\\1\"</blockquote>");
m_TagMap["quote="] = std::make_pair(QRegExp("\\[quote=([^\\]]*)\\](.*)\\[/quote\\]"),
"<blockquote>\"\\2\"<br/><span>--\\1</span></blockquote></p>");
m_TagMap["code"] = std::make_pair(QRegExp("\\[code\\](.*)\\[/code\\]"),
"<pre>\\1</pre>");
m_TagMap["heading"]= std::make_pair(QRegExp("\\[heading\\](.*)\\[/heading\\]"),
"<h2><strong>\\1</strong></h2>");
// lists
m_TagMap["list"] = std::make_pair(QRegExp("\\[list\\](.*)\\[/list\\]"),
"<ul>\\1</ul>");
m_TagMap["list="] = std::make_pair(QRegExp("\\[list.*\\](.*)\\[/list\\]"),
"<ol>\\1</ol>");
m_TagMap["ul"] = std::make_pair(QRegExp("\\[ul\\](.*)\\[/ul\\]"),
"<ul>\\1</ul>");
m_TagMap["ol"] = std::make_pair(QRegExp("\\[ol\\](.*)\\[/ol\\]"),
"<ol>\\1</ol>");
m_TagMap["li"] = std::make_pair(QRegExp("\\[li\\](.*)\\[/li\\]"),
"<li>\\1</li>");
m_TagMap["*"] = std::make_pair(QRegExp("\\[\\*\\](.*)<br/>"),
"<li>\\1</li>");
// tables
m_TagMap["table"] = std::make_pair(QRegExp("\\[table\\](.*)\\[/table\\]"),
"<table>\\1</table>");
m_TagMap["tr"] = std::make_pair(QRegExp("\\[tr\\](.*)\\[/tr\\]"),
"<tr>\\1</tr>");
m_TagMap["th"] = std::make_pair(QRegExp("\\[th\\](.*)\\[/th\\]"),
"<th>\\1</th>");
m_TagMap["td"] = std::make_pair(QRegExp("\\[td\\](.*)\\[/td\\]"),
"<td>\\1</td>");
// web content
m_TagMap["url"] = std::make_pair(QRegExp("\\[url\\](.*)\\[/url\\]"),
"<a href=\"\\1\">\\1</a>");
m_TagMap["url="] = std::make_pair(QRegExp("\\[url=([^\\]]*)\\](.*)\\[/url\\]"),
"<a href=\"\\1\">\\2</a>");
/* m_TagMap["img"] = std::make_pair(QRegExp("\\[img\\](.*)\\[/img\\]"),
"<img src=\"\\1\"/>");
m_TagMap["img="] = std::make_pair(QRegExp("\\[img=([^\\]]*)\\](.*)\\[/img\\]"),
"<img src=\"\\2\" align=\"\\1\" />");*/
m_TagMap["img"] = std::make_pair(QRegExp("\\[img\\](.*)\\[/img\\]"), "");
m_TagMap["img="] = std::make_pair(QRegExp("\\[img=([^\\]]*)\\](.*)\\[/img\\]"), "");
m_TagMap["email="] = std::make_pair(QRegExp("\\[email=\"?([^\\]]*)\"?\\](.*)\\[/email\\]"),
"<a href=\"mailto:\\1\">\\2</a>");
m_TagMap["youtube"] = std::make_pair(QRegExp("\\[youtube\\](.*)\\[/youtube\\]"),
"<a href=\"http://www.youtube.com/v/\\1\">http://www.youtube.com/v/\\1</a>");
// make all patterns non-greedy and case-insensitive
for (TagMap::iterator iter = m_TagMap.begin(); iter != m_TagMap.end(); ++iter) {
iter->second.first.setCaseSensitivity(Qt::CaseInsensitive);
iter->second.first.setMinimal(true);
}
}
private:
QRegExp m_TagNameExp;
TagMap m_TagMap;
};
QString convertToHTML(const QString &inputParam)
{
// this code goes over the input string once and replaces all bbtags
// it encounters. This function is called recursively for every replaced
// string to convert nested tags.
//
// This could be implemented simpler by applying a set of regular expressions
// for each recognized bb-tag one after the other but that would probably be
// very inefficient (O(n^2)).
QString input = inputParam.mid(0).replace("\r\n", "<br/>");
input.replace("\\\"", "\"").replace("\\'", "'");
QString result;
int lastBlock = 0;
int pos = 0;
// iterate over the input buffer
while ((pos = input.indexOf('[', lastBlock)) != -1) {
// append everything between the previous tag-block and the current one
result.append(input.midRef(lastBlock, pos - lastBlock));
// convert the tag and content if necessary
int length = -1;
QString replacement = BBCodeMap::instance().convertTag(input.mid(pos), length);
if (length != 0) {
QString temp = convertToHTML(replacement);
result.append(temp);
// length contains the number of characters in the original tag
pos += length;
} else {
// nothing replaced
result.append('[');
++pos;
}
lastBlock = pos;
}
// append the remainder (everything after the last tag)
result.append(input.midRef(lastBlock));
return result;
}
} // namespace BBCode
+21 -21
View File
@@ -17,24 +17,24 @@ 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 BBCODE_H
#define BBCODE_H
#include <QString>
namespace BBCode {
/**
* @brief convert a string with BB Code-Tags to HTML
* @param input the input string with BB tags
* @param replaceOccured if not NULL, this parameter will be set to true if any bb tags were replaced
* @return the same string in html representation
**/
QString convertToHTML(const QString &input);
}
#endif // BBCODE_H
#ifndef BBCODE_H
#define BBCODE_H
#include <QString>
namespace BBCode {
/**
* @brief convert a string with BB Code-Tags to HTML
* @param input the input string with BB tags
* @param replaceOccured if not NULL, this parameter will be set to true if any bb tags were replaced
* @return the same string in html representation
**/
QString convertToHTML(const QString &input);
}
#endif // BBCODE_H
+28 -2
View File
@@ -25,6 +25,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QFile>
#include <QDir>
#include <QList>
#include <QCoreApplication>
using namespace MOBase;
@@ -34,11 +35,18 @@ using namespace MOShared;
CategoryFactory* CategoryFactory::s_Instance = NULL;
QString CategoryFactory::categoriesFilePath()
{
return QCoreApplication::applicationDirPath() + "/categories.dat";
}
CategoryFactory::CategoryFactory()
{
atexit(&cleanup);
reset();
QFile categoryFile(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOrganizerDirectory())).append("/categories.dat"));
QFile categoryFile(categoriesFilePath());
if (!categoryFile.open(QIODevice::ReadOnly)) {
loadDefaultCategories();
@@ -117,10 +125,16 @@ void CategoryFactory::setParents()
}
}
void CategoryFactory::cleanup()
{
delete s_Instance;
s_Instance = NULL;
}
void CategoryFactory::saveCategories()
{
QFile categoryFile(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOrganizerDirectory())).append("/categories.dat"));
QFile categoryFile(categoriesFilePath());
if (!categoryFile.open(QIODevice::WriteOnly)) {
reportError(QObject::tr("Failed to save custom categories"));
@@ -144,6 +158,18 @@ void CategoryFactory::saveCategories()
}
unsigned int CategoryFactory::countCategories(std::tr1::function<bool (const Category &category)> filter)
{
unsigned int result = 0;
for (auto iter = m_Categories.begin(); iter != m_Categories.end(); ++iter) {
if (filter(*iter)) {
++result;
}
}
return result;
}
void CategoryFactory::addCategory(int id, const QString &name, const std::vector<int> &nexusIDs, int parentID)
{
int index = m_Categories.size();
+179 -161
View File
@@ -17,164 +17,182 @@ 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 CATEGORIES_H
#define CATEGORIES_H
#include <QString>
#include <vector>
#include <map>
/**
* @brief Manage the available mod categories
* @warning member functions of this class currently use a wild mix of ids and indexes to look up categories,
* optimized to where the request comes from. Therefore be very careful which of the two you have available
**/
class CategoryFactory {
friend class CategoriesDialog;
public:
static const int CATEGORY_NONE = 0;
static const int CATEGORY_SPECIAL_FIRST = 10000;
static const int CATEGORY_SPECIAL_CHECKED = CATEGORY_SPECIAL_FIRST;
static const int CATEGORY_SPECIAL_UNCHECKED = 10001;
static const int CATEGORY_SPECIAL_UPDATEAVAILABLE = 10002;
static const int CATEGORY_SPECIAL_NOCATEGORY = 10003;
static const int CATEGORY_SPECIAL_CONFLICT = 10004;
public:
/**
* @brief reset the list of categories
**/
void reset();
/**
* @brief save the categories to the categories.dat file
**/
void saveCategories();
/**
* @brief retrieve the number of available categories
*
* @return unsigned int number of categories
**/
unsigned numCategories() const { return m_Categories.size(); }
/**
* @brief get the id of the parent category
*
* @param index the index to look up
* @return int id of the parent category
**/
int getParentID(unsigned int index) const;
/**
* @brief determine if a category exists (by id)
*
* @param id the id to check for existance
* @return true if the category exists, false otherwise
**/
bool categoryExists(int id) const;
/**
* @brief test if a category is child of a second one
* @param id the presumed child id
* @param parentID the parent id to test for
* @return true if id is a child of parentID
**/
bool isDecendantOf(int id, int parentID) const;
/**
* @brief test if the specified category has child categories
*
* @param index index of the category to look up
* @return bool true if the category has child categories
**/
bool hasChildren(unsigned int index) const;
/**
* @brief retrieve the name of a category
*
* @param index index of the category to look up
* @return QString name of the category
**/
QString getCategoryName(unsigned int index) const;
/**
* @brief look up the id of a category by its index
*
* @param index index of the category to look up
* @return int id of the category
**/
int getCategoryID(unsigned int index) const;
/**
* @brief look up the index of a category by its id
*
* @param id index of the category to look up
* @return unsigned int index of the category
**/
int getCategoryIndex(int ID) const;
/**
* @brief retrieve the index of a category by its nexus id
*
* @param nexusID nexus id of the category to look up
* @return unsigned int index of the category or 0 if no category matches
**/
unsigned int resolveNexusID(int nexusID) const;
public:
/**
* @brief retrieve a reference to the singleton instance
*
* @return the reference to the singleton
**/
static CategoryFactory &instance();
private:
struct Category {
Category(int sortValue, int id, const QString &name, const std::vector<int> &nexusIDs, int parentID)
: m_SortValue(sortValue), m_ID(id), m_Name(name), m_HasChildren(false),
m_NexusIDs(nexusIDs), m_ParentID(parentID) {}
int m_SortValue;
int m_ID;
int m_ParentID;
bool m_HasChildren;
QString m_Name;
std::vector<int> m_NexusIDs;
friend bool operator<(const Category &LHS, const Category &RHS) {
return LHS.m_SortValue < RHS.m_SortValue;
}
};
private:
CategoryFactory();
void loadDefaultCategories();
void addCategory(int id, const QString &name, const std::vector<int> &nexusID, int parentID);
void setParents();
private:
static CategoryFactory *s_Instance;
std::vector<Category> m_Categories;
std::map<int, unsigned int> m_IDMap;
std::map<int, unsigned int> m_NexusMap;
};
#endif // CATEGORIES_H
#ifndef CATEGORIES_H
#define CATEGORIES_H
#include <QString>
#include <vector>
#include <map>
#include <functional>
/**
* @brief Manage the available mod categories
* @warning member functions of this class currently use a wild mix of ids and indexes to look up categories,
* optimized to where the request comes from. Therefore be very careful which of the two you have available
**/
class CategoryFactory {
friend class CategoriesDialog;
public:
static const int CATEGORY_NONE = 0;
static const int CATEGORY_SPECIAL_FIRST = 10000;
static const int CATEGORY_SPECIAL_CHECKED = CATEGORY_SPECIAL_FIRST;
static const int CATEGORY_SPECIAL_UNCHECKED = 10001;
static const int CATEGORY_SPECIAL_UPDATEAVAILABLE = 10002;
static const int CATEGORY_SPECIAL_NOCATEGORY = 10003;
static const int CATEGORY_SPECIAL_CONFLICT = 10004;
static const int CATEGORY_SPECIAL_NOTENDORSED = 10005;
public:
struct Category {
Category(int sortValue, int id, const QString &name, const std::vector<int> &nexusIDs, int parentID)
: m_SortValue(sortValue), m_ID(id), m_Name(name), m_HasChildren(false),
m_NexusIDs(nexusIDs), m_ParentID(parentID) {}
int m_SortValue;
int m_ID;
int m_ParentID;
bool m_HasChildren;
QString m_Name;
std::vector<int> m_NexusIDs;
friend bool operator<(const Category &LHS, const Category &RHS) {
return LHS.m_SortValue < RHS.m_SortValue;
}
};
public:
/**
* @brief reset the list of categories
**/
void reset();
/**
* @brief save the categories to the categories.dat file
**/
void saveCategories();
/**
* @brief retrieve the number of available categories
*
* @return unsigned int number of categories
**/
unsigned numCategories() const { return m_Categories.size(); }
/**
* @brief count all categories that match a specified filter
* @param filter the filter to test
* @return number of matching categories
*/
unsigned int countCategories(std::tr1::function<bool (const Category &category)> filter);
/**
* @brief get the id of the parent category
*
* @param index the index to look up
* @return int id of the parent category
**/
int getParentID(unsigned int index) const;
/**
* @brief determine if a category exists (by id)
*
* @param id the id to check for existance
* @return true if the category exists, false otherwise
**/
bool categoryExists(int id) const;
/**
* @brief test if a category is child of a second one
* @param id the presumed child id
* @param parentID the parent id to test for
* @return true if id is a child of parentID
**/
bool isDecendantOf(int id, int parentID) const;
/**
* @brief test if the specified category has child categories
*
* @param index index of the category to look up
* @return bool true if the category has child categories
**/
bool hasChildren(unsigned int index) const;
/**
* @brief retrieve the name of a category
*
* @param index index of the category to look up
* @return QString name of the category
**/
QString getCategoryName(unsigned int index) const;
/**
* @brief look up the id of a category by its index
*
* @param index index of the category to look up
* @return int id of the category
**/
int getCategoryID(unsigned int index) const;
/**
* @brief look up the index of a category by its id
*
* @param id index of the category to look up
* @return unsigned int index of the category
**/
int getCategoryIndex(int ID) const;
/**
* @brief retrieve the index of a category by its nexus id
*
* @param nexusID nexus id of the category to look up
* @return unsigned int index of the category or 0 if no category matches
**/
unsigned int resolveNexusID(int nexusID) const;
public:
/**
* @brief retrieve a reference to the singleton instance
*
* @return the reference to the singleton
**/
static CategoryFactory &instance();
/**
* @return path to the file that contains the categories list
*/
static QString categoriesFilePath();
private:
CategoryFactory();
void loadDefaultCategories();
void addCategory(int id, const QString &name, const std::vector<int> &nexusID, int parentID);
void setParents();
static void cleanup();
private:
static CategoryFactory *s_Instance;
std::vector<Category> m_Categories;
std::map<int, unsigned int> m_IDMap;
std::map<int, unsigned int> m_NexusMap;
private:
};
#endif // CATEGORIES_H
+1 -1
View File
@@ -164,7 +164,7 @@ void CategoriesDialog::fillTable()
CategoryFactory &categories = CategoryFactory::instance();
QTableWidget *table = ui->categoriesTable;
#if QT_VERSION >= 0x050000
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
table->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
table->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Fixed);
+5
View File
@@ -33,6 +33,11 @@ DirectoryRefresher::DirectoryRefresher()
{
}
DirectoryRefresher::~DirectoryRefresher()
{
delete m_DirectoryStructure;
}
DirectoryEntry *DirectoryRefresher::getDirectoryStructure()
{
QMutexLocker locker(&m_RefreshLock);
+3 -1
View File
@@ -21,10 +21,10 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#define DIRECTORYREFRESHER_H
#include <QObject>
#include <directoryentry.h>
#include <vector>
#include <QMutex>
#include <tuple>
#include <directoryentry.h>
/**
@@ -43,6 +43,8 @@ public:
**/
DirectoryRefresher();
~DirectoryRefresher();
/**
* @brief retrieve the updated directory structure
*
+15
View File
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32" name="dlls" version="1.0.0.0" processorArchitecture="x86"/>
<file name="icuin49.dll"/>
<file name="icuuc49.dll"/>
<file name="icudt49.dll"/>
<file name="Qt5Cored.dll"/>
<file name="Qt5Declaratived.dll"/>
<file name="Qt5Guid.dll"/>
<file name="Qt5Networkd.dll"/>
<file name="Qt5Scriptd.dll"/>
<file name="Qt5Sqld.dll"/>
<file name="Qt5Widgetsd.dll"/>
<file name="Qt5XmlPatternsd.dll"/>
</assembly>
+17
View File
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32" name="dlls" version="1.0.0.0" processorArchitecture="x86"/>
<file name="icuin49.dll"/>
<file name="icuuc49.dll"/>
<file name="icudt49.dll"/>
<file name="Qt5Core.dll"/>
<file name="Qt5Declarative.dll"/>
<file name="Qt5Gui.dll"/>
<file name="Qt5Network.dll"/>
<file name="Qt5Script.dll"/>
<file name="Qt5Sql.dll"/>
<file name="Qt5Svg.dll"/>
<file name="Qt5Widgets.dll"/>
<file name="Qt5Xml.dll"/>
<file name="Qt5XmlPatterns.dll"/>
</assembly>
+90 -87
View File
@@ -17,90 +17,93 @@ You should have received a copy of the GNU General Public License
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "downloadlist.h"
#include "downloadmanager.h"
#include <QEvent>
#include <QSortFilterProxyModel>
DownloadList::DownloadList(DownloadManager *manager, QObject *parent)
: QAbstractTableModel(parent), m_Manager(manager)
{
connect(m_Manager, SIGNAL(update(int)), this, SLOT(update(int)));
connect(m_Manager, SIGNAL(aboutToUpdate()), this, SLOT(aboutToUpdate()));
}
int DownloadList::rowCount(const QModelIndex&) const
{
return m_Manager->numTotalDownloads();
}
int DownloadList::columnCount(const QModelIndex&) const
{
return 3;
}
QModelIndex DownloadList::index(int row, int column, const QModelIndex&) const
{
return createIndex(row, column, row);
}
QModelIndex DownloadList::parent(const QModelIndex&) const
{
return QModelIndex();
}
QVariant DownloadList::headerData(int section, Qt::Orientation orientation, int role) const
{
if ((role == Qt::DisplayRole) &&
(orientation == Qt::Horizontal)) {
switch (section) {
case 0: return tr("Name");
case 1: return tr("Filetime");
default: return tr("Done");
}
} else {
return QAbstractItemModel::headerData(section, orientation, role);
}
}
QVariant DownloadList::data(const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole) {
return index.row();
} else if (role == Qt::ToolTipRole) {
if (m_Manager->isInfoIncomplete(index.row())) {
return tr("Information missing, please select \"Query Info\" from the context menu to re-retrieve.");
} else {
NexusInfo info = m_Manager->getNexusInfo(index.row());
return QString("%1 (ID %2) %3").arg(info.m_ModName).arg(m_Manager->getModID(index.row())).arg(info.m_Version);
}
} else {
return QVariant();
}
}
void DownloadList::aboutToUpdate()
{
emit beginResetModel();
}
void DownloadList::update(int row)
{
if (row < 0) {
emit endResetModel();
} else if (row < this->rowCount()) {
emit dataChanged(this->index(row, 0, QModelIndex()), this->index(row, 1, QModelIndex()));
} else {
qCritical("invalid row %d in download list, update failed", row);
}
}
#include "downloadlist.h"
#include "downloadmanager.h"
#include <QEvent>
#include <QSortFilterProxyModel>
DownloadList::DownloadList(DownloadManager *manager, QObject *parent)
: QAbstractTableModel(parent), m_Manager(manager)
{
connect(m_Manager, SIGNAL(update(int)), this, SLOT(update(int)));
connect(m_Manager, SIGNAL(aboutToUpdate()), this, SLOT(aboutToUpdate()));
}
int DownloadList::rowCount(const QModelIndex&) const
{
return m_Manager->numTotalDownloads();
}
int DownloadList::columnCount(const QModelIndex&) const
{
return 3;
}
QModelIndex DownloadList::index(int row, int column, const QModelIndex&) const
{
return createIndex(row, column, row);
}
QModelIndex DownloadList::parent(const QModelIndex&) const
{
return QModelIndex();
}
QVariant DownloadList::headerData(int section, Qt::Orientation orientation, int role) const
{
if ((role == Qt::DisplayRole) &&
(orientation == Qt::Horizontal)) {
switch (section) {
case COL_NAME: return tr("Name");
case COL_FILETIME: return tr("Filetime");
default: return tr("Done");
}
} else {
return QAbstractItemModel::headerData(section, orientation, role);
}
}
QVariant DownloadList::data(const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole) {
return index.row();
} else if (role == Qt::ToolTipRole) {
QString text = m_Manager->getFileName(index.row()) + "\n";
if (m_Manager->isInfoIncomplete(index.row())) {
text += tr("Information missing, please select \"Query Info\" from the context menu to re-retrieve.");
} else {
NexusInfo info = m_Manager->getNexusInfo(index.row());
text += QString("%1 (ID %2) %3").arg(info.m_ModName).arg(m_Manager->getModID(index.row())).arg(info.m_Version);
}
return text;
} else {
return QVariant();
}
}
void DownloadList::aboutToUpdate()
{
emit beginResetModel();
}
void DownloadList::update(int row)
{
if (row < 0) {
emit endResetModel();
} else if (row < this->rowCount()) {
#pragma message("updating only the one column is a hack")
emit dataChanged(this->index(row, 2, QModelIndex()), this->index(row, 2, QModelIndex()));
} else {
qCritical("invalid row %d in download list, update failed", row);
}
}
+77 -73
View File
@@ -17,76 +17,80 @@ 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 DOWNLOADLIST_H
#define DOWNLOADLIST_H
#include <QAbstractTableModel>
class DownloadManager;
/**
* @brief model of the list of active and completed downloads
**/
class DownloadList : public QAbstractTableModel
{
Q_OBJECT
public:
/**
* @brief constructor
*
* @param manager the download manager processing downloads
* @param parent parent object Defaults to 0.
**/
explicit DownloadList(DownloadManager *manager, QObject *parent = 0);
/**
* @brief retrieve the number of rows to display. Invoked by Qt
*
* @param parent not relevant for this implementation
* @return number of rows to display
**/
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
virtual int columnCount(const QModelIndex &parent) const;
QModelIndex index(int row, int column, const QModelIndex &parent) const;
QModelIndex parent(const QModelIndex &child) const;
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
/**
* @brief retrieve the data to display in a specific row. Invoked by Qt
*
* @param index location to look up
* @param role ... Defaults to Qt::DisplayRole.
* @return this implementation only returns the row, the QItemDelegate implementation is expected to fetch its information from the DownloadManager
**/
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
signals:
public slots:
/**
* @brief used to inform the model that data has changed
*
* @param row the row that changed. This can be negative to update the whole view
**/
void update(int row);
void aboutToUpdate();
private:
private:
DownloadManager *m_Manager;
};
#endif // DOWNLOADLIST_H
#ifndef DOWNLOADLIST_H
#define DOWNLOADLIST_H
#include <QAbstractTableModel>
class DownloadManager;
/**
* @brief model of the list of active and completed downloads
**/
class DownloadList : public QAbstractTableModel
{
Q_OBJECT
public:
enum EColumn {
COL_NAME = 0,
COL_FILETIME,
COL_STATUS
};
public:
/**
* @brief constructor
*
* @param manager the download manager processing downloads
* @param parent parent object Defaults to 0.
**/
explicit DownloadList(DownloadManager *manager, QObject *parent = 0);
/**
* @brief retrieve the number of rows to display. Invoked by Qt
*
* @param parent not relevant for this implementation
* @return number of rows to display
**/
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
virtual int columnCount(const QModelIndex &parent) const;
QModelIndex index(int row, int column, const QModelIndex &parent) const;
QModelIndex parent(const QModelIndex &child) const;
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
/**
* @brief retrieve the data to display in a specific row. Invoked by Qt
*
* @param index location to look up
* @param role ... Defaults to Qt::DisplayRole.
* @return this implementation only returns the row, the QItemDelegate implementation is expected to fetch its information from the DownloadManager
**/
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
public slots:
/**
* @brief used to inform the model that data has changed
*
* @param row the row that changed. This can be negative to update the whole view
**/
void update(int row);
void aboutToUpdate();
private:
DownloadManager *m_Manager;
};
#endif // DOWNLOADLIST_H

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