Compare commits

..
Author SHA1 Message Date
Tannin 0eb1662a0e - very effective optimization to findfirstfile-calls
- several configuration files are now only saved to disk if the content actually changed.
  This should also get rid of a problem where plugins.txt was re-written immediately after starting the game
  (causing a conflict with the game)
- reduced "noise" from hook.dll
- removed some debugging messages
2014-05-05 18:24:15 +02:00
Tannin 164ec25a75 - bugfix: endless loop in detection of mod order problems 2014-05-04 16:13:35 +02:00
Tannin 6fb36d6c02 - main window now has a small view displaying log messages
- mod list will now be highlighted when grouping is active is active
- download tooltip now supports bbcode markup in the description
- bbcode translator will now translate some named colors
- algorithm for detection of mod order problems is now more sophisticated
- exposed more functionality to python plugins
- updated to qt 4.8.6 dlls
- bugfix: plugin list wasn't
- bugfix: state changes in mod list wasn't always reported
- bugfix: loot client will now create necessary directory
- bugfix: NCC sometimes used wrong source path for extracting
- bugfix: removed noisy debug message
2014-05-04 14:50:01 +02:00
Tannin ea1f959ad5 - download tooltip now also includes the file description
- will now display an error message when the ini file can't be updated (in addition to what windows says)
2014-05-01 10:03:40 +02:00
Tannin 7cf3b3455b Added tag release v1.2.0 for changeset cc9f6dd8ee3f 2014-04-25 20:02:53 +02:00
Tannin 84cfa95254 - bugfix: newly installed files could be added hidden
- bugfix: registered bsas in data aren't ordered correctly
2014-04-25 19:15:12 +02:00
Tannin 264da60929 - updated installer
- prettified a few log messages
2014-04-24 22:07:42 +02:00
Tannin 2db33523a1 - added an option to show meta info on downloads instead of filenames
- MO will now cancel if user tries to run MO vfs-injected
- when saving the MO ini file it is now written to a tmp file first and then overwritten
- updated to link against boost python 1.55
2014-04-23 23:59:30 +02:00
Tannin 540747177a - loot client no longer stalls the process while waiting for masterlist update
- configurator now gives better warning messages when encountering an invalid ini file
- bugfix: crash on cleanup up browser dialog
- bugfix: GetCurrentDirectory returned wrong string length
2014-04-16 22:32:59 +02:00
Tannin 739c3424e7 - loot integration now displays the report
- fixes to the previous merge
- bugfix: cli loot didn't handle non-ascii characters correctly
2014-04-05 20:54:08 +02:00
Tannin cabed9b268 Merge with branch1.1 2014-04-05 15:36:42 +02:00
Tannin c017f4a0d5 - added buttons to backup and restore the modlist and pluginlist
- replaced boss integration with loot
2014-04-05 15:14:37 +02:00
Tannin b1f1682790 - bugfix: the add/remove categories function could fail when a filter/grouping on categories was active 2014-03-26 17:23:26 +01:00
Tannin 28301e7486 - improved NCC compatibility
- crude support for multi-volume archives
- updated imageformats plugins
- nxmhandler now puts the exe to the top of the list when registering an MO instance, even if it is already in the list
- bugfix: WritePrivateProfileString hook attempted to access lpKeyName even when it is null
2014-03-26 15:35:59 +01:00
Tannin 2d0fab4482 Merge 2014-03-18 19:18:17 +01:00
Tannin c19c4820d8 - force-enabled game esms no longer break keyboard-navigation in plugin list 2014-03-18 19:18:04 +01:00
Tannin 8ab1b47943 - bugfix: if resuming a download failed with the server sending a textual error message,
MO tried to display the whole file inside the error message
- bugfix: resuming a download didn't trigger a nexus-login when necessary
- bugfix: integrated fomod installer only used the first block of data inside a description
2014-03-18 18:29:32 +01:00
Tannin ff272dcbbd Merge 2014-03-16 20:05:13 +01:00
Tannin 98354cd1e7 some fixes towards qt5 compatibility 2014-03-16 20:04:57 +01:00
Tannin 129b76d7d2 - unpacking bsas during installation no longer overwrites loose files (since the loose files
would have taken precedence)
2014-03-13 21:57:11 +01:00
Tannin a82b7e9949 - "CreateDirectory" will no longer create directories in original data directory
- bain installer will now be less picky about the archives supported
- updated NCC to be compatible with more recent NMM code base
- hack in NCC to allow it to install arbitrary sized files even in 32-bit builds
- updated the python27.dll to one that links to msvcr100.dll to get rid of the dependency of msvcr90.dll
- bugfix: dll search order wasn't set to allow plugins to load the correct qt dlls
2014-03-13 19:00:32 +01:00
Tannin 0f8f7bf777 Added tag releease v1.1.2 for changeset 4276e1188b42 2014-02-26 22:14:06 +01:00
Tannin f4cf992700 Removed tag 1.1.2 2014-02-26 22:13:53 +01:00
Tannin bec644bac3 Added tag 1.1.2 for changeset 4276e1188b42 2014-02-26 22:13:43 +01:00
Tannin bb98bfade6 - MO will now be elevated if needed 2014-02-23 18:53:38 +01:00
Tannin 00f4e1799f - slightly overworked display of icon delegates
- updated installer
2014-02-23 17:18:20 +01:00
Tannin 35fcf1c25b - made the indicator for drag&drop more visible
- message boxes can now be made to not (re-)activate the window
- executable names for starting from the command line are now case-insensitive
2014-02-22 19:22:12 +01:00
Tannin bed3c08a6d - bugfix: on-demand loading of data tree broke filtering on conflicting files 2014-02-18 19:08:12 +01:00
Tannin f9eba9dc15 - ini file changes that would have to overwrite ini tweaks are now stored in a separate file
and actually get used.
- a warning message advices users to clean out that separate file
- slightly improved default main window layout
- bugfix: newly created ini tweaks were added to the list with incorrect  properties
2014-02-17 21:15:20 +01:00
Tannin 9c8e43853d - a few hooks will now somewhat handle file names starting with \\?\
- mod meta information is now (also) saved by a timer to reduce the likelyhood
of a data loss in case of a crash
- mod meta files are now written to a temporary file and then renamed to real name to
reduce chance of breaking the file
- updated minimum compatible nmm version to 0.47.0
- bugfix: defaults for newestVersion, version and installationFile when creating
an empty mod were integers instead of strings
- bugfix: "Plugins" and "Archives" weren't translatable
2014-02-12 21:00:49 +01:00
Tannin 7aadb47637 - archives.txt is now written using the "safe"-write mechanism
- added the whole boss fork to the repository
- bugfix: boss db is now always re-initialised because otherwise there might have been differing results between runs
- bugfix: locked load order was ignored by integrated boss
- bugfix: archive list wasn't written back on all changes that affected it
- bugfix: CreateFile-hook didn't reroute files created with OPEN_ALWAYS to overwrite directory
- bugfix: NtQueryDirectoryFile-hook didn't return the correct status code when searching for a file that doesn't exist
2014-02-07 21:05:48 +01:00
Tannin 76fbe6effe - tabs in the mod info dialog can now be moved around by the user 2014-02-04 19:55:27 +01:00
Tannin 38ee6ccf0a Added tag release v1.1.1 for changeset 73a1f1438658 2014-02-02 15:14:07 +01:00
Tannin 7722a9b6df - main window is now actually disabled while integrated boss is running
- bugfix: integrated boss sorting couldn't recognize plugins specified via regular expression
2014-02-02 14:26:24 +01:00
Tannin 48704877ca - bugfix: upon moving files between mods, an attempt was made to access origins
for both, even if one (or both) mods weren't active
- bugfix: plugin-list should now deal with nested "layoutAboutToBeChanged" calls
gracefully. May be the reason of a bug.
2014-02-02 00:09:03 +01:00
Tannin 48c944c737 - bugfix: elevation dialog didn't offer a "yes" option
- bugfix: python plugins crashed the application when trying to create a nexus bridge
- bugfix: python plugins couldn't register for failed requests correctly
2014-01-29 21:06:55 +01:00
Tannin af50eedbe2 - bugfix: dds preview or transparent textures looked odd
- bugfix: lazy loaded data tree deleted the placeholder
2014-01-29 00:23:16 +01:00
Tannin 52e5dd3c57 Added tag release v1.1.0 for changeset 87c2eea95307 2014-01-29 00:20:47 +01:00
Tannin ccd5d1294f - bugfix: accessing profile without loading one when starting an app through the commandline
- bugfix: locked-dialog was disabled
2014-01-27 21:31:10 +01:00
Tannin de984a4ef8 - information from boss no longer gets lost as soon as the plugin list gets refreshed
- bugfix: modified boss dll missed one file on sorting
2014-01-23 21:14:44 +01:00
Tannin e597823337 - boss integration
- plugin list can now also display multiple flags for a file (like the mod list)
- changed some compiler&linker settings to produce smaller binaries
2014-01-23 00:05:46 +01:00
Tannin e69210b3a7 - when a download server returns a text file, it's assumed to be an error and the text displayed as an error
- save games can now be deleted from inside MO
- bugfix: removing the pending download entry failed if the download-url request failed
- bugfix: download manager didn't stop automatically resuming failed downloads under certain circumstances
- bugfix: uninstalled downloads were treated as not-finished when refreshing the download list
- bugfix: updating the filesystem watcher on the saves directory didn't work correctly
2014-01-18 19:51:58 +01:00
Tannin 40d20ab294 - added an about dialog
- updated json library
2014-01-16 20:43:42 +01:00
Tannin 6ed82866b0 - moved code for file previews to plugins 2014-01-14 21:16:36 +01:00
Tannin a083a2d3b6 - implemented hook for NtQueryDirectoryFile
- saves list is now automatically updated on FS changes
- optimization: data tree widget is no longer filled completely at once but one directory at a time
- bugfix: pending downloads were not removed from list after a failed nxm request
- bugfix: there was still a nmm.nexusmods.com link
- bugfix: the text "alpha" in version strings wasn't interpreted correctly
2014-01-13 19:32:54 +01:00
Tannin db09b806b9 - Mod Organizer can now display most image types (including dds) and txt files from the data
tree, presenting a comparison of variants in case of overwritten files
2014-01-05 18:50:56 +01:00
Tannin 859c0aed98 download manager now removed orphaned meta files 2014-01-04 16:39:38 +01:00
Tannin 0ea7d99b9f Merge 2014-01-04 16:05:39 +01:00
Tannin 6cffbd4f27 using icons + splash from heavydude 2014-01-04 16:05:25 +01:00
Tannin 4dc3538a7d - nxmhandler will now ask before registering itself
- downloads from nexus are now displayed before file information is retrieved
- logging from the ui is now a bit more informative
- download list now scrolls to bottom automatically
2014-01-04 15:57:14 +01:00
Tannin e45b747c82 Added tag release v1.0.12 for changeset 440287834340 2014-01-03 18:43:03 +01:00
Tannin 2d6bacbb6a -removed compiled translations from the repository 2014-01-03 18:41:47 +01:00
Tannin d029e97724 - hook dll now monitors all mod directories, not only overwrite
- dialog for changing executables now warns if changes will be lost
- main window is now locked before activating pre-start hooks
- better responsiveness while main window is locked (or should be)
2014-01-03 18:40:46 +01:00
Tannin a9435f637e Added tag release v1.0.11 for changeset 806fd77aa2de 2013-12-19 20:33:38 +01:00
Tannin e1e35da6fe Added tag release v1.0.10 for changeset e72788d8ac35 2013-12-19 20:31:48 +01:00
Tannin e43f126b03 - bugfix: crash on overwriting a mod (introduced after the previous release)
- bugfix: ncc installer now brings the installer window to front (again? more reliably? not sure if it really worked before)
2013-12-19 20:30:39 +01:00
Tannin 35c9fe3e98 - bugfix: archive.dll could cause a crash, attempting to close an archive that failed to open
- bugfix: upon changing categories the mappings of deleted categories wasn't cleaned up which could cause an error message
- bugfix: the number of esps/esms that can be loaded is actually 255 not 256 since the save game counts too
- bugfix: "visit on nexus" from the modinfo dialog also lead to the wrong url
2013-12-19 19:40:59 +01:00
Tannin 82f7b09b40 Merge 2013-12-14 17:19:27 +01:00
Tannin f33d24870f - added more information to readme
- 7zip source path is now configurable
2013-12-14 17:19:15 +01:00
Tannin 14ac234daf - plugin list now highlights plugins with attached ini files
- bugfix: opening nexus through the globe icon used the nmm.nexusmods.com url
2013-12-14 13:23:13 +01:00
Tannin 22b8eb7c5a - downgrading a mod (using replace) will now change the version
- bain installer will now accept archives with omod conversion data.
2013-12-11 20:43:30 +01:00
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 98e5e57a84 - added support for mod page plugins
- re-introduced the integrated browser
- added a plugin to download from the tes alliance page
- the download list now contains the file description
- nexus interface now stores cookies persistently to reduce number of required log-ins
2013-09-15 15:20:00 +02:00
128 changed files with 14084 additions and 8371 deletions
+7
View File
@@ -13,3 +13,10 @@ source - Copy/*
ModOrganizer-build-*
pdbs/*
source/NCC/BossDummy.x/*
*.ts
staging_prepare/*
staging_trans/*
tools/python_zip/*
Makefile
syntax: regexp
Makefile\.(Debug|Release)
+158 -15
View File
@@ -1,46 +1,115 @@
HOW TO BUILD
============
Intro:
------
Building Mod Organizer can be a rather daunting task especially if you're not very comfortable with C++ development under windows.
Please note that if you only want to work on and build a plugin you can save yourself a lot of trouble
Overview:
---------
As of December 2013 MO consists of the following subprojects:
- organizer: The main userinterface. heavy usage of various libraries
- hookdll: core library of the virtual file system
- uibase: interop between plugins and the main application as well as some reusable functionality
- shared: functionality shared between organizer and hookdll. I'm attempting to get rid of this library over time
- nxmhandler: tool to pass handling of nxm links to MO or other applications
- helper: tool for doing operations requiring elevated priviledges if MO doesn't have them
- proxydll: dll used in the "proxy dll" load mechanism
- esptk: small library containing functionality to work with esps/esms
- bsatk: small library containing functionality to work with bsas. Requires zlib to extract files. Requires boost_thread to provide multi-threaded extraction
- archive: small wrapper library around 7zip for dealing with mod archives. Requires 7zip
- NCC: extension to NMM to provide a binary with command line interface for fomod installation. This is c# code and does not build with the rest of the project. Requires the rest of NMM
- bossdummy: dummy dll that looks like the boss.dll. This is used instead of the real boss dlls in NCC to save some disk space
- pythonrunner: library for embedding python code. Requires boost_python, python 2.7 and pyqt4
And various plugins:
- checkFNIS: Activates each time an application is started from MO and runs fnis if necessary
- diagnoseBasic: Various diagnostic checks on the game
- inieditor: minimalistic file editor for ini files
- installerBain: handles non-scripted bain installers
- installerBCF: no functionality. Supposed to eventually allow installations using bcfs (bain conversion file). python code
- installerBundle: handles installation of archives wrapped in archives
- installerFomod: handles installation of xml fomods
- installerManual: handles installations of archives that aren't supported by any other plugin (or if the user chooses to do the installation manually)
- installerNCC: handles installation of any fomod (requires NCC)
- installerQuick: handles very simple one-click installations
- NMMImport: importer from existing nmm installation
- proxyPython: integrates pythonrunner as a plugin into MO
- pyniEdit: more user-friendly ini editor. python code
Requirements:
-------------
Visual C++ compiler 2010 (VC 10.0) or up
- Included in visual c++ express 2010 or windows sdk 7.0
- Included in visual c++ express 2010 or windows sdk 7.x
- Do install windows sdk too if only for the cdb debugger which is included in that package
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
Qt Libraries 4.8.x (http://qt-project.org/downloads)
- i.e. "Qt libraries 4.8.5 for Windows (VS 2010, 235 MB)"
- tested: 4.8.5
- Qt5 is not yet supported but WIP. You will see a few conditional qt5 pathes
- Install according to instruction
boost libraries (http://www.boost.org/)
- 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)
- tested: 1.49
- Build 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 libs MO needs (at the time of writing) are
boost_thread (for everything that links agains bsatk) and boost_python (for pythonrunner). You can disable the others to save 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
- 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
7z sourcecode (http://www.7-zip.org/download.html)
- only for "archive" subproject
- no need to compile, will be linked into project
Python 2.7 (32-bit)
- only for pythonrunner
PyQt4 for Python 2.7
- tested: 4.10
- only for pythonrunner
Recommended:
------------
Qt Creator
- http://qt-project.org/downloads#qt-creator
- I.e. "Qt Creator 2.8.1 for Windows (53 MB)"
- With Qt Creator usually the rule is "the newer the better"
- Start Qt Creator and check if things are set up correctly:
1) Go to Tools > Options > Build & Run > Qt Versions
2.1) If the QtSDK 4.8.x you installed earlier is not auto-detected, click "Add" to add it manually
2.2) Navigate to your <your qt4 installation>\bin\qmake.exe
2.3) Restart qt creator
3) Go to Tools > Options > Build & Run > Kits
3.1) If no Kit is auto-detected (or the auto-detected ones have picked up the wrong qt or vc++ installation) click "Add"
3.2) Enter a Name (i.e. "Qt 4.8.5 MSVC2010 32bit")
3.3) In Compiler select the visual studio compiler installed earlier (may show up as "Microsoft Windows SDK for Windows x). Make sure you select the x86 variant
3.4) CDB should be auto-detected
3.5) Select the qt version set up earlier
4) Apply and close the options
Set up (using Qt Creator):
--------------------------
1. Using Qt Creator open source/ModOrganizer.pro from your working copy
2. Open the "Projects" tab, open the "Details" for "Build Environment"
3. Click "Add" to add a variable called "BOOSTPATH" with the path of your boost installation as the value (i.e. C:\code\boost_1_52_0)
4. Click "Add" to add a variable called "ZLIBPATH" with the path of your zlib installation as the value (i.e. C:\code\zlib-1.2.7)
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.
3a. Click "Add" to add a variable called "BOOSTPATH" with the path of your boost installation as the value (i.e. C:\code\boost_1_49_0)
3b. Click "Add" to add a variable called "ZLIBPATH" with the path of your zlib installation as the value (i.e. C:\code\zlib-1.2.7)
3c. Click "Add" to add a variable called "7ZIPPATH" with the path of your zlib installation as the value (i.e. C:\code\7zip)
3d. Click "Add" to add a variable called "PYTHONPATH" with the path of your zlib installation as the value (i.e. C:\code\python)
4. Switch the build configuration at the very top of the same page from "debug" to "release" (or vice versa) and repeat step 3
5. Compile the configuration(s) you want to use (debug and/or release) (Build All). This should compile correctly.
6. <reserved for future use. Maybe grab a coffee?>
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:
@@ -68,4 +137,78 @@ Set up (without Qt Creator):
I'm not using this workflow so I can't give more detailed instructions.
Please note that the primary project format of MO remains qmake, if you work with visual studio and make changes to the project (like adding
source files) you have to manually transfer those changes to the .pro file.
source files) you have to manually transfer those changes to the .pro file.
-----------------
Troubleshooting (thanks to Ross):
-----------------
1) When I try to build, I am seeing the error "error: LNK1104: cannot open file 'zlibstatic.lib'"
a) Make sure you have the following files
{ZLIBPATH}\build\zconf.h
{ZLIBPATH}\build\zlib.h
{ZLIBPATH}\build\zlibstatic.lib
b) make sure "zlibstat.lib" was renamed to "zlibstatic.lib"
c) currently, there are references to zlibstatic in the following 2 project files:
./bsatk/bsatk.pro
./hookdll/hookdll.pro
2) After building, I try to open {MOPROJECTPATH}\outputd\ModOragnizer.exe and get this error
"The program can't start because QtDeclaratived4.dll is missing from your computer. Try reinstalling the program to fix this problem."
-> When setting up Qt4.8.x, make sure you copied the "d" (debug) versions of the dll files to {MOPROJECTPATH}\outputd\dlls
If you copied the release version or did not copy the dlls at all, you may see this error.
The *.dll files can be found in {QT48xPATH}\bin
Similiar:
http://stackoverflow.com/questions/11196416/cant-start-qt-exe-file-on-windows-7
3) I am getting one or more of the the following compiler warnings...
"{MOPROJECTPATH}\source\bsatk\bsaexception.cpp:32: warning: C4996: 'vsnprintf': This function or variable may be unsafe.
Consider using vsnprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details."
-> Ignore/suppress warning like this and make be ultra-careful using printf-style functions. vsnprintf_s is a visual-c++ only function so using those would make porting (i.e. to mingw) harder
"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\INCLUDE\stdio.h:354: see declaration of 'vsnprintf'"
-> see previous
"debug\bsaarchive.obj:-1: warning: LNK4042: object specified more than once; extras ignored"
-> This appears to be an issue when using VC++ 2010 as the compiler. There are some posts on StackOverflow
which suggest fixes when using VC++ as the IDE, but not sure how to apply them to Qt Creator.
http://stackoverflow.com/questions/3729515
http://stackoverflow.com/questions/3695174
-> Also, not sure if this affects VC++ 2012 / VC++ 2013 / GCC via cygwin/mingw.
Not even sure if the project would successfully compile on these.
"{MOPROJECTPATH}\source\organizer\mainwindow.cpp:3995: warning: C4428: universal-character-name encountered in source"
-> very pointless warning.
http://stackoverflow.com/questions/11589571
http://stackoverflow.com/questions/7078013
the best solution I saw was to just disable the warning altogether...
#pragma warning( disable : 4428 )
"warning: LNK4098: defaultlib 'LIBCMT' conflicts with use of other libs; use /NODEFAULTLIB:library"
-> You can always add a #pragma to ignore them :P
http://msdn.microsoft.com/en-us/library/2c8f766e%28v=vs.80%29.aspx
4) I got the following error while building...
"error: LNK1201: error writing to program database
'{MOPROJECTPATH}\{whatever-your-build-directory-name-is}\organizer\debug\ModOrganizer.pdb';
check for insufficient disk space, invalid path, or insufficient privilege"
-> I had this happen after trying to look at something in memory via Process Explorer.
To resolve, I killed and restarted PE. Alternatively, you could probably use the
Unlocker utility. After unlocking, I manually deleted everything in the directory.
Unlocker: http://www.filehippo.com/download_unlocker/ or http://www.emptyloop.com/unlocker/
Warning: With Unlocker v1.9.2, you must select "Advanced" then uncheck everything to
avoid having some Delta toolbar garbage installed...
+3 -2
View File
@@ -13,11 +13,12 @@ SUBDIRS = bsatk \
nxmhandler \
BossDummy \
pythonRunner \
esptk
esptk \
loot_cli
plugins.depends = pythonRunner
hookdll.depends = shared
organizer.depends = shared uibase plugins
organizer.depends = shared uibase plugins loot_cli
CONFIG(debug, debug|release) {
DESTDIR = outputd
+83
View File
@@ -0,0 +1,83 @@
/*
Copyright (C) 2014 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 "aboutdialog.h"
#include "ui_aboutdialog.h"
#include <utility.h>
AboutDialog::AboutDialog(const QString &version, QWidget *parent)
: QDialog(parent)
, ui(new Ui::AboutDialog)
{
ui->setupUi(this);
m_LicenseFiles[LICENSE_LGPL3] = "lgpl-3.0.txt";
m_LicenseFiles[LICENSE_GPL3] = "gpl-3.0.txt";
m_LicenseFiles[LICENSE_BSD3] = "bsd3.txt";
m_LicenseFiles[LICENSE_BOOST] = "boost.txt";
m_LicenseFiles[LICENSE_CCBY3] = "by-sa3.txt";
m_LicenseFiles[LICENSE_ZLIB] = "zlib.txt";
addLicense("Qt 4.8.5", LICENSE_LGPL3);
addLicense("Qt Json", LICENSE_GPL3);
addLicense("Boost Library", LICENSE_BOOST);
addLicense("Tango Icon Theme", LICENSE_NONE);
addLicense("RRZE Icon Set", LICENSE_CCBY3);
addLicense("7-zip", LICENSE_LGPL3);
addLicense("ZLib", LICENSE_ZLIB);
addLicense("NIF File Format Library", LICENSE_BSD3);
addLicense("BOSS (modified)", LICENSE_GPL3);
addLicense("Alphanum Algorithm", LICENSE_ZLIB);
ui->nameLabel->setText(QString("<span style=\"font-size:12pt; font-weight:600;\">%1 %2</span>").arg(ui->nameLabel->text()).arg(version));
#ifdef HGID
ui->revisionLabel->setText(ui->revisionLabel->text() + " " + HGID);
#else
ui->revisionLabel->setText(ui->revisionLabel->text() + " unknown");
#endif
}
AboutDialog::~AboutDialog()
{
delete ui;
}
void AboutDialog::addLicense(const QString &name, Licenses license)
{
QListWidgetItem *item = new QListWidgetItem(name);
item->setData(Qt::UserRole, license);
ui->creditsList->addItem(item);
}
void AboutDialog::on_creditsList_currentItemChanged(QListWidgetItem *current, QListWidgetItem*)
{
auto iter = m_LicenseFiles.find(current->data(Qt::UserRole).toInt());
if (iter != m_LicenseFiles.end()) {
QString filePath = qApp->applicationDirPath() + "/license/" + iter->second;
QString text = MOBase::readFileText(filePath);
ui->licenseText->setText(text);
} else {
ui->licenseText->setText(tr("No license"));
}
}
+69
View File
@@ -0,0 +1,69 @@
#ifndef ABOUTDIALOG_H
/*
Copyright (C) 2014 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/>.
*/
#define ABOUTDIALOG_H
#include <QDialog>
#include <QListWidgetItem>
#include <map>
#include <vector>
#include <utility>
namespace Ui {
class AboutDialog;
}
class AboutDialog : public QDialog
{
Q_OBJECT
public:
explicit AboutDialog(const QString &version, QWidget *parent = 0);
~AboutDialog();
private:
enum Licenses {
LICENSE_NONE,
LICENSE_LGPL3,
LICENSE_GPL3,
LICENSE_BSD3,
LICENSE_BOOST,
LICENSE_CCBY3,
LICENSE_ZLIB
};
private:
void addLicense(const QString &name, Licenses license);
private slots:
void on_creditsList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous);
private:
Ui::AboutDialog *ui;
std::map<int, QString> m_LicenseFiles;
};
#endif // ABOUTDIALOG_H
+295
View File
@@ -0,0 +1,295 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AboutDialog</class>
<widget class="QDialog" name="AboutDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>508</width>
<height>335</height>
</rect>
</property>
<property name="windowTitle">
<string>About</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="iconLabel">
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources.qrc">:/MO/gui/mo_icon.ico</pixmap>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="about">
<attribute name="title">
<string>About</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="nameLabel">
<property name="text">
<string notr="true">Mod Organizer</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="revisionLabel">
<property name="text">
<string>Revision:</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string notr="true">Copyright 2011-2014 Sebastian Herbord</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string notr="true">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This program 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.&lt;/p&gt;&lt;p&gt;See the GNU General Public License for more details.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="software">
<attribute name="title">
<string>Used Software</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QListWidget" name="creditsList"/>
</item>
<item>
<widget class="QTextBrowser" name="licenseText"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="credits">
<attribute name="title">
<string>Credits</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Translators</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QListWidget" name="listWidget_2">
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<item>
<property name="text">
<string notr="true">pndrev (German)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">DaWul (Spanish)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Fiama (Spanish)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Alyndiar (French)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Jlkawaii (French)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Rigoletto (French)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Scythe1912 (Chinese)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">yc0620shen (Chinese)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">miraclefreak (Czech)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">tokcdk (Russian)</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Others</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<widget class="QListWidget" name="listWidget">
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<item>
<property name="text">
<string notr="true">blacksol</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">DoubleYou</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">deathneko11</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Bridger</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">GSDFan</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Uhuru</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Wolverine2710</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">z929669</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="closeButton">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources>
<include location="resources.qrc"/>
</resources>
<connections>
<connection>
<sender>closeButton</sender>
<signal>clicked()</signal>
<receiver>AboutDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>460</x>
<y>313</y>
</hint>
<hint type="destinationlabel">
<x>253</x>
<y>167</y>
</hint>
</hints>
</connection>
</connections>
</ui>
+24 -8
View File
@@ -22,6 +22,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QRegExp>
#include <map>
#include <algorithm>
#include <boost/assign.hpp>
namespace BBCode {
@@ -43,7 +44,6 @@ public:
// 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
@@ -60,7 +60,21 @@ public:
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);
if (tagIter->second.second.isEmpty()) {
if (tagName == "color") {
QString color = tagIter->second.first.cap(1);
QString content = tagIter->second.first.cap(2);
auto colIter = m_ColorMap.find(color.toLower());
if (colIter != m_ColorMap.end()) {
color = colIter->second;
}
return temp.replace(tagIter->second.first, QString("<font style=\"color: #%1;\">%2</font>").arg(color, content));
} else {
qWarning("don't know how to deal with tag %s", qPrintable(tagName));
}
} else {
return temp.replace(tagIter->second.first, tagIter->second.second);
}
} else {
// expression doesn't match. either the input string is invalid
// or the expression is
@@ -96,7 +110,7 @@ private:
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\\]"),
@@ -139,10 +153,6 @@ private:
"<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\\]"),
@@ -150,6 +160,11 @@ private:
m_TagMap["youtube"] = std::make_pair(QRegExp("\\[youtube\\](.*)\\[/youtube\\]"),
"<a href=\"http://www.youtube.com/v/\\1\">http://www.youtube.com/v/\\1</a>");
m_ColorMap = boost::assign::map_list_of("red", "FF0000")("green", "00FF00")("blue", "0000FF")
("black", "000000")("gray", "7F7F7F")("white", "FFFFFF")
("yellow", "FFFF00")("cyan", "00FFFF")("magenta", "FF00FF")
("brown", "A52A2A")("orange", "FFCC00");
// 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);
@@ -157,10 +172,11 @@ private:
}
}
private:
QRegExp m_TagNameExp;
TagMap m_TagMap;
std::map<QString, QString> m_ColorMap;
};
+270
View File
@@ -0,0 +1,270 @@
/*
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 "browserdialog.h"
#include "ui_browserdialog.h"
#include "messagedialog.h"
#include "report.h"
#include "json.h"
#include "persistentcookiejar.h"
#include <gameinfo.h>
#include <utility.h>
#include <gameinfo.h>
#include <QNetworkCookieJar>
#include <QNetworkCookie>
#include <QMenu>
#include <QInputDialog>
#include <QWebHistory>
#include <QDir>
#include <QWebFrame>
#include <QDesktopWidget>
BrowserDialog::BrowserDialog(QWidget *parent)
: QDialog(parent)
, ui(new Ui::BrowserDialog)
, m_AccessManager(new QNetworkAccessManager)
{
ui->setupUi(this);
m_AccessManager->setCookieJar(new PersistentCookieJar(
QDir::fromNativeSeparators(MOBase::ToQString(MOShared::GameInfo::instance().getCacheDir())) + "/cookies.dat", this));
Qt::WindowFlags flags = windowFlags() | Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint;
Qt::WindowFlags helpFlag = Qt::WindowContextHelpButtonHint;
flags = flags & (~helpFlag);
setWindowFlags(flags);
m_Tabs = this->findChild<QTabWidget*>("browserTabWidget");
connect(m_Tabs, SIGNAL(tabCloseRequested(int)), this, SLOT(tabCloseRequested(int)));
}
BrowserDialog::~BrowserDialog()
{
delete ui;
}
void BrowserDialog::closeEvent(QCloseEvent *event)
{
// m_AccessManager->showCookies();
QDialog::closeEvent(event);
}
void BrowserDialog::initTab(BrowserView *newView)
{
newView->page()->setNetworkAccessManager(m_AccessManager);
newView->page()->setForwardUnsupportedContent(true);
connect(newView, SIGNAL(loadProgress(int)), this, SLOT(progress(int)));
connect(newView, SIGNAL(titleChanged(QString)), this, SLOT(titleChanged(QString)));
connect(newView, SIGNAL(initTab(BrowserView*)), this, SLOT(initTab(BrowserView*)));
connect(newView, SIGNAL(startFind()), this, SLOT(startSearch()));
connect(newView, SIGNAL(urlChanged(QUrl)), this, SLOT(urlChanged(QUrl)));
connect(newView, SIGNAL(openUrlInNewTab(QUrl)), this, SLOT(openInNewTab(QUrl)));
connect(newView->page(), SIGNAL(downloadRequested(QNetworkRequest)), this, SLOT(downloadRequested(QNetworkRequest)));
connect(newView->page(), SIGNAL(unsupportedContent(QNetworkReply*)), this, SLOT(unsupportedContent(QNetworkReply*)));
ui->backBtn->setEnabled(false);
ui->fwdBtn->setEnabled(false);
m_Tabs->addTab(newView, tr("new"));
newView->settings()->setAttribute(QWebSettings::PluginsEnabled, true);
newView->settings()->setAttribute(QWebSettings::AutoLoadImages, true);
}
void BrowserDialog::openInNewTab(const QUrl &url)
{
BrowserView *newView = new BrowserView(this);
initTab(newView);
newView->setUrl(url);
}
BrowserView *BrowserDialog::getCurrentView()
{
return qobject_cast<BrowserView*>(m_Tabs->currentWidget());
}
void BrowserDialog::urlChanged(const QUrl&)
{
BrowserView *currentView = getCurrentView();
if (currentView != NULL) {
ui->backBtn->setEnabled(currentView->history()->canGoBack());
ui->fwdBtn->setEnabled(currentView->history()->canGoForward());
}
}
void BrowserDialog::openUrl(const QUrl &url)
{
if (isHidden()) {
show();
}
openInNewTab(url);
}
void BrowserDialog::maximizeWidth()
{
int viewportWidth = getCurrentView()->page()->viewportSize().width();
int frameWidth = width() - viewportWidth;
int contentWidth = getCurrentView()->page()->mainFrame()->contentsSize().width();
QDesktopWidget screen;
int currentScreen = screen.screenNumber(this);
int screenWidth = screen.screenGeometry(currentScreen).size().width();
int targetWidth = std::min<int>(std::max<int>(viewportWidth, contentWidth) + frameWidth, screenWidth);
this->resize(targetWidth, height());
}
void BrowserDialog::progress(int value)
{
ui->loadProgress->setValue(value);
if (value == 100) {
maximizeWidth();
ui->loadProgress->setVisible(false);
} else {
ui->loadProgress->setVisible(true);
}
}
void BrowserDialog::titleChanged(const QString &title)
{
BrowserView *view = qobject_cast<BrowserView*>(sender());
for (int i = 0; i < m_Tabs->count(); ++i) {
if (m_Tabs->widget(i) == view) {
m_Tabs->setTabText(i, title.mid(0, 15));
m_Tabs->setTabToolTip(i, title);
}
}
}
QString BrowserDialog::guessFileName(const QString &url)
{
QRegExp uploadsExp(QString("http://.+/uploads/([^/]+)$"));
if (uploadsExp.indexIn(url) != -1) {
// these seem to be premium downloads
return uploadsExp.cap(1);
}
QRegExp filesExp(QString("http://.+\\?file=([^&]+)"));
if (filesExp.indexIn(url) != -1) {
// a regular manual download?
return filesExp.cap(1);
}
return "unknown";
}
void BrowserDialog::unsupportedContent(QNetworkReply *reply)
{
try {
QWebPage *page = qobject_cast<QWebPage*>(sender());
if (page == NULL) {
qCritical("sender not a page");
return;
}
BrowserView *view = qobject_cast<BrowserView*>(page->view());
if (view == NULL) {
qCritical("no view?");
return;
}
qDebug("unsupported: %s - %s", view->url().toString().toUtf8().constData(), reply->url().toString().toUtf8().constData());
emit requestDownload(view->url(), reply);
} catch (const std::exception &e) {
if (isVisible()) {
MessageDialog::showMessage(tr("failed to start download"), this);
}
qCritical("exception downloading unsupported content: %s", e.what());
}
}
void BrowserDialog::downloadRequested(const QNetworkRequest &request)
{
qCritical("download request %s ignored", request.url().toString().toUtf8().constData());
}
void BrowserDialog::tabCloseRequested(int index)
{
if (m_Tabs->count() == 1) {
this->close();
} else {
m_Tabs->widget(index)->deleteLater();
m_Tabs->removeTab(index);
}
}
void BrowserDialog::on_backBtn_clicked()
{
BrowserView *currentView = getCurrentView();
if (currentView != NULL) {
currentView->back();
}
}
void BrowserDialog::on_fwdBtn_clicked()
{
BrowserView *currentView = getCurrentView();
if (currentView != NULL) {
currentView->forward();
}
}
void BrowserDialog::startSearch()
{
ui->searchEdit->setFocus();
}
void BrowserDialog::on_searchEdit_returnPressed()
{
BrowserView *currentView = getCurrentView();
if (currentView != NULL) {
currentView->findText(ui->searchEdit->text(), QWebPage::FindWrapsAroundDocument);
}
}
void BrowserDialog::on_browserTabWidget_currentChanged(QWidget *current)
{
BrowserView *currentView = qobject_cast<BrowserView*>(current);
if (currentView != NULL) {
ui->backBtn->setEnabled(currentView->history()->canGoBack());
ui->fwdBtn->setEnabled(currentView->history()->canGoForward());
}
}
void BrowserDialog::on_refreshBtn_clicked()
{
getCurrentView()->reload();
}
+124
View File
@@ -0,0 +1,124 @@
/*
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 BROWSERDIALOG_H
#define BROWSERDIALOG_H
#include "browserview.h"
#include "tutorialcontrol.h"
#include <QDialog>
#include <QProgressBar>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QTimer>
#include <QWebView>
#include <QQueue>
#include <QTabWidget>
#include <QAtomicInt>
namespace Ui {
class BrowserDialog;
}
/**
* @brief a dialog containing a webbrowser that is intended to browse the nexus network
**/
class BrowserDialog : public QDialog
{
Q_OBJECT
public:
/**
* @brief constructor
*
* @param accessManager the access manager to use for network requests
* @param parent parent widget
**/
explicit BrowserDialog(QWidget *parent = 0);
~BrowserDialog();
/**
* @brief set the url to open. If automatic login is enabled, the url is opened after login
*
* @param url the url to open
**/
void openUrl(const QUrl &url);
signals:
/**
* @brief emitted when the user starts a download
* @param pageUrl url of the current web site from which the download was started
* @param reply network reply of the started download
*/
void requestDownload(const QUrl &pageUrl, QNetworkReply *reply);
protected:
virtual void closeEvent(QCloseEvent *);
private slots:
void initTab(BrowserView *newView);
void openInNewTab(const QUrl &url);
void progress(int value);
void titleChanged(const QString &title);
void unsupportedContent(QNetworkReply *reply);
void downloadRequested(const QNetworkRequest &request);
void tabCloseRequested(int index);
void urlChanged(const QUrl &url);
void on_backBtn_clicked();
void on_fwdBtn_clicked();
void on_searchEdit_returnPressed();
void startSearch();
void on_browserTabWidget_currentChanged(QWidget *arg1);
void on_refreshBtn_clicked();
private:
QString guessFileName(const QString &url);
BrowserView *getCurrentView();
void maximizeWidth();
private:
Ui::BrowserDialog *ui;
QNetworkAccessManager *m_AccessManager;
QTabWidget *m_Tabs;
};
#endif // BROWSERDIALOG_H
+289
View File
@@ -0,0 +1,289 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>BrowserDialog</class>
<widget class="QDialog" name="BrowserDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1008</width>
<height>750</height>
</rect>
</property>
<property name="windowTitle">
<string>Some Page</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="toolBar" native="true">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>22</height>
</size>
</property>
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>226</red>
<green>226</green>
<blue>226</blue>
</color>
</brush>
</colorrole>
<colorrole role="Button">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>106</red>
<green>106</green>
<blue>106</blue>
</color>
</brush>
</colorrole>
<colorrole role="ButtonText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>199</red>
<green>199</green>
<blue>199</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>81</red>
<green>81</green>
<blue>81</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>226</red>
<green>226</green>
<blue>226</blue>
</color>
</brush>
</colorrole>
<colorrole role="Button">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>106</red>
<green>106</green>
<blue>106</blue>
</color>
</brush>
</colorrole>
<colorrole role="ButtonText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>199</red>
<green>199</green>
<blue>199</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>81</red>
<green>81</green>
<blue>81</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>120</red>
<green>120</green>
<blue>120</blue>
</color>
</brush>
</colorrole>
<colorrole role="Button">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>106</red>
<green>106</green>
<blue>106</blue>
</color>
</brush>
</colorrole>
<colorrole role="ButtonText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>120</red>
<green>120</green>
<blue>120</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>81</red>
<green>81</green>
<blue>81</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>81</red>
<green>81</green>
<blue>81</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="autoFillBackground">
<bool>true</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="backBtn">
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/MO/gui/previous</normaloff>:/MO/gui/previous</iconset>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="fwdBtn">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/MO/gui/next</normaloff>:/MO/gui/next</iconset>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="refreshBtn">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/MO/gui/refresh</normaloff>:/MO/gui/refresh</iconset>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Search</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="searchEdit"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QTabWidget" name="browserTabWidget">
<property name="contextMenuPolicy">
<enum>Qt::DefaultContextMenu</enum>
</property>
<property name="tabsClosable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="loadProgress">
<property name="value">
<number>0</number>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="resources.qrc"/>
</resources>
<connections/>
</ui>
+76
View File
@@ -0,0 +1,76 @@
/*
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 "browserview.h"
#include <QEvent>
#include <QKeyEvent>
#include <QWebFrame>
#include <QWebElement>
#include <QNetworkDiskCache>
#include <QMenu>
#include <Shlwapi.h>
#include "utility.h"
BrowserView::BrowserView(QWidget *parent)
: QWebView(parent)
{
installEventFilter(this);
page()->settings()->setMaximumPagesInCache(10);
}
QWebView *BrowserView::createWindow(QWebPage::WebWindowType)
{
BrowserView *newView = new BrowserView(parentWidget());
emit initTab(newView);
return newView;
}
bool BrowserView::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::ShortcutOverride) {
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->matches(QKeySequence::Find)) {
emit startFind();
} else if (keyEvent->matches(QKeySequence::FindNext)) {
emit findAgain();
}
} else if (event->type() == QEvent::MouseButtonPress) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
if (mouseEvent->button() == Qt::MidButton) {
mouseEvent->ignore();
return true;
}
} else if (event->type() == QEvent::MouseButtonRelease) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
if (mouseEvent->button() == Qt::MidButton) {
QWebHitTestResult hitTest = page()->frameAt(mouseEvent->pos())->hitTestContent(mouseEvent->pos());
if (hitTest.linkUrl().isValid()) {
emit openUrlInNewTab(hitTest.linkUrl());
}
mouseEvent->ignore();
return true;
}
}
return QWebView::eventFilter(obj, event);
}
+80
View File
@@ -0,0 +1,80 @@
/*
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 NEXUSVIEW_H
#define NEXUSVIEW_H
#include "finddialog.h"
#include <QWebView>
#include <QWebPage>
#include <QTabWidget>
/**
* @brief web view used to display a nexus page
**/
class BrowserView : public QWebView
{
Q_OBJECT
public:
explicit BrowserView(QWidget *parent = 0);
signals:
/**
* @brief emitted when the user opens a new window to be displayed in another tab
*
* @param newView the view for the newly opened window
**/
void initTab(BrowserView *newView);
/**
* @brief emitted when the user requests a link to be opened in a new tab by middle-clicking
*
* @param url the url to open
*/
void openUrlInNewTab(const QUrl &url);
/**
* @brief Ctrl-f was clicked. The containing dialog should activate its find-facility
*/
void startFind();
/**
* @brief F3 was pressed. The containing dialog should search again
*/
void findAgain();
protected:
virtual QWebView *createWindow(QWebPage::WebWindowType type);
virtual bool eventFilter(QObject *obj, QEvent *event);
private:
QString m_FindPattern;
bool m_MiddleClick;
};
#endif // NEXUSVIEW_H
+1
View File
@@ -103,6 +103,7 @@ CategoryFactory &CategoryFactory::instance()
void CategoryFactory::reset()
{
m_Categories.clear();
m_IDMap.clear();
addCategory(0, "None", MakeVector<int>(2, 28, 87), 0);
}
+12 -7
View File
@@ -34,9 +34,10 @@ DownloadList::DownloadList(DownloadManager *manager, QObject *parent)
int DownloadList::rowCount(const QModelIndex&) const
{
return m_Manager->numTotalDownloads();
return m_Manager->numTotalDownloads() + m_Manager->numPendingDownloads();
}
int DownloadList::columnCount(const QModelIndex&) const
{
return 3;
@@ -75,14 +76,18 @@ 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.");
if (index.row() < m_Manager->numTotalDownloads()) {
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 {
const MOBase::ModRepositoryFileInfo *info = m_Manager->getFileInfo(index.row());
return QString("%1 (ID %2) %3<br><span>%4</span>").arg(info->modName).arg(m_Manager->getModID(index.row())).arg(info->version.canonicalString()).arg(info->description);
}
return text;
} 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 tr("pending download");
}
return text;
} else {
return QVariant();
}
+14 -8
View File
@@ -37,13 +37,16 @@ bool DownloadListSortProxy::lessThan(const QModelIndex &left,
{
int leftIndex = sourceModel()->data(left).toInt();
int rightIndex = sourceModel()->data(right).toInt();
if (left.column() == DownloadList::COL_NAME) {
return m_Manager->getFileName(leftIndex).compare(m_Manager->getFileName(rightIndex), Qt::CaseInsensitive) < 0;
} else if (left.column() == DownloadList::COL_FILETIME) {
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);
if (leftIndex < m_Manager->numTotalDownloads()) {
if (left.column() == DownloadList::COL_NAME) {
return m_Manager->getFileName(leftIndex).compare(m_Manager->getFileName(rightIndex), Qt::CaseInsensitive) < 0;
} else if (left.column() == DownloadList::COL_FILETIME) {
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 {
return leftIndex < rightIndex;
}
} else {
return leftIndex < rightIndex;
}
@@ -54,6 +57,9 @@ bool DownloadListSortProxy::filterAcceptsRow(int source_row, const QModelIndex&)
{
if (m_CurrentFilter.length() == 0) {
return true;
} else if (source_row < m_Manager->numTotalDownloads()) {
return m_Manager->getFileName(source_row).contains(m_CurrentFilter, Qt::CaseInsensitive);
} else {
return false;
}
return m_Manager->getFileName(source_row).contains(m_CurrentFilter, Qt::CaseInsensitive);
}
+110 -82
View File
@@ -40,8 +40,13 @@ DownloadListWidget::~DownloadListWidget()
}
DownloadListWidgetDelegate::DownloadListWidgetDelegate(DownloadManager *manager, QTreeView *view, QObject *parent)
: QItemDelegate(parent), m_Manager(manager), m_ItemWidget(new DownloadListWidget), m_ContextRow(0), m_View(view)
DownloadListWidgetDelegate::DownloadListWidgetDelegate(DownloadManager *manager, bool metaDisplay, QTreeView *view, QObject *parent)
: QItemDelegate(parent)
, m_Manager(manager)
, m_MetaDisplay(metaDisplay)
, m_ItemWidget(new DownloadListWidget)
, m_ContextRow(0)
, m_View(view)
{
m_NameLabel = m_ItemWidget->findChild<QLabel*>("nameLabel");
m_SizeLabel = m_ItemWidget->findChild<QLabel*>("sizeLabel");
@@ -82,6 +87,83 @@ void DownloadListWidgetDelegate::drawCache(QPainter *painter, const QStyleOption
}
void DownloadListWidgetDelegate::paintPendingDownload(int downloadIndex) const
{
std::pair<int, int> nexusids = m_Manager->getPendingDownload(downloadIndex);
m_NameLabel->setText(tr("< mod %1 file %2 >").arg(nexusids.first).arg(nexusids.second));
m_SizeLabel->setText("???");
m_InstallLabel->setVisible(true);
m_InstallLabel->setText(tr("Pending"));
m_Progress->setVisible(false);
}
void DownloadListWidgetDelegate::paintRegularDownload(int downloadIndex) const
{
QString name = m_MetaDisplay ? m_Manager->getDisplayName(downloadIndex) : m_Manager->getFileName(downloadIndex);
if (name.length() > 53) {
name.truncate(50);
name.append("...");
}
m_NameLabel->setText(name);
m_SizeLabel->setText(QString::number(m_Manager->getFileSize(downloadIndex) / 1024));
DownloadManager::DownloadState state = m_Manager->getState(downloadIndex);
if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR)) {
QPalette labelPalette;
m_InstallLabel->setVisible(true);
m_Progress->setVisible(false);
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Paused - Double Click to resume", 0));
#else
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Paused - Double Click to resume", 0, QApplication::UnicodeUTF8));
#endif
labelPalette.setColor(QPalette::WindowText, Qt::darkRed);
m_InstallLabel->setPalette(labelPalette);
} else if (state == DownloadManager::STATE_FETCHINGMODINFO) {
m_InstallLabel->setText(tr("Fetching Info 1"));
m_Progress->setVisible(false);
} else if (state == DownloadManager::STATE_FETCHINGFILEINFO) {
m_InstallLabel->setText(tr("Fetching Info 2"));
m_Progress->setVisible(false);
} else if (state >= DownloadManager::STATE_READY) {
QPalette labelPalette;
m_InstallLabel->setVisible(true);
m_Progress->setVisible(false);
if (state == DownloadManager::STATE_INSTALLED) {
// the tr-macro doesn't work here, maybe because the translation is actually associated with DownloadListWidget instead
// of DownloadListWidgetDelegate?
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Installed - Double Click to re-install", 0));
#else
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Installed - Double Click to re-install", 0, QApplication::UnicodeUTF8));
#endif
labelPalette.setColor(QPalette::WindowText, Qt::darkGray);
} else if (state == DownloadManager::STATE_UNINSTALLED) {
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Uninstalled - Double Click to re-install", 0));
#else
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Uninstalled - Double Click to re-install", 0, QApplication::UnicodeUTF8));
#endif
labelPalette.setColor(QPalette::WindowText, Qt::lightGray);
} else {
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Done - Double Click to install", 0));
#else
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Done - Double Click to install", 0, QApplication::UnicodeUTF8));
#endif
labelPalette.setColor(QPalette::WindowText, Qt::darkGreen);
}
m_InstallLabel->setPalette(labelPalette);
if (m_Manager->isInfoIncomplete(downloadIndex)) {
m_NameLabel->setText("<img src=\":/MO/gui/warning_16\" /> " + m_NameLabel->text());
}
} else {
m_InstallLabel->setVisible(false);
m_Progress->setVisible(true);
m_Progress->setValue(m_Manager->getProgress(downloadIndex));
}
}
void DownloadListWidgetDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
try {
@@ -95,67 +177,10 @@ void DownloadListWidgetDelegate::paint(QPainter *painter, const QStyleOptionView
int downloadIndex = index.data().toInt();
QString name = m_Manager->getFileName(downloadIndex);
if (name.length() > 53) {
name.truncate(50);
name.append("...");
}
m_NameLabel->setText(name);
m_SizeLabel->setText(QString::number(m_Manager->getFileSize(downloadIndex) / 1024));
DownloadManager::DownloadState state = m_Manager->getState(downloadIndex);
if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR)) {
QPalette labelPalette;
m_InstallLabel->setVisible(true);
m_Progress->setVisible(false);
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Paused - Double Click to resume", 0));
#else
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Paused - Double Click to resume", 0, QApplication::UnicodeUTF8));
#endif
labelPalette.setColor(QPalette::WindowText, Qt::darkRed);
m_InstallLabel->setPalette(labelPalette);
} else if (state == DownloadManager::STATE_FETCHINGMODINFO) {
m_InstallLabel->setText(tr("Fetching Info 1"));
m_Progress->setVisible(false);
} else if (state == DownloadManager::STATE_FETCHINGFILEINFO) {
m_InstallLabel->setText(tr("Fetching Info 2"));
m_Progress->setVisible(false);
} else if (state >= DownloadManager::STATE_READY) {
QPalette labelPalette;
m_InstallLabel->setVisible(true);
m_Progress->setVisible(false);
if (state == DownloadManager::STATE_INSTALLED) {
// the tr-macro doesn't work here, maybe because the translation is actually associated with DownloadListWidget instead
// of DownloadListWidgetDelegate?
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Installed - Double Click to re-install", 0));
#else
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Installed - Double Click to re-install", 0, QApplication::UnicodeUTF8));
#endif
labelPalette.setColor(QPalette::WindowText, Qt::darkGray);
} else if (state == DownloadManager::STATE_UNINSTALLED) {
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Uninstalled - Double Click to re-install", 0));
#else
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Uninstalled - Double Click to re-install", 0, QApplication::UnicodeUTF8));
#endif
labelPalette.setColor(QPalette::WindowText, Qt::lightGray);
} else {
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Done - Double Click to install", 0));
#else
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Done - Double Click to install", 0, QApplication::UnicodeUTF8));
#endif
labelPalette.setColor(QPalette::WindowText, Qt::darkGreen);
}
m_InstallLabel->setPalette(labelPalette);
if (m_Manager->isInfoIncomplete(downloadIndex)) {
m_NameLabel->setText("<img src=\":/MO/gui/warning_16\" /> " + m_NameLabel->text());
}
if (downloadIndex >= m_Manager->numTotalDownloads()) {
paintPendingDownload(downloadIndex - m_Manager->numTotalDownloads());
} else {
m_InstallLabel->setVisible(false);
m_Progress->setVisible(true);
m_Progress->setValue(m_Manager->getProgress(downloadIndex));
paintRegularDownload(downloadIndex);
}
#pragma message("caching disabled because changes in the list (including resorting) doesn't work correctly")
@@ -280,29 +305,32 @@ bool DownloadListWidgetDelegate::editorEvent(QEvent *event, QAbstractItemModel *
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
if (mouseEvent->button() == Qt::RightButton) {
QMenu menu(m_View);
bool hidden = false;
m_ContextRow = qobject_cast<QSortFilterProxyModel*>(model)->mapToSource(index).row();
DownloadManager::DownloadState state = m_Manager->getState(m_ContextRow);
bool hidden = m_Manager->isHidden(m_ContextRow);
if (state >= DownloadManager::STATE_READY) {
menu.addAction(tr("Install"), this, SLOT(issueInstall()));
if (m_Manager->isInfoIncomplete(m_ContextRow)) {
menu.addAction(tr("Query Info"), this, SLOT(issueQueryInfo()));
if (m_ContextRow < m_Manager->numTotalDownloads()) {
DownloadManager::DownloadState state = m_Manager->getState(m_ContextRow);
hidden = m_Manager->isHidden(m_ContextRow);
if (state >= DownloadManager::STATE_READY) {
menu.addAction(tr("Install"), this, SLOT(issueInstall()));
if (m_Manager->isInfoIncomplete(m_ContextRow)) {
menu.addAction(tr("Query Info"), this, SLOT(issueQueryInfo()));
}
menu.addAction(tr("Delete"), this, SLOT(issueDelete()));
if (hidden) {
menu.addAction(tr("Un-Hide"), this, SLOT(issueRestoreToView()));
} else {
menu.addAction(tr("Remove from View"), this, SLOT(issueRemoveFromView()));
}
} 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("Resume"), this, SLOT(issueResume()));
}
menu.addAction(tr("Delete"), this, SLOT(issueDelete()));
if (hidden) {
menu.addAction(tr("Un-Hide"), this, SLOT(issueRestoreToView()));
} else {
menu.addAction(tr("Remove from View"), this, SLOT(issueRemoveFromView()));
}
} 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("Resume"), this, SLOT(issueResume()));
}
menu.addSeparator();
menu.addSeparator();
}
menu.addAction(tr("Delete Installed..."), this, SLOT(issueDeleteCompleted()));
menu.addAction(tr("Delete All..."), this, SLOT(issueDeleteAll()));
if (!hidden) {
+6 -1
View File
@@ -54,12 +54,15 @@ class DownloadListWidgetDelegate : public QItemDelegate
public:
DownloadListWidgetDelegate(DownloadManager *manager, QTreeView *view, QObject *parent = 0);
DownloadListWidgetDelegate(DownloadManager *manager, bool metaDisplay, QTreeView *view, QObject *parent = 0);
~DownloadListWidgetDelegate();
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
void paintPendingDownload(int downloadIndex) const;
void paintRegularDownload(int downloadIndex) const;
signals:
void installDownload(int index);
@@ -102,6 +105,8 @@ private:
DownloadListWidget *m_ItemWidget;
DownloadManager *m_Manager;
bool m_MetaDisplay;
QLabel *m_NameLabel;
QLabel *m_SizeLabel;
QProgressBar *m_Progress;
+92 -64
View File
@@ -40,8 +40,12 @@ DownloadListWidgetCompact::~DownloadListWidgetCompact()
}
DownloadListWidgetCompactDelegate::DownloadListWidgetCompactDelegate(DownloadManager *manager, QTreeView *view, QObject *parent)
: QItemDelegate(parent), m_Manager(manager), m_ItemWidget(new DownloadListWidgetCompact), m_View(view)
DownloadListWidgetCompactDelegate::DownloadListWidgetCompactDelegate(DownloadManager *manager, bool metaDisplay, QTreeView *view, QObject *parent)
: QItemDelegate(parent)
, m_Manager(manager)
, m_MetaDisplay(metaDisplay)
, m_ItemWidget(new DownloadListWidgetCompact)
, m_View(view)
{
m_NameLabel = m_ItemWidget->findChild<QLabel*>("nameLabel");
m_SizeLabel = m_ItemWidget->findChild<QLabel*>("sizeLabel");
@@ -82,6 +86,66 @@ void DownloadListWidgetCompactDelegate::drawCache(QPainter *painter, const QStyl
}
void DownloadListWidgetCompactDelegate::paintPendingDownload(int downloadIndex) const
{
std::pair<int, int> nexusids = m_Manager->getPendingDownload(downloadIndex);
m_NameLabel->setText(tr("< mod %1 file %2 >").arg(nexusids.first).arg(nexusids.second));
if (m_SizeLabel != NULL) {
m_SizeLabel->setText("???");
}
m_DoneLabel->setVisible(true);
m_DoneLabel->setText(tr("Pending"));
m_Progress->setVisible(false);
}
void DownloadListWidgetCompactDelegate::paintRegularDownload(int downloadIndex) const
{
QString name = m_MetaDisplay ? m_Manager->getDisplayName(downloadIndex) : m_Manager->getFileName(downloadIndex);
if (name.length() > 53) {
name.truncate(50);
name.append("...");
}
m_NameLabel->setText(name);
DownloadManager::DownloadState state = m_Manager->getState(downloadIndex);
if ((m_SizeLabel != NULL) && (state >= DownloadManager::STATE_READY)) {
m_SizeLabel->setText(QString::number(m_Manager->getFileSize(downloadIndex) / 1048576));
}
if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR)) {
m_DoneLabel->setVisible(true);
m_Progress->setVisible(false);
m_DoneLabel->setText(tr("Paused"));
m_DoneLabel->setForegroundRole(QPalette::Link);
} else if (state == DownloadManager::STATE_FETCHINGMODINFO) {
m_DoneLabel->setText(tr("Fetching Info 1"));
} else if (state == DownloadManager::STATE_FETCHINGFILEINFO) {
m_DoneLabel->setText(tr("Fetching Info 2"));
} else if (state >= DownloadManager::STATE_READY) {
m_DoneLabel->setVisible(true);
m_Progress->setVisible(false);
if (state == DownloadManager::STATE_INSTALLED) {
m_DoneLabel->setText(tr("Installed"));
m_DoneLabel->setForegroundRole(QPalette::Mid);
} else if (state == DownloadManager::STATE_UNINSTALLED) {
m_DoneLabel->setText(tr("Uninstalled"));
m_DoneLabel->setForegroundRole(QPalette::Dark);
} else {
m_DoneLabel->setText(tr("Done"));
m_DoneLabel->setForegroundRole(QPalette::WindowText);
}
if (m_Manager->isInfoIncomplete(downloadIndex)) {
m_NameLabel->setText("<img src=\":/MO/gui/warning_16\"/> " + m_NameLabel->text());
}
} else {
m_DoneLabel->setVisible(false);
m_Progress->setVisible(true);
m_Progress->setValue(m_Manager->getProgress(downloadIndex));
}
}
void DownloadListWidgetCompactDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
#pragma message("This is quite costy - room for optimization?")
@@ -100,49 +164,10 @@ void DownloadListWidgetCompactDelegate::paint(QPainter *painter, const QStyleOpt
}
int downloadIndex = index.data().toInt();
QString name = m_Manager->getFileName(downloadIndex);
if (name.length() > 53) {
name.truncate(50);
name.append("...");
}
m_NameLabel->setText(name);
DownloadManager::DownloadState state = m_Manager->getState(downloadIndex);
if ((m_SizeLabel != NULL) && (state >= DownloadManager::STATE_READY)) {
m_SizeLabel->setText(QString::number(m_Manager->getFileSize(downloadIndex) / 1048576));
}
if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR)) {
m_DoneLabel->setVisible(true);
m_Progress->setVisible(false);
m_DoneLabel->setText(tr("Paused"));
m_DoneLabel->setForegroundRole(QPalette::Link);
} else if (state == DownloadManager::STATE_FETCHINGMODINFO) {
m_DoneLabel->setText(tr("Fetching Info 1"));
} else if (state == DownloadManager::STATE_FETCHINGFILEINFO) {
m_DoneLabel->setText(tr("Fetching Info 2"));
} else if (state >= DownloadManager::STATE_READY) {
m_DoneLabel->setVisible(true);
m_Progress->setVisible(false);
if (state == DownloadManager::STATE_INSTALLED) {
m_DoneLabel->setText(tr("Installed"));
m_DoneLabel->setForegroundRole(QPalette::Mid);
} else if (state == DownloadManager::STATE_UNINSTALLED) {
m_DoneLabel->setText(tr("Uninstalled"));
m_DoneLabel->setForegroundRole(QPalette::Dark);
} else {
m_DoneLabel->setText(tr("Done"));
m_DoneLabel->setForegroundRole(QPalette::WindowText);
}
if (m_Manager->isInfoIncomplete(downloadIndex)) {
m_NameLabel->setText("<img src=\":/MO/gui/warning_16\"/> " + m_NameLabel->text());
}
if (downloadIndex >= m_Manager->numTotalDownloads()) {
paintPendingDownload(downloadIndex - m_Manager->numTotalDownloads());
} else {
m_DoneLabel->setVisible(false);
m_Progress->setVisible(true);
m_Progress->setValue(m_Manager->getProgress(downloadIndex));
paintRegularDownload(downloadIndex);
}
#pragma message("caching disabled because changes in the list (including resorting) doesn't work correctly")
@@ -268,29 +293,32 @@ bool DownloadListWidgetCompactDelegate::editorEvent(QEvent *event, QAbstractItem
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
if (mouseEvent->button() == Qt::RightButton) {
QMenu menu;
bool hidden = false;
m_ContextIndex = qobject_cast<QSortFilterProxyModel*>(model)->mapToSource(index);
DownloadManager::DownloadState state = m_Manager->getState(m_ContextIndex.row());
bool hidden = m_Manager->isHidden(m_ContextIndex.row());
if (state >= DownloadManager::STATE_READY) {
menu.addAction(tr("Install"), this, SLOT(issueInstall()));
if (m_Manager->isInfoIncomplete(m_ContextIndex.row())) {
menu.addAction(tr("Query Info"), this, SLOT(issueQueryInfo()));
if (m_ContextIndex.row() < m_Manager->numTotalDownloads()) {
DownloadManager::DownloadState state = m_Manager->getState(m_ContextIndex.row());
hidden = m_Manager->isHidden(m_ContextIndex.row());
if (state >= DownloadManager::STATE_READY) {
menu.addAction(tr("Install"), this, SLOT(issueInstall()));
if (m_Manager->isInfoIncomplete(m_ContextIndex.row())) {
menu.addAction(tr("Query Info"), this, SLOT(issueQueryInfo()));
}
menu.addAction(tr("Delete"), this, SLOT(issueDelete()));
if (hidden) {
menu.addAction(tr("Un-Hide"), this, SLOT(issueRestoreToView()));
} else {
menu.addAction(tr("Remove from View"), this, SLOT(issueRemoveFromView()));
}
} 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("Resume"), this, SLOT(issueResume()));
}
menu.addAction(tr("Delete"), this, SLOT(issueDelete()));
if (hidden) {
menu.addAction(tr("Un-Hide"), this, SLOT(issueRestoreToView()));
} else {
menu.addAction(tr("Remove from View"), this, SLOT(issueRemoveFromView()));
}
} 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("Resume"), this, SLOT(issueResume()));
}
menu.addSeparator();
menu.addSeparator();
}
menu.addAction(tr("Delete Installed..."), this, SLOT(issueDeleteCompleted()));
menu.addAction(tr("Delete All..."), this, SLOT(issueDeleteAll()));
if (!hidden) {
+5 -1
View File
@@ -54,7 +54,7 @@ class DownloadListWidgetCompactDelegate : public QItemDelegate
public:
DownloadListWidgetCompactDelegate(DownloadManager *manager, QTreeView *view, QObject *parent = 0);
DownloadListWidgetCompactDelegate(DownloadManager *manager, bool metaDisplay, QTreeView *view, QObject *parent = 0);
~DownloadListWidgetCompactDelegate();
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
@@ -78,6 +78,8 @@ protected:
private:
void drawCache(QPainter *painter, const QStyleOptionViewItem &option, const QPixmap &cache) const;
void paintPendingDownload(int downloadIndex) const;
void paintRegularDownload(int downloadIndex) const;
private slots:
@@ -101,6 +103,8 @@ private:
DownloadListWidgetCompact *m_ItemWidget;
DownloadManager *m_Manager;
bool m_MetaDisplay;
QLabel *m_NameLabel;
QLabel *m_SizeLabel;
QProgressBar *m_Progress;
+243 -94
View File
File diff suppressed because it is too large Load Diff

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