mirror of
https://github.com/ModOrganizer2/modorganizer.git
synced 2026-07-27 13:58:24 -07:00
Compare commits
180
Commits
1.1.2
...
release_v1.2.15
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9edc39633b | ||
|
|
b415db619e | ||
|
|
bd8267993d | ||
|
|
f5c56efeb3 | ||
|
|
a16e25380f | ||
|
|
459816ab71 | ||
|
|
9b5c238938 | ||
|
|
e7b6a7cbdd | ||
|
|
ab925e1e7c | ||
|
|
7bfb48d6ab | ||
|
|
88817c7f3b | ||
|
|
ee0041ba18 | ||
|
|
306ba78b0f | ||
|
|
e33406b4b5 | ||
|
|
a5906f1044 | ||
|
|
ebfeb2fbf9 | ||
|
|
f666e3d835 | ||
|
|
003cb6dec5 | ||
|
|
7fb7207ac7 | ||
|
|
64eced4614 | ||
|
|
8634b97bea | ||
|
|
116a36b943 | ||
|
|
479fdb3dcd | ||
|
|
acf35da699 | ||
|
|
6eb05396e4 | ||
|
|
9fcf34fec7 | ||
|
|
6c1e63258c | ||
|
|
226993eece | ||
|
|
b2d04d70fc | ||
|
|
99de80e722 | ||
|
|
78f628e0af | ||
|
|
78da5fc37f | ||
|
|
ffef339e2b | ||
|
|
4fa700bb55 | ||
|
|
45a46778fb | ||
|
|
cfb863f6c3 | ||
|
|
f2f9e11fdd | ||
|
|
9907437d93 | ||
|
|
d23466f036 | ||
|
|
3b7a468f73 | ||
|
|
53896e66f1 | ||
|
|
efc77930ad | ||
|
|
01265e9b03 | ||
|
|
9494938534 | ||
|
|
0b14949d0e | ||
|
|
2237d7c103 | ||
|
|
7c1273b246 | ||
|
|
9ab7bada1c | ||
|
|
1eea3bd90e | ||
|
|
10cc566081 | ||
|
|
53d1f3e00e | ||
|
|
20db939501 | ||
|
|
df0bd3331a | ||
|
|
db0e278817 | ||
|
|
bfa6c9ab1e | ||
|
|
7a7c464b18 | ||
|
|
2ce135e0bf | ||
|
|
93bd29c13d | ||
|
|
a62ecc5bf1 | ||
|
|
637ce6bcc1 | ||
|
|
5f1022917b | ||
|
|
d3d7e30286 | ||
|
|
b77dcb2206 | ||
|
|
7d27138086 | ||
|
|
430048d201 | ||
|
|
19cb2d4076 | ||
|
|
4c42a6fbf1 | ||
|
|
5aa5c90d39 | ||
|
|
243b59c64c | ||
|
|
12a57d7f6d | ||
|
|
b0a4748da5 | ||
|
|
482f13a50b | ||
|
|
9daeb9479b | ||
|
|
f481a7aae3 | ||
|
|
15b9927cef | ||
|
|
cc42e76f54 | ||
|
|
07bae15d7c | ||
|
|
84598cbcbf | ||
|
|
778160cf0d | ||
|
|
02973be652 | ||
|
|
14106436ca | ||
|
|
fc2591e028 | ||
|
|
4f509e365e | ||
|
|
9a97098cc3 | ||
|
|
4ebc8dc014 | ||
|
|
4b1e6683d2 | ||
|
|
5d3c1f34f4 | ||
|
|
06701856f8 | ||
|
|
5d4a55c3a6 | ||
|
|
844ba99892 | ||
|
|
470b6ed0bf | ||
|
|
715623e790 | ||
|
|
0050cb0740 | ||
|
|
9879aae575 | ||
|
|
f6ef5477e7 | ||
|
|
cc9827cdda | ||
|
|
e24f3fef77 | ||
|
|
4e5a67fc06 | ||
|
|
0a152ceadf | ||
|
|
5718af3510 | ||
|
|
434b6be69d | ||
|
|
67b0268e70 | ||
|
|
d412060d59 | ||
|
|
84c66727bf | ||
|
|
bfb3385e49 | ||
|
|
f59f52501c | ||
|
|
9b67e338e1 | ||
|
|
7944bacfd9 | ||
|
|
1b4c07eb20 | ||
|
|
d93df95dcf | ||
|
|
46a32ff3b7 | ||
|
|
0046d8710e | ||
|
|
2b5748003d | ||
|
|
a49ed5c33c | ||
|
|
62b0c07a93 | ||
|
|
05c58c8b3d | ||
|
|
9b33e0a970 | ||
|
|
b1ac479fb6 | ||
|
|
80b10107d9 | ||
|
|
1707941f6e | ||
|
|
d0b75e8b25 | ||
|
|
4fc441b249 | ||
|
|
581d065d7a | ||
|
|
5d2b5202af | ||
|
|
8044ef4f1d | ||
|
|
3d98491ebc | ||
|
|
923654961b | ||
|
|
76c861ed12 | ||
|
|
31cab54861 | ||
|
|
2a16cc4262 | ||
|
|
a5b6556d67 | ||
|
|
af89733121 | ||
|
|
baf1240be7 | ||
|
|
6e4626852c | ||
|
|
e8f56d65d2 | ||
|
|
5e7c875b29 | ||
|
|
b2a7c7c223 | ||
|
|
7b4582c1b1 | ||
|
|
5d7b23acef | ||
|
|
3628ec930b | ||
|
|
e22aeca3ff | ||
|
|
cbd6b288eb | ||
|
|
484749e612 | ||
|
|
5b3cdaa83b | ||
|
|
6d3f88b330 | ||
|
|
0feb4b702d | ||
|
|
5a4b6e70fd | ||
|
|
18574c2ba8 | ||
|
|
1eb783aae3 | ||
|
|
93a19799b8 | ||
|
|
2a31eb40fb | ||
|
|
cf0a1bc2be | ||
|
|
48c8cca578 | ||
|
|
977b407525 | ||
|
|
f4b1aba61a | ||
|
|
0eb1662a0e | ||
|
|
164ec25a75 | ||
|
|
6fb36d6c02 | ||
|
|
ea1f959ad5 | ||
|
|
7cf3b3455b | ||
|
|
84cfa95254 | ||
|
|
264da60929 | ||
|
|
2db33523a1 | ||
|
|
540747177a | ||
|
|
739c3424e7 | ||
|
|
cabed9b268 | ||
|
|
c017f4a0d5 | ||
|
|
b1f1682790 | ||
|
|
28301e7486 | ||
|
|
2d0fab4482 | ||
|
|
c19c4820d8 | ||
|
|
8ab1b47943 | ||
|
|
ff272dcbbd | ||
|
|
98354cd1e7 | ||
|
|
129b76d7d2 | ||
|
|
a82b7e9949 | ||
|
|
0f8f7bf777 | ||
|
|
f4cf992700 | ||
|
|
bec644bac3 | ||
|
|
98e5e57a84 |
@@ -18,5 +18,22 @@ staging_prepare/*
|
||||
staging_trans/*
|
||||
tools/python_zip/*
|
||||
Makefile
|
||||
html
|
||||
*.vcxproj
|
||||
*.pdb
|
||||
*.dll
|
||||
*.exp
|
||||
*.tlog
|
||||
*.user
|
||||
*.obj
|
||||
*.suo
|
||||
*.sln
|
||||
*.log
|
||||
*.filters
|
||||
*.lib
|
||||
source/organizer/resources/contents/icons
|
||||
source/plugins/build-*
|
||||
*/GeneratedFiles/*
|
||||
syntax: regexp
|
||||
Makefile\.(Debug|Release)
|
||||
source/.*/debug/.*
|
||||
|
||||
+22
-8
@@ -10,7 +10,7 @@ Please note that if you only want to work on and build a plugin you can save you
|
||||
Overview:
|
||||
---------
|
||||
|
||||
As of December 2013 MO consists of the following subprojects:
|
||||
As of Juli 2014 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
|
||||
@@ -24,13 +24,14 @@ As of December 2013 MO consists of the following subprojects:
|
||||
- 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
|
||||
- loot_cli: this is a command line client of loot. This can be better integrated with MO than the official loot client.
|
||||
|
||||
And various plugins:
|
||||
- bsaExtractor: offers to extract bsas after a mod has been installed
|
||||
- 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)
|
||||
@@ -39,7 +40,13 @@ And various plugins:
|
||||
- NMMImport: importer from existing nmm installation
|
||||
- proxyPython: integrates pythonrunner as a plugin into MO
|
||||
- pyniEdit: more user-friendly ini editor. python code
|
||||
- previewBase: used for file previews. this plugin covers image formats supported by the qt installation (usually at least jpg, gif, png) and text files
|
||||
- previewDDS: used to preview dds textures. uses code from the nif file format library
|
||||
|
||||
There are a few more plugins that are either broken or samples
|
||||
- installerBCF: this was intended to use .bcf (bain conversion file) files as installation instructions but currently it is completely function-less
|
||||
- helloWorldCpp: sample for cpp plugins. This should compile even without fulfilling most dependencies below
|
||||
- pageTESAlliance: integrates the tes alliance page into MO. This integration is not nearly as tight as that of nexus.
|
||||
|
||||
Requirements:
|
||||
-------------
|
||||
@@ -50,13 +57,20 @@ Visual C++ compiler 2010 (VC 10.0) or up
|
||||
Note: If you're having trouble installing the windows sdk, you may be affected by this bug: http://support.microsoft.com/kb/2717426
|
||||
|
||||
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
|
||||
- i.e. "Qt libraries 4.8.6 for Windows (VS 2010, 235 MB)"
|
||||
- tested: 4.8.6
|
||||
- Install according to instruction
|
||||
|
||||
Qt 5 Compatibility:
|
||||
MO compiles and mostly runs correctly built with Qt 5.3 and VC++ 2013 but
|
||||
- python plugins haven't been rewritten to use qt5 yet
|
||||
- pyqt5 isn't distributed as binaries for python 2.7 so this needs to be set up and built first
|
||||
- tutorial doesn't work because it seems to be impossible to create a transparent Qt Quick control...
|
||||
- the previewdds plugin only compiles with the opengl variant of the qt 5 distribution
|
||||
- Qt5 is a bi*** to distribute
|
||||
|
||||
boost libraries (http://www.boost.org/)
|
||||
- tested: 1.49
|
||||
- tested: 1.55
|
||||
- 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)
|
||||
@@ -105,8 +119,8 @@ Set up (using Qt Creator):
|
||||
2. Open the "Projects" tab, open the "Details" for "Build Environment"
|
||||
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)
|
||||
3c. Click "Add" to add a variable called "SEVENZIPPATH" with the path of your 7zip installation as the value (i.e. C:\code\7zip)
|
||||
3d. Click "Add" to add a variable called "PYTHONPATH" with the path of your python 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?>
|
||||
|
||||
+1566
-1059
File diff suppressed because it is too large
Load Diff
+31
-6
@@ -1,6 +1,5 @@
|
||||
TEMPLATE = subdirs
|
||||
|
||||
|
||||
SUBDIRS = bsatk \
|
||||
shared \
|
||||
uibase \
|
||||
@@ -13,15 +12,41 @@ SUBDIRS = bsatk \
|
||||
nxmhandler \
|
||||
BossDummy \
|
||||
pythonRunner \
|
||||
boss_modified \
|
||||
loot_cli \
|
||||
esptk
|
||||
|
||||
plugins.depends = pythonRunner
|
||||
pythonRunner.depends = uibase
|
||||
plugins.depends = pythonRunner uibase
|
||||
hookdll.depends = shared
|
||||
organizer.depends = shared uibase plugins boss_modified
|
||||
organizer.depends = shared uibase plugins
|
||||
|
||||
CONFIG(debug, debug|release) {
|
||||
DESTDIR = outputd
|
||||
DESTDIR = $$PWD/../outputd
|
||||
} else {
|
||||
DESTDIR = output
|
||||
DESTDIR = $$PWD/../output
|
||||
}
|
||||
|
||||
STATICDATAPATH = $${DESTDIR}\\..\\tools\\static_data\\dlls
|
||||
DLLSPATH = $${DESTDIR}\\dlls
|
||||
|
||||
otherlibs.path = $$DLLSPATH
|
||||
otherlibs.files += $${STATICDATAPATH}\\7z.dll \
|
||||
$${BOOSTPATH}\\stage\\lib\\boost_python-vc*-mt-1*.dll
|
||||
|
||||
qtlibs.path = $$DLLSPATH
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4) {
|
||||
QTLIBNAMES += Core Gui Network OpenGL Script Sql Svg Qml Quick Webkit Widgets Xml XmlPatterns
|
||||
} else {
|
||||
QTLIBNAMES += Core Declarative Gui Network OpenGL Script Sql Svg Webkit Xml XmlPatterns
|
||||
}
|
||||
|
||||
QTLIBSUFFIX = $${QT_MAJOR_VERSION}.dll
|
||||
CONFIG(debug, debug|release): QTLIBSUFFIX = "d$${QTLIBSUFFIX}" # Can't use Debug: .. here, it ignores the line - no idea why, as it works in BossDummy.pro
|
||||
|
||||
for(QTNAME, QTLIBNAMES) {
|
||||
QTFILE = Qt$${QTNAME}
|
||||
qtlibs.files += $$[QT_INSTALL_BINS]\\$${QTFILE}$${QTLIBSUFFIX}
|
||||
}
|
||||
|
||||
INSTALLS += qtlibs otherlibs
|
||||
|
||||
+6
-6
@@ -35,17 +35,17 @@ AboutDialog::AboutDialog(const QString &version, QWidget *parent)
|
||||
m_LicenseFiles[LICENSE_BOOST] = "boost.txt";
|
||||
m_LicenseFiles[LICENSE_CCBY3] = "by-sa3.txt";
|
||||
m_LicenseFiles[LICENSE_ZLIB] = "zlib.txt";
|
||||
m_LicenseFiles[LICENSE_APACHE2] = "apache-license-2.0.txt";
|
||||
|
||||
addLicense("Qt 4.8.5", LICENSE_LGPL3);
|
||||
addLicense("Qt 5.3", 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);
|
||||
addLicense("Tango Icon Theme", LICENSE_NONE);
|
||||
addLicense("RRZE Icon Set", LICENSE_CCBY3);
|
||||
addLicense("Icons by Lorc, Delapouite and sbed available on http://game-icons.net", LICENSE_CCBY3);
|
||||
addLicense("Castle Core", LICENSE_APACHE2);
|
||||
|
||||
ui->nameLabel->setText(QString("<span style=\"font-size:12pt; font-weight:600;\">%1 %2</span>").arg(ui->nameLabel->text()).arg(version));
|
||||
#ifdef HGID
|
||||
|
||||
+2
-1
@@ -48,7 +48,8 @@ private:
|
||||
LICENSE_BSD3,
|
||||
LICENSE_BOOST,
|
||||
LICENSE_CCBY3,
|
||||
LICENSE_ZLIB
|
||||
LICENSE_ZLIB,
|
||||
LICENSE_APACHE2
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
@@ -178,6 +178,11 @@
|
||||
<string notr="true">tokcdk (Russian)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Ren (Korean)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@@ -214,6 +219,16 @@
|
||||
<string notr="true">Bridger</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>GamerPoet</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Gopher</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">GSDFan</string>
|
||||
|
||||
+97
-97
@@ -1,97 +1,97 @@
|
||||
/*
|
||||
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 "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;
|
||||
}
|
||||
/*
|
||||
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 "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 != nullptr) {
|
||||
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 != nullptr) {
|
||||
QLabel *espName = dynamic_cast<QLabel*>(modsTable->cellWidget(row, 0));
|
||||
|
||||
result.insert(espName->text());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
+70
-70
@@ -1,70 +1,70 @@
|
||||
/*
|
||||
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 ACTIVATEMODSDIALOG_H
|
||||
#define ACTIVATEMODSDIALOG_H
|
||||
|
||||
#include "tutorabledialog.h"
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace Ui {
|
||||
class ActivateModsDialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Dialog that is used to batch activate/deactivate mods and plugins
|
||||
**/
|
||||
class ActivateModsDialog : public MOBase::TutorableDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief constructor
|
||||
*
|
||||
* @param missingPlugins a map containing missing plugins that need to be activated
|
||||
* @param parent ... Defaults to 0.
|
||||
**/
|
||||
explicit ActivateModsDialog(const std::map<QString, std::vector<QString> > &missingPlugins, QWidget *parent = 0);
|
||||
~ActivateModsDialog();
|
||||
|
||||
/**
|
||||
* @brief get a list of mods that the user chose to activate
|
||||
*
|
||||
* @note This can of ocurse only be called after the dialog has been displayed
|
||||
*
|
||||
* @return set< QString > the mods to activate
|
||||
**/
|
||||
std::set<QString> getModsToActivate();
|
||||
|
||||
/**
|
||||
* @brief get a list of plugins that should be activated
|
||||
*
|
||||
* @return set< QString > the plugins to activate. This contains only plugins that become available after enabling the mods retrieved with getModsToActivate
|
||||
**/
|
||||
std::set<QString> getESPsToActivate();
|
||||
|
||||
private slots:
|
||||
|
||||
private:
|
||||
Ui::ActivateModsDialog *ui;
|
||||
};
|
||||
|
||||
#endif // ACTIVATEMODSDIALOG_H
|
||||
/*
|
||||
Copyright (C) 2012 Sebastian Herbord. All rights reserved.
|
||||
|
||||
This file is part of Mod Organizer.
|
||||
|
||||
Mod Organizer is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Mod Organizer is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ACTIVATEMODSDIALOG_H
|
||||
#define ACTIVATEMODSDIALOG_H
|
||||
|
||||
#include "tutorabledialog.h"
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace Ui {
|
||||
class ActivateModsDialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Dialog that is used to batch activate/deactivate mods and plugins
|
||||
**/
|
||||
class ActivateModsDialog : public MOBase::TutorableDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief constructor
|
||||
*
|
||||
* @param missingPlugins a map containing missing plugins that need to be activated
|
||||
* @param parent ... Defaults to 0.
|
||||
**/
|
||||
explicit ActivateModsDialog(const std::map<QString, std::vector<QString> > &missingPlugins, QWidget *parent = 0);
|
||||
~ActivateModsDialog();
|
||||
|
||||
/**
|
||||
* @brief get a list of mods that the user chose to activate
|
||||
*
|
||||
* @note This can of ocurse only be called after the dialog has been displayed
|
||||
*
|
||||
* @return set< QString > the mods to activate
|
||||
**/
|
||||
std::set<QString> getModsToActivate();
|
||||
|
||||
/**
|
||||
* @brief get a list of plugins that should be activated
|
||||
*
|
||||
* @return set< QString > the plugins to activate. This contains only plugins that become available after enabling the mods retrieved with getModsToActivate
|
||||
**/
|
||||
std::set<QString> getESPsToActivate();
|
||||
|
||||
private slots:
|
||||
|
||||
private:
|
||||
Ui::ActivateModsDialog *ui;
|
||||
};
|
||||
|
||||
#endif // ACTIVATEMODSDIALOG_H
|
||||
|
||||
+274
-211
@@ -1,211 +1,274 @@
|
||||
/*
|
||||
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 "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
|
||||
|
||||
/*
|
||||
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 "bbcode.h"
|
||||
|
||||
#include <QRegExp>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <boost/assign.hpp>
|
||||
|
||||
|
||||
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(QString input, int &length)
|
||||
{
|
||||
// extract the tag name
|
||||
m_TagNameExp.indexIn(input, 1, QRegExp::CaretAtOffset);
|
||||
QString tagName = m_TagNameExp.cap(0).toLower();
|
||||
TagMap::iterator tagIter = m_TagMap.find(tagName);
|
||||
if (tagIter != m_TagMap.end()) {
|
||||
// recognized tag
|
||||
if (tagName.endsWith('=')) {
|
||||
tagName.chop(1);
|
||||
}
|
||||
|
||||
int closeTagPos = 0;
|
||||
int closeTagLength = 0;
|
||||
if (tagName == "*") {
|
||||
// ends at the next bullet point
|
||||
closeTagPos = input.indexOf(QRegExp("(\\[\\*\\]|</ul>)", Qt::CaseInsensitive), 3);
|
||||
// leave closeTagLength at 0 because we don't want to "eat" the next bullet point
|
||||
} else if (tagName == "line") {
|
||||
// ends immediately after the tag
|
||||
closeTagPos = 6;
|
||||
// leave closeTagLength at 0 because there is no close tag to skip over
|
||||
} else {
|
||||
QString closeTag = QString("[/%1]").arg(tagName);
|
||||
closeTagPos = input.indexOf(closeTag, 0, Qt::CaseInsensitive);
|
||||
if (closeTagPos == -1) {
|
||||
// workaround to improve compatibility: add fake closing tag
|
||||
input.append(closeTag);
|
||||
closeTagPos = input.size() - closeTag.size();
|
||||
}
|
||||
closeTagLength = closeTag.size();
|
||||
}
|
||||
|
||||
if (closeTagPos > -1) {
|
||||
length = closeTagPos + closeTagLength;
|
||||
QString temp = input.mid(0, length);
|
||||
if (tagIter->second.first.indexIn(temp) == 0) {
|
||||
if (tagIter->second.second.isEmpty()) {
|
||||
if (tagName == "color") {
|
||||
QString color = tagIter->second.first.cap(1);
|
||||
QString content = tagIter->second.first.cap(2);
|
||||
if (color.at(0) == "#") {
|
||||
return temp.replace(tagIter->second.first, QString("<font style=\"color: %1;\">%2</font>").arg(color, content));
|
||||
} else {
|
||||
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 {
|
||||
if (tagName == "*") {
|
||||
temp.remove(QRegExp("(\\[/\\*\\])?(<br/>)?$"));
|
||||
}
|
||||
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\\]"),
|
||||
"");
|
||||
m_TagMap["font="] = std::make_pair(QRegExp("\\[font=([^\\]]*)\\](.*)\\[/font\\]"),
|
||||
"<font style=\"font-family: \\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>");
|
||||
m_TagMap["line"] = std::make_pair(QRegExp("\\[line\\]"),
|
||||
"<hr>");
|
||||
|
||||
// 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>");
|
||||
|
||||
// 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\" alt=\"\\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);
|
||||
}
|
||||
|
||||
// this tag is in fact greedy
|
||||
m_TagMap["*"] = std::make_pair(QRegExp("\\[\\*\\](.*)"),
|
||||
"<li>\\1</li>");
|
||||
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("red", "FF0000"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("green", "00FF00"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("blue", "0000FF"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("black", "000000"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("gray", "7F7F7F"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("white", "FFFFFF"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("yellow", "FFFF00"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("cyan", "00FFFF"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("magenta", "FF00FF"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("brown", "A52A2A"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("orange", "FFA500"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("gold", "FFD700"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("deepskyblue", "00BFFF"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("salmon", "FA8072"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("dodgerblue", "1E90FF"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("greenyellow", "ADFF2F"));
|
||||
m_ColorMap.insert(std::make_pair<QString, QString>("peru", "CD853F"));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
QRegExp m_TagNameExp;
|
||||
TagMap m_TagMap;
|
||||
std::map<QString, QString> m_ColorMap;
|
||||
};
|
||||
|
||||
|
||||
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));
|
||||
|
||||
if ((pos < (input.size() - 1)) && (input.at(pos + 1) == '/')) {
|
||||
// skip invalid end tag
|
||||
int tagEnd = input.indexOf(']', pos) + 1;
|
||||
pos = tagEnd;
|
||||
} else {
|
||||
// convert the tag and content if necessary
|
||||
int length = -1;
|
||||
QString replacement = BBCodeMap::instance().convertTag(input.mid(pos), length);
|
||||
if (length != 0) {
|
||||
result.append(convertToHTML(replacement));
|
||||
// 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
|
||||
|
||||
|
||||
+40
-40
@@ -1,40 +1,40 @@
|
||||
/*
|
||||
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 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
|
||||
/*
|
||||
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 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 nullptr, 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
|
||||
|
||||
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
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 "persistentcookiejar.h"
|
||||
|
||||
#include "json.h"
|
||||
|
||||
#include <utility.h>
|
||||
#include <gameinfo.h>
|
||||
#include "settings.h"
|
||||
#include <QNetworkCookieJar>
|
||||
#include <QNetworkCookie>
|
||||
#include <QMenu>
|
||||
#include <QInputDialog>
|
||||
#include <QWebHistory>
|
||||
#include <QDir>
|
||||
#include <QWebFrame>
|
||||
#include <QDesktopWidget>
|
||||
#include <QKeyEvent>
|
||||
|
||||
|
||||
|
||||
BrowserDialog::BrowserDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::BrowserDialog)
|
||||
, m_AccessManager(new QNetworkAccessManager(this))
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
m_AccessManager->setCookieJar(new PersistentCookieJar(
|
||||
QDir::fromNativeSeparators(Settings::instance().getCacheDirectory() + "/cookies.dat")));
|
||||
|
||||
Qt::WindowFlags flags = windowFlags() | Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint;
|
||||
Qt::WindowFlags helpFlag = Qt::WindowContextHelpButtonHint;
|
||||
flags = flags & (~helpFlag);
|
||||
setWindowFlags(flags);
|
||||
|
||||
m_Tabs = this->findChild<QTabWidget*>("browserTabWidget");
|
||||
|
||||
installEventFilter(this);
|
||||
|
||||
connect(m_Tabs, SIGNAL(tabCloseRequested(int)), this, SLOT(tabCloseRequested(int)));
|
||||
|
||||
ui->urlEdit->setVisible(false);
|
||||
}
|
||||
|
||||
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 &url)
|
||||
{
|
||||
BrowserView *currentView = getCurrentView();
|
||||
if (currentView != nullptr) {
|
||||
ui->backBtn->setEnabled(currentView->history()->canGoBack());
|
||||
ui->fwdBtn->setEnabled(currentView->history()->canGoForward());
|
||||
}
|
||||
ui->urlEdit->setText(url.toString());
|
||||
}
|
||||
|
||||
|
||||
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 == nullptr) {
|
||||
qCritical("sender not a page");
|
||||
return;
|
||||
}
|
||||
BrowserView *view = qobject_cast<BrowserView*>(page->view());
|
||||
if (view == nullptr) {
|
||||
qCritical("no view?");
|
||||
return;
|
||||
}
|
||||
|
||||
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 != nullptr) {
|
||||
currentView->back();
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserDialog::on_fwdBtn_clicked()
|
||||
{
|
||||
BrowserView *currentView = getCurrentView();
|
||||
if (currentView != nullptr) {
|
||||
currentView->forward();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BrowserDialog::startSearch()
|
||||
{
|
||||
ui->searchEdit->setFocus();
|
||||
}
|
||||
|
||||
|
||||
void BrowserDialog::on_searchEdit_returnPressed()
|
||||
{
|
||||
BrowserView *currentView = getCurrentView();
|
||||
if (currentView != nullptr) {
|
||||
currentView->findText(ui->searchEdit->text(), QWebPage::FindWrapsAroundDocument);
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserDialog::on_refreshBtn_clicked()
|
||||
{
|
||||
getCurrentView()->reload();
|
||||
}
|
||||
|
||||
void BrowserDialog::on_browserTabWidget_currentChanged(int index)
|
||||
{
|
||||
BrowserView *currentView = qobject_cast<BrowserView*>(ui->browserTabWidget->widget(index));
|
||||
if (currentView != nullptr) {
|
||||
ui->backBtn->setEnabled(currentView->history()->canGoBack());
|
||||
ui->fwdBtn->setEnabled(currentView->history()->canGoForward());
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserDialog::on_urlEdit_returnPressed()
|
||||
{
|
||||
QWebView *currentView = getCurrentView();
|
||||
if (currentView != nullptr) {
|
||||
currentView->setUrl(QUrl(ui->urlEdit->text()));
|
||||
}
|
||||
}
|
||||
|
||||
bool BrowserDialog::eventFilter(QObject *object, QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::KeyPress) {
|
||||
QKeyEvent *keyEvent = reinterpret_cast<QKeyEvent*>(event);
|
||||
if ((keyEvent->modifiers() & Qt::ControlModifier)
|
||||
&& (keyEvent->key() == Qt::Key_U)) {
|
||||
ui->urlEdit->setVisible(!ui->urlEdit->isVisible());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return QDialog::eventFilter(object, event);
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
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 <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);
|
||||
|
||||
virtual bool eventFilter(QObject *object, QEvent *event);
|
||||
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_refreshBtn_clicked();
|
||||
|
||||
void on_browserTabWidget_currentChanged(int index);
|
||||
|
||||
void on_urlEdit_returnPressed();
|
||||
|
||||
private:
|
||||
|
||||
QString guessFileName(const QString &url);
|
||||
|
||||
BrowserView *getCurrentView();
|
||||
|
||||
void maximizeWidth();
|
||||
|
||||
private:
|
||||
|
||||
Ui::BrowserDialog *ui;
|
||||
|
||||
QNetworkAccessManager *m_AccessManager;
|
||||
|
||||
QTabWidget *m_Tabs;
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // BROWSERDIALOG_H
|
||||
@@ -0,0 +1,314 @@
|
||||
<?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="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<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="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<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>
|
||||
<widget class="QLineEdit" name="urlEdit">
|
||||
<property name="enabled">
|
||||
<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>
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
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);
|
||||
}
|
||||
@@ -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
|
||||
+319
-301
File diff suppressed because it is too large
Load Diff
+200
-198
@@ -1,198 +1,200 @@
|
||||
/*
|
||||
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 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
|
||||
/*
|
||||
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 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;
|
||||
static const int CATEGORY_SPECIAL_MANAGED = 10006;
|
||||
static const int CATEGORY_SPECIAL_UNMANAGED = 10007;
|
||||
|
||||
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
|
||||
|
||||
+243
-243
@@ -1,243 +1,243 @@
|
||||
/*
|
||||
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 "categoriesdialog.h"
|
||||
#include "ui_categoriesdialog.h"
|
||||
#include "categories.h"
|
||||
#include "utility.h"
|
||||
#include <QItemDelegate>
|
||||
#include <QRegExpValidator>
|
||||
#include <QLineEdit>
|
||||
#include <QMenu>
|
||||
|
||||
|
||||
class NewIDValidator : public QIntValidator {
|
||||
public:
|
||||
NewIDValidator(const std::set<int> &ids)
|
||||
: m_UsedIDs(ids) {}
|
||||
virtual State validate(QString &input, int &pos) const {
|
||||
State intRes = QIntValidator::validate(input, pos);
|
||||
if (intRes == Acceptable) {
|
||||
bool ok = false;
|
||||
int id = input.toInt(&ok);
|
||||
if (m_UsedIDs.find(id) != m_UsedIDs.end()) {
|
||||
return QValidator::Intermediate;
|
||||
}
|
||||
}
|
||||
return intRes;
|
||||
}
|
||||
private:
|
||||
const std::set<int> &m_UsedIDs;
|
||||
};
|
||||
|
||||
|
||||
class ExistingIDValidator : public QIntValidator {
|
||||
public:
|
||||
ExistingIDValidator(const std::set<int> &ids)
|
||||
: m_UsedIDs(ids) {}
|
||||
virtual State validate(QString &input, int &pos) const {
|
||||
State intRes = QIntValidator::validate(input, pos);
|
||||
if (intRes == Acceptable) {
|
||||
bool ok = false;
|
||||
int id = input.toInt(&ok);
|
||||
if ((id == 0) || (m_UsedIDs.find(id) != m_UsedIDs.end())) {
|
||||
return QValidator::Acceptable;
|
||||
} else {
|
||||
return QValidator::Intermediate;
|
||||
}
|
||||
} else {
|
||||
return intRes;
|
||||
}
|
||||
}
|
||||
private:
|
||||
const std::set<int> &m_UsedIDs;
|
||||
};
|
||||
|
||||
|
||||
class ValidatingDelegate : public QItemDelegate {
|
||||
|
||||
public:
|
||||
ValidatingDelegate(QObject *parent, QValidator *validator)
|
||||
: QItemDelegate(parent), m_Validator(validator) {}
|
||||
|
||||
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem&, const QModelIndex&) const
|
||||
{
|
||||
QLineEdit *edit = new QLineEdit(parent);
|
||||
edit->setValidator(m_Validator);
|
||||
return edit;
|
||||
}
|
||||
virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
|
||||
{
|
||||
QLineEdit *edit = qobject_cast<QLineEdit*>(editor);
|
||||
int pos = 0;
|
||||
QString editText = edit->text();
|
||||
if (m_Validator->validate(editText, pos) == QValidator::Acceptable) {
|
||||
QItemDelegate::setModelData(editor, model, index);
|
||||
}
|
||||
}
|
||||
private:
|
||||
QValidator *m_Validator;
|
||||
};
|
||||
|
||||
|
||||
CategoriesDialog::CategoriesDialog(QWidget *parent)
|
||||
: TutorableDialog("Categories", parent), ui(new Ui::CategoriesDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
fillTable();
|
||||
connect(ui->categoriesTable, SIGNAL(cellChanged(int,int)), this, SLOT(cellChanged(int,int)));
|
||||
}
|
||||
|
||||
CategoriesDialog::~CategoriesDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
|
||||
void CategoriesDialog::cellChanged(int row, int)
|
||||
{
|
||||
int currentID = ui->categoriesTable->item(row, 0)->text().toInt();
|
||||
if (currentID > m_HighestID) {
|
||||
m_HighestID = currentID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CategoriesDialog::commitChanges()
|
||||
{
|
||||
CategoryFactory &categories = CategoryFactory::instance();
|
||||
categories.reset();
|
||||
|
||||
for (int i = 0; i < ui->categoriesTable->rowCount(); ++i) {
|
||||
int index = ui->categoriesTable->verticalHeader()->logicalIndex(i);
|
||||
QString nexusIDString = ui->categoriesTable->item(index, 2)->text();
|
||||
QStringList nexusIDStringList = nexusIDString.split(',', QString::SkipEmptyParts);
|
||||
std::vector<int> nexusIDs;
|
||||
for (QStringList::iterator iter = nexusIDStringList.begin();
|
||||
iter != nexusIDStringList.end(); ++iter) {
|
||||
nexusIDs.push_back(iter->toInt());
|
||||
}
|
||||
|
||||
categories.addCategory(
|
||||
ui->categoriesTable->item(index, 0)->text().toInt(),
|
||||
ui->categoriesTable->item(index, 1)->text(),
|
||||
nexusIDs,
|
||||
ui->categoriesTable->item(index, 3)->text().toInt());
|
||||
}
|
||||
categories.setParents();
|
||||
|
||||
categories.saveCategories();
|
||||
}
|
||||
|
||||
|
||||
void CategoriesDialog::refreshIDs()
|
||||
{
|
||||
m_HighestID = 0;
|
||||
for (int i = 0; i < ui->categoriesTable->rowCount(); ++i) {
|
||||
int id = ui->categoriesTable->item(i, 0)->text().toInt();
|
||||
if (id > m_HighestID) {
|
||||
m_HighestID = id;
|
||||
}
|
||||
m_IDs.insert(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CategoriesDialog::fillTable()
|
||||
{
|
||||
CategoryFactory &categories = CategoryFactory::instance();
|
||||
QTableWidget *table = ui->categoriesTable;
|
||||
|
||||
#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);
|
||||
table->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed);
|
||||
table->verticalHeader()->setSectionsMovable(true);
|
||||
table->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
|
||||
#else
|
||||
table->horizontalHeader()->setResizeMode(0, QHeaderView::Fixed);
|
||||
table->horizontalHeader()->setResizeMode(1, QHeaderView::Stretch);
|
||||
table->horizontalHeader()->setResizeMode(2, QHeaderView::Fixed);
|
||||
table->horizontalHeader()->setResizeMode(3, QHeaderView::Fixed);
|
||||
table->verticalHeader()->setMovable(true);
|
||||
table->verticalHeader()->setResizeMode(QHeaderView::Fixed);
|
||||
#endif
|
||||
|
||||
|
||||
table->setItemDelegateForColumn(0, new ValidatingDelegate(this, new NewIDValidator(m_IDs)));
|
||||
table->setItemDelegateForColumn(2, new ValidatingDelegate(this, new QRegExpValidator(QRegExp("([0-9]+)?(,[0-9]+)*"), this)));
|
||||
table->setItemDelegateForColumn(3, new ValidatingDelegate(this, new ExistingIDValidator(m_IDs)));
|
||||
|
||||
int row = 0;
|
||||
for (std::vector<CategoryFactory::Category>::const_iterator iter = categories.m_Categories.begin();
|
||||
iter != categories.m_Categories.end(); ++iter, ++row) {
|
||||
const CategoryFactory::Category &category = *iter;
|
||||
if (category.m_ID == 0) {
|
||||
--row;
|
||||
continue;
|
||||
}
|
||||
table->insertRow(row);
|
||||
// table->setVerticalHeaderItem(row, new QTableWidgetItem(" "));
|
||||
|
||||
QScopedPointer<QTableWidgetItem> idItem(new QTableWidgetItem());
|
||||
idItem->setData(Qt::DisplayRole, category.m_ID);
|
||||
|
||||
QScopedPointer<QTableWidgetItem> nameItem(new QTableWidgetItem(category.m_Name));
|
||||
QScopedPointer<QTableWidgetItem> nexusIDItem(new QTableWidgetItem(MOBase::VectorJoin(category.m_NexusIDs, ",")));
|
||||
QScopedPointer<QTableWidgetItem> parentIDItem(new QTableWidgetItem());
|
||||
parentIDItem->setData(Qt::DisplayRole, category.m_ParentID);
|
||||
|
||||
table->setItem(row, 0, idItem.take());
|
||||
table->setItem(row, 1, nameItem.take());
|
||||
table->setItem(row, 2, nexusIDItem.take());
|
||||
table->setItem(row, 3, parentIDItem.take());
|
||||
}
|
||||
|
||||
refreshIDs();
|
||||
}
|
||||
|
||||
|
||||
void CategoriesDialog::addCategory_clicked()
|
||||
{
|
||||
int row = m_ContextRow >= 0 ? m_ContextRow : 0;
|
||||
ui->categoriesTable->insertRow(row);
|
||||
ui->categoriesTable->setVerticalHeaderItem(row, new QTableWidgetItem(" "));
|
||||
ui->categoriesTable->setItem(row, 0, new QTableWidgetItem(QString::number(++m_HighestID)));
|
||||
ui->categoriesTable->setItem(row, 1, new QTableWidgetItem("new"));
|
||||
ui->categoriesTable->setItem(row, 2, new QTableWidgetItem(""));
|
||||
ui->categoriesTable->setItem(row, 3, new QTableWidgetItem("0"));
|
||||
}
|
||||
|
||||
|
||||
void CategoriesDialog::removeCategory_clicked()
|
||||
{
|
||||
ui->categoriesTable->removeRow(m_ContextRow);
|
||||
}
|
||||
|
||||
|
||||
void CategoriesDialog::on_categoriesTable_customContextMenuRequested(const QPoint &pos)
|
||||
{
|
||||
m_ContextRow = ui->categoriesTable->rowAt(pos.y());
|
||||
QMenu menu;
|
||||
menu.addAction(tr("Add"), this, SLOT(addCategory_clicked()));
|
||||
menu.addAction(tr("Remove"), this, SLOT(removeCategory_clicked()));
|
||||
|
||||
menu.exec(ui->categoriesTable->mapToGlobal(pos));
|
||||
}
|
||||
/*
|
||||
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 "categoriesdialog.h"
|
||||
#include "ui_categoriesdialog.h"
|
||||
#include "categories.h"
|
||||
#include "utility.h"
|
||||
#include <QItemDelegate>
|
||||
#include <QRegExpValidator>
|
||||
#include <QLineEdit>
|
||||
#include <QMenu>
|
||||
|
||||
|
||||
class NewIDValidator : public QIntValidator {
|
||||
public:
|
||||
NewIDValidator(const std::set<int> &ids)
|
||||
: m_UsedIDs(ids) {}
|
||||
virtual State validate(QString &input, int &pos) const {
|
||||
State intRes = QIntValidator::validate(input, pos);
|
||||
if (intRes == Acceptable) {
|
||||
bool ok = false;
|
||||
int id = input.toInt(&ok);
|
||||
if (m_UsedIDs.find(id) != m_UsedIDs.end()) {
|
||||
return QValidator::Intermediate;
|
||||
}
|
||||
}
|
||||
return intRes;
|
||||
}
|
||||
private:
|
||||
const std::set<int> &m_UsedIDs;
|
||||
};
|
||||
|
||||
|
||||
class ExistingIDValidator : public QIntValidator {
|
||||
public:
|
||||
ExistingIDValidator(const std::set<int> &ids)
|
||||
: m_UsedIDs(ids) {}
|
||||
virtual State validate(QString &input, int &pos) const {
|
||||
State intRes = QIntValidator::validate(input, pos);
|
||||
if (intRes == Acceptable) {
|
||||
bool ok = false;
|
||||
int id = input.toInt(&ok);
|
||||
if ((id == 0) || (m_UsedIDs.find(id) != m_UsedIDs.end())) {
|
||||
return QValidator::Acceptable;
|
||||
} else {
|
||||
return QValidator::Intermediate;
|
||||
}
|
||||
} else {
|
||||
return intRes;
|
||||
}
|
||||
}
|
||||
private:
|
||||
const std::set<int> &m_UsedIDs;
|
||||
};
|
||||
|
||||
|
||||
class ValidatingDelegate : public QItemDelegate {
|
||||
|
||||
public:
|
||||
ValidatingDelegate(QObject *parent, QValidator *validator)
|
||||
: QItemDelegate(parent), m_Validator(validator) {}
|
||||
|
||||
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem&, const QModelIndex&) const
|
||||
{
|
||||
QLineEdit *edit = new QLineEdit(parent);
|
||||
edit->setValidator(m_Validator);
|
||||
return edit;
|
||||
}
|
||||
virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
|
||||
{
|
||||
QLineEdit *edit = qobject_cast<QLineEdit*>(editor);
|
||||
int pos = 0;
|
||||
QString editText = edit->text();
|
||||
if (m_Validator->validate(editText, pos) == QValidator::Acceptable) {
|
||||
QItemDelegate::setModelData(editor, model, index);
|
||||
}
|
||||
}
|
||||
private:
|
||||
QValidator *m_Validator;
|
||||
};
|
||||
|
||||
|
||||
CategoriesDialog::CategoriesDialog(QWidget *parent)
|
||||
: TutorableDialog("Categories", parent), ui(new Ui::CategoriesDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
fillTable();
|
||||
connect(ui->categoriesTable, SIGNAL(cellChanged(int,int)), this, SLOT(cellChanged(int,int)));
|
||||
}
|
||||
|
||||
CategoriesDialog::~CategoriesDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
|
||||
void CategoriesDialog::cellChanged(int row, int)
|
||||
{
|
||||
int currentID = ui->categoriesTable->item(row, 0)->text().toInt();
|
||||
if (currentID > m_HighestID) {
|
||||
m_HighestID = currentID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CategoriesDialog::commitChanges()
|
||||
{
|
||||
CategoryFactory &categories = CategoryFactory::instance();
|
||||
categories.reset();
|
||||
|
||||
for (int i = 0; i < ui->categoriesTable->rowCount(); ++i) {
|
||||
int index = ui->categoriesTable->verticalHeader()->logicalIndex(i);
|
||||
QString nexusIDString = ui->categoriesTable->item(index, 2)->text();
|
||||
QStringList nexusIDStringList = nexusIDString.split(',', QString::SkipEmptyParts);
|
||||
std::vector<int> nexusIDs;
|
||||
for (QStringList::iterator iter = nexusIDStringList.begin();
|
||||
iter != nexusIDStringList.end(); ++iter) {
|
||||
nexusIDs.push_back(iter->toInt());
|
||||
}
|
||||
|
||||
categories.addCategory(
|
||||
ui->categoriesTable->item(index, 0)->text().toInt(),
|
||||
ui->categoriesTable->item(index, 1)->text(),
|
||||
nexusIDs,
|
||||
ui->categoriesTable->item(index, 3)->text().toInt());
|
||||
}
|
||||
categories.setParents();
|
||||
|
||||
categories.saveCategories();
|
||||
}
|
||||
|
||||
|
||||
void CategoriesDialog::refreshIDs()
|
||||
{
|
||||
m_HighestID = 0;
|
||||
for (int i = 0; i < ui->categoriesTable->rowCount(); ++i) {
|
||||
int id = ui->categoriesTable->item(i, 0)->text().toInt();
|
||||
if (id > m_HighestID) {
|
||||
m_HighestID = id;
|
||||
}
|
||||
m_IDs.insert(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CategoriesDialog::fillTable()
|
||||
{
|
||||
CategoryFactory &categories = CategoryFactory::instance();
|
||||
QTableWidget *table = ui->categoriesTable;
|
||||
|
||||
#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);
|
||||
table->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed);
|
||||
table->verticalHeader()->setSectionsMovable(true);
|
||||
table->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
|
||||
#else
|
||||
table->horizontalHeader()->setResizeMode(0, QHeaderView::Fixed);
|
||||
table->horizontalHeader()->setResizeMode(1, QHeaderView::Stretch);
|
||||
table->horizontalHeader()->setResizeMode(2, QHeaderView::Fixed);
|
||||
table->horizontalHeader()->setResizeMode(3, QHeaderView::Fixed);
|
||||
table->verticalHeader()->setMovable(true);
|
||||
table->verticalHeader()->setResizeMode(QHeaderView::Fixed);
|
||||
#endif
|
||||
|
||||
|
||||
table->setItemDelegateForColumn(0, new ValidatingDelegate(this, new NewIDValidator(m_IDs)));
|
||||
table->setItemDelegateForColumn(2, new ValidatingDelegate(this, new QRegExpValidator(QRegExp("([0-9]+)?(,[0-9]+)*"), this)));
|
||||
table->setItemDelegateForColumn(3, new ValidatingDelegate(this, new ExistingIDValidator(m_IDs)));
|
||||
|
||||
int row = 0;
|
||||
for (std::vector<CategoryFactory::Category>::const_iterator iter = categories.m_Categories.begin();
|
||||
iter != categories.m_Categories.end(); ++iter, ++row) {
|
||||
const CategoryFactory::Category &category = *iter;
|
||||
if (category.m_ID == 0) {
|
||||
--row;
|
||||
continue;
|
||||
}
|
||||
table->insertRow(row);
|
||||
// table->setVerticalHeaderItem(row, new QTableWidgetItem(" "));
|
||||
|
||||
QScopedPointer<QTableWidgetItem> idItem(new QTableWidgetItem());
|
||||
idItem->setData(Qt::DisplayRole, category.m_ID);
|
||||
|
||||
QScopedPointer<QTableWidgetItem> nameItem(new QTableWidgetItem(category.m_Name));
|
||||
QScopedPointer<QTableWidgetItem> nexusIDItem(new QTableWidgetItem(MOBase::VectorJoin(category.m_NexusIDs, ",")));
|
||||
QScopedPointer<QTableWidgetItem> parentIDItem(new QTableWidgetItem());
|
||||
parentIDItem->setData(Qt::DisplayRole, category.m_ParentID);
|
||||
|
||||
table->setItem(row, 0, idItem.take());
|
||||
table->setItem(row, 1, nameItem.take());
|
||||
table->setItem(row, 2, nexusIDItem.take());
|
||||
table->setItem(row, 3, parentIDItem.take());
|
||||
}
|
||||
|
||||
refreshIDs();
|
||||
}
|
||||
|
||||
|
||||
void CategoriesDialog::addCategory_clicked()
|
||||
{
|
||||
int row = m_ContextRow >= 0 ? m_ContextRow : 0;
|
||||
ui->categoriesTable->insertRow(row);
|
||||
ui->categoriesTable->setVerticalHeaderItem(row, new QTableWidgetItem(" "));
|
||||
ui->categoriesTable->setItem(row, 0, new QTableWidgetItem(QString::number(++m_HighestID)));
|
||||
ui->categoriesTable->setItem(row, 1, new QTableWidgetItem("new"));
|
||||
ui->categoriesTable->setItem(row, 2, new QTableWidgetItem(""));
|
||||
ui->categoriesTable->setItem(row, 3, new QTableWidgetItem("0"));
|
||||
}
|
||||
|
||||
|
||||
void CategoriesDialog::removeCategory_clicked()
|
||||
{
|
||||
ui->categoriesTable->removeRow(m_ContextRow);
|
||||
}
|
||||
|
||||
|
||||
void CategoriesDialog::on_categoriesTable_customContextMenuRequested(const QPoint &pos)
|
||||
{
|
||||
m_ContextRow = ui->categoriesTable->rowAt(pos.y());
|
||||
QMenu menu;
|
||||
menu.addAction(tr("Add"), this, SLOT(addCategory_clicked()));
|
||||
menu.addAction(tr("Remove"), this, SLOT(removeCategory_clicked()));
|
||||
|
||||
menu.exec(ui->categoriesTable->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
+71
-71
@@ -1,71 +1,71 @@
|
||||
/*
|
||||
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 CATEGORIESDIALOG_H
|
||||
#define CATEGORIESDIALOG_H
|
||||
|
||||
#include "tutorabledialog.h"
|
||||
#include <set>
|
||||
|
||||
namespace Ui {
|
||||
class CategoriesDialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Dialog that allows users to configure mod categories
|
||||
**/
|
||||
class CategoriesDialog : public MOBase::TutorableDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
explicit CategoriesDialog(QWidget *parent = 0);
|
||||
~CategoriesDialog();
|
||||
|
||||
/**
|
||||
* @brief store changes here to the global categories store (categories.h)
|
||||
*
|
||||
**/
|
||||
void commitChanges();
|
||||
|
||||
private slots:
|
||||
|
||||
void on_categoriesTable_customContextMenuRequested(const QPoint &pos);
|
||||
void addCategory_clicked();
|
||||
void removeCategory_clicked();
|
||||
void cellChanged(int row, int column);
|
||||
|
||||
private:
|
||||
|
||||
void refreshIDs();
|
||||
void fillTable();
|
||||
|
||||
private:
|
||||
|
||||
Ui::CategoriesDialog *ui;
|
||||
int m_ContextRow;
|
||||
|
||||
int m_HighestID;
|
||||
std::set<int> m_IDs;
|
||||
|
||||
};
|
||||
|
||||
#endif // CATEGORIESDIALOG_H
|
||||
|
||||
/*
|
||||
Copyright (C) 2012 Sebastian Herbord. All rights reserved.
|
||||
|
||||
This file is part of Mod Organizer.
|
||||
|
||||
Mod Organizer is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Mod Organizer is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CATEGORIESDIALOG_H
|
||||
#define CATEGORIESDIALOG_H
|
||||
|
||||
#include "tutorabledialog.h"
|
||||
#include <set>
|
||||
|
||||
namespace Ui {
|
||||
class CategoriesDialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Dialog that allows users to configure mod categories
|
||||
**/
|
||||
class CategoriesDialog : public MOBase::TutorableDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
explicit CategoriesDialog(QWidget *parent = 0);
|
||||
~CategoriesDialog();
|
||||
|
||||
/**
|
||||
* @brief store changes here to the global categories store (categories.h)
|
||||
*
|
||||
**/
|
||||
void commitChanges();
|
||||
|
||||
private slots:
|
||||
|
||||
void on_categoriesTable_customContextMenuRequested(const QPoint &pos);
|
||||
void addCategory_clicked();
|
||||
void removeCategory_clicked();
|
||||
void cellChanged(int row, int column);
|
||||
|
||||
private:
|
||||
|
||||
void refreshIDs();
|
||||
void fillTable();
|
||||
|
||||
private:
|
||||
|
||||
Ui::CategoriesDialog *ui;
|
||||
int m_ContextRow;
|
||||
|
||||
int m_HighestID;
|
||||
std::set<int> m_IDs;
|
||||
|
||||
};
|
||||
|
||||
#endif // CATEGORIESDIALOG_H
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user